Skip to content

安全功能

一句话:CSRF 防护、XSS 过滤、SQL 注入防护、接口限流等安全功能。


CSRF 防护

启用 CSRF 防护

server/app/useApp.php 中配置:

php
'security' => [
    'csrf' => [
        'enabled' => true,      // 是否启用 CSRF 防护
        'stateless' => true,     // 是否使用无状态 Token(推荐,减少 Session 锁竞争)
    ],
]

生成 CSRF Token

php
// 生成并获取 CSRF Token
$token = Anon_Auth_Csrf::generateToken();

// 获取当前 Token(如果不存在则生成)
$token = Anon_Auth_Csrf::getToken();

无状态 Token 说明:

  • 默认启用无状态 Token,基于 HMAC 签名,无需存储在 Session 中
  • 减少 Session 锁竞争,提高并发性能
  • Token 包含时间戳、随机数和 Session ID,有效期 2 小时
  • 可通过配置 stateless => false 切换为传统 Session 存储模式

验证 CSRF Token

php
// 自动从请求中获取并验证 Token
Anon_Auth_Csrf::verify();

// 验证指定的 Token
Anon_Auth_Csrf::verify($token);

// 验证失败时不抛出异常,返回 false
$isValid = Anon_Auth_Csrf::verify($token, false);

在路由中使用

php
// 在路由文件中验证 CSRF
const Anon_Http_RouterMeta = [
    'header' => true,
    'requireLogin' => false,
    'method' => 'POST',
];

// 验证 CSRF Token
Anon_Auth_Csrf::verify();

使用 CSRF 中间件

php
// 在 useCode.php 中注册全局中间件
Anon_Http_Middleware::global(Anon_Auth_CsrfMiddleware::make([
    '/api/public', // 排除的路由
]));

前端获取 Token

javascript
// 从响应头或配置中获取 Token
fetch('/anon/common/config')
    .then(res => res.json())
    .then(data => {
        const csrfToken = data.data.csrfToken;
        // 在请求头中携带 Token
        fetch('/api/endpoint', {
            method: 'POST',
            headers: {
                'X-CSRF-Token': csrfToken
            }
        });
    });

XSS 过滤

启用 XSS 过滤

server/app/useApp.php 中配置:

php
'security' => [
    'xss' => [
        'enabled' => true, // 是否启用 XSS 自动过滤
        'stripHtml' => true, // 是否移除 HTML 标签
        'skipFields' => ['password', 'token', 'csrf_token'], // 跳过的字段
    ],
]

手动过滤数据

php
// 过滤单个字符串
$clean = Anon_Security_Security_Security_Security_Sanitize::text('<script>alert("xss")</script>');

// 过滤 HTML(允许指定标签)
$html = Anon_Security_Security_Security_Security_Sanitize::html('<p>Hello</p><script>alert("xss")</script>', '<p><strong>');

// 过滤数组(递归)
$data = Anon_Security_Security_Security_Security_Sanitize::array([
    'name' => '<script>alert("xss")</script>',
    'content' => '<p>Safe content</p>'
]);

// 使用安全工具类过滤
$filtered = Anon_Security_Security_Security_Security_Security::filterInput($_POST, [
    'stripHtml' => true,
    'skipFields' => ['password']
]);

使用 XSS 过滤中间件

php
// 在 useCode.php 中注册全局中间件
Anon_Http_Middleware::global(Anon_XssFilterMiddleware::make(
    true, // 移除 HTML 标签
    ['password', 'token'] // 跳过的字段
));

检查 XSS 风险

php
// 检查字符串是否包含潜在的 XSS 代码
if (Anon_Security_Security_Security_Security_Security::containsXss($userInput)) {
    // 处理风险
}

SQL 注入防护

使用预处理语句

框架的查询构建器自动使用预处理语句,防止 SQL 注入:

php
// 使用查询构建器(推荐)
$db = Anon_Database::getInstance();
$users = $db->db('users')
    ->where('name', '=', $username)
    ->where('email', '=', $email)
    ->get();

// 使用 prepare 方法
$stmt = $db->prepare('SELECT * FROM users WHERE id = ?', [$userId]);
$result = $stmt->get_result();

验证 SQL 查询安全性

在调试模式下,框架会自动检查 SQL 查询:

php
// 手动验证(仅在调试模式下有效)
Anon_Security_Security_Security_Security_Security::validateSqlQuery($sql, $params);

// 检查是否使用了预处理语句
$isSafe = Anon_Security_Security_Security_Security_Security::isUsingPreparedStatement($sql, $params);

转义 LIKE 查询

php
// 转义 LIKE 查询中的特殊字符
$search = Anon_Security_Security_Security_Security_Security::escapeLike($userInput);
$users = $db->db('users')
    ->where('name', 'LIKE', "%{$search}%")
    ->get();

检查 SQL 注入风险

php
// 检查字符串是否包含潜在的 SQL 注入代码
if (Anon_Security_Security_Security_Security_Security::containsSqlInjection($userInput)) {
    // 处理风险
}

接口限流

使用限流中间件

php
// 在 useCode.php 中注册限流中间件
Anon_Http_Middleware::global(
    Anon_Auth_RateLimitMiddleware::make(
        100, // 最大请求次数
        60,  // 时间窗口(秒)
        'api', // 限流键前缀
        [
            'useIp' => true,    // 基于 IP
            'useUserId' => true // 基于用户 ID
        ]
    )
);

手动检查限流

php
// 检查是否超过限制
$limit = Anon_Auth_RateLimit::checkLimit(
    'api:login', // 限流键
    10,          // 最大尝试次数
    3600         // 时间窗口(秒)
);

if (!$limit['allowed']) {
    // 超过限制
    Anon_Http_Response::error('请求过于频繁', [], 429);
}

// 返回信息
// [
//     'allowed' => bool,
//     'remaining' => int,
//     'resetAt' => int,
//     'count' => int
// ]

在路由中使用

php
// 在路由文件中检查限流
const Anon_Http_RouterMeta = [
    'header' => true,
    'requireLogin' => false,
    'method' => 'POST',
];

$limit = Anon_Auth_RateLimit::checkLimit('login', 5, 3600);
if (!$limit['allowed']) {
    Anon_Http_Response::error('登录尝试次数过多,请稍后再试', [], 429);
}

最佳实践

1. 始终使用预处理语句

php
// ✅ 正确
$stmt = $db->prepare('SELECT * FROM users WHERE id = ?', [$userId]);

// ❌ 错误
$sql = "SELECT * FROM users WHERE id = {$userId}";
$result = $db->query($sql);

2. 过滤用户输入

php
// ✅ 正确
$username = Anon_Security_Security_Security_Security_Sanitize::text($_POST['username']);
$email = Anon_Security_Security_Security_Security_Sanitize::email($_POST['email']);

// ❌ 错误
$username = $_POST['username'];

3. 验证 CSRF Token

php
// ✅ 正确
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    Anon_Auth_Csrf::verify();
}

// ❌ 错误
// 直接处理 POST 请求,不验证 CSRF

4. 使用限流保护敏感接口

php
// ✅ 正确
Anon_Http_Middleware::global(
    Anon_Auth_RateLimitMiddleware::make(10, 60, 'login')
);

5. 配置安全选项

server/app/useApp.php 中配置所有安全选项:

php
'security' => [
    'csrf' => [
        'enabled' => true,      // 是否启用 CSRF 防护
        'stateless' => true,    // 是否使用无状态 Token(推荐,减少 Session 锁竞争)
    ],
    'xss' => [
        'enabled' => true,      // 是否启用 XSS 自动过滤
        'stripHtml' => true,   // 是否移除 HTML 标签
        'skipFields' => ['password', 'token', 'csrf_token'], // 跳过的字段
    ],
    'sql' => [
        'validateInDebug' => true, // 在调试模式下验证 SQL 查询安全性
    ],
],

Released under the MIT License.