杜绝sql注入不能靠误传的“强制路由与严格过滤”,而必须采用参数绑定、字段白名单、类型校验和输入用途分离四条路径。

不能靠“开启强制路由与严格过滤”来杜绝SQL注入——ThinkPHP 6 本身不提供名为“强制路由”或“严格过滤”的全局开关,这类说法是误传。真正起效的只有参数绑定、字段白名单、类型校验和输入用途分离这四条路径。
where() 接字符串就是放弃防护
很多人写 where("name = '" . input('name') . "'") 或 where('status = ' . input('status')),以为加了引号就安全。其实 PHP 在双引号里解析变量后,整个字符串直接进 parseWhere() 做文本替换,PDO 预处理完全不触发。
- 安全写法只两种:
where(['name' => input('name')])(数组)或where('name', input('name'))(变量对) - 闭包也安全:
where(function ($q) { $q->like('name', input('q')); }) - 绝对禁止:
whereRaw("name = '{$_GET['name']}'")、where("id = {$id}")—— 这类写法让所有框架层防护形同虚设
原生 SQL 必须用 ? 占位符 + 参数数组
Db::query() 和 Db::execute() 是纯裸通道,框架不做任何解析。传进去什么,MySQL 就执行什么。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- ✅ 安全:
Db::query("SELECT * FROM user WHERE id = ? AND status = ?", [$id, $status]) - ✅ 命名占位也行:
Db::query("SELECT * FROM user WHERE name = :name", [':name' => $name]) - ❌ 危险:
Db::query("SELECT * FROM user WHERE id = " . input('id'))—— 即使$id是数字,攻击者仍可传10 UNION SELECT password FROM admin - ⚠️ 注意:
?不支持绑定表名、字段名、ORDER BY方向,这些必须走白名单校验
动态字段/排序/IN 查询必须显式白名单或展开占位
用户输入若参与 order()、group()、in 条件或表名拼接,? 无能为力,只能靠代码逻辑兜底。
-
order()危险写法:order(input('sort') . ' ' . input('dir'))→ 攻击者传id; DROP TABLE user--直接触发 - 正确做法:
in_array(input('sort'), ['id', 'name', 'create_time']) ?: die(); -
IN查询别直接 bind 数组:where('id', 'in', [1,2,3])是安全的(框架自动展开),但Db::query("WHERE id IN (?)", [[1,2,3]])会生成IN ('1,2,3')报错 - 更稳妥:
$ids = array_map('intval', input('ids/a', [])); where('id', 'in', $ids)
模型层字段类型 + auto_convert 才是静默防线
仅靠控制器里 input('id/d') 转整型不够——如果后续又在模型里用 force(true) 或动态字段覆盖,类型校验就失效了。
- 在模型中声明:
protected $type = ['id' => 'integer', 'status' => 'boolean']; - 确保
database.auto_convert为true(默认开启) - 传入
'id' => '1 OR 1=1'会被转成整数1,恶意部分直接丢弃;传入'id' => '(SELECT 1)'则转成0或抛异常 - ⚠️ 字符串字段(
string、text)不会被截断,仍需按输出场景做htmlspecialchars()或白名单验证
最易被忽略的一点:所有链式查询(where()、order()、limit())只是构建 Query 对象,真正绑定发生在 select()、find()、value() 执行时。调试中看到的 WHERE id = ? 不是 bug,是正常行为;想确认是否真绑定,得看日志里的 Binding: [1] 记录,而不是 SQL 模板。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










