ThinkPHP 6.3 无全局自动过滤机制,防 SQL 注入须在查询前按上下文防护:数字转类型、枚举走白名单、文本限长防 XSS,所有查询必须用参数绑定,禁用 whereRaw 拼接,确保 PDO 预处理启用且权限最小化。

ThinkPHP 6.3 中没有“全局自动过滤所有输入”的安全机制,也不能靠开启某个开关就一劳永逸防 SQL 注入。真正有效的做法是:**在数据进入查询前的每个关键节点,按上下文做针对性防护**——这比幻想“全局过滤”更可靠、更可控。
只对参数值做类型/范围校验,不碰原始输入
不要试图用 filter_var 或正则统一“清洗”所有 $_GET、$_POST。很多业务场景下,用户输入本就该含特殊字符(如邮箱、JSON 字符串、搜索关键词)。错误的全局过滤反而破坏数据语义,还可能绕过校验逻辑。
- 对数字类参数,强制类型转换:
(int)input('id')、intval(input('page')) - 对状态、排序字段等有限枚举值,走白名单:
in_array(input('status'), ['draft', 'published', 'deleted']) ?: 'draft' - 对用户名、标题等文本字段,仅在入库前做长度限制和 XSS 过滤(如
htmlspecialchars()),而非用于 WHERE 条件拼接
所有数据库查询必须使用参数绑定
这是最核心的一条。ThinkPHP 6.3 的 where()、whereLike()、whereIn()、whereBetween() 等方法默认支持 PDO 参数绑定,框架会自动转义并防止注入。
- ✅ 正确:
->where('title', 'like', '%' . input('q') . '%')—— 框架将%xxx%当作完整参数传给 PDO - ❌ 危险:
->whereRaw("title LIKE '%" . input('q') . "%')—— 字符串已拼接完成,PDO 完全不介入 - ✅ 动态字段名需白名单:
$field = in_array(input('sort'), ['name', 'create_time']) ? input('sort') : 'id'; $query->order($field . ' DESC');
禁用或严格管控 whereRaw、query->execute 等直通接口
whereRaw() 是明确绕过所有安全层的通道,不是“高级用法”,而是“最后手段”。项目中应禁止直接拼接用户输入;如确需使用(例如 JSON_CONTAINS、GIS 函数),必须显式传参数组触发绑定:
- ✅ 可信写法:
->whereRaw('json_contains(tags, ?)', [$keyword]) - ❌ 绝对禁止:
->whereRaw('json_contains(tags, "' . input('tag') . '")') - 建议在基础模型类中重写
whereRaw()方法,加入日志告警或开发环境抛异常,倒逼团队改用安全方式
配合数据库连接层加固
即使代码写了 ? 占位符,若 PDO 配置不当,仍可能退化为字符串拼接:
- 检查数据库配置中是否设置了
'PDO::ATTR_EMULATE_PREPARES' => false(TP6 默认已是 false,但自定义连接时易遗漏) - 上线前开启 MySQL general_log,确认真实执行的 SQL 是否含
WHERE id = ?而非WHERE id = 123 - 避免在生产环境使用 root 或高权限数据库账号,最小权限原则分配表级操作权限
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











