ThinkPHP where条件不加类型声明易导致SQL注入,因默认不校验参数类型,如'id'=>'1 OR 1=1'会原样拼入SQL;需通过模型$type定义、auto_convert配置或input过滤器强制转换类型。

ThinkPHP 的 where 条件中不加类型声明为什么容易出问题
因为 ThinkPHP 默认对 where 中的值不做类型校验,比如传入 'id' => '1 OR 1=1',若字段定义为 int 却没启用类型转换,框架仍会原样拼进 SQL —— 这就是典型注入入口。
常见错误现象:where('id', '1; DROP TABLE user') 在未开启类型约束时可能被当作字符串处理,最终生成 WHERE id = '1; DROP TABLE user'(虽未必执行成功,但已脱离预期语义);更隐蔽的是数字型字段被传入含函数或子查询的字符串,如 'id' => '(SELECT password FROM admin LIMIT 1)'。
- 使用场景:API 接口接收 GET/POST 参数后直接用于查询,例如
$this->where('id', input('id'))->find() - 关键区别:
where('id', 1)和where('id', '1')在未指定类型时,底层都走字符串拼接;只有显式声明类型(如where('id', 1, 'eq')或配合模型字段类型)才会触发强制转换 - 性能影响极小——类型检测发生在参数解析阶段,不涉及额外数据库查询
在模型中定义字段类型并启用 auto_convert
ThinkPHP 6+ 的模型支持通过 $schema 或 $type 属性声明字段类型,配合配置项 database.auto_convert(默认 true)可自动将传入值转为目标类型。
例如定义用户模型字段:
立即学习“PHP免费学习笔记(深入)”;
protected $type = [
'id' => 'integer',
'status' => 'boolean',
'create_time' => 'datetime:Y-m-d H:i:s',
];- 必须确保数据库字段实际类型与 PHP 类型匹配,否则转换失败(如 DB 字段是
VARCHAR却设为integer,会导致0或空值) - 字符串类字段(
string、text)不会被截断或过滤,仍需配合htmlspecialchars或白名单验证防止 XSS 或二次注入 - 日期类型字段若传入恶意字符串如
'2024-01-01; SELECT * FROM xxx',会被转成null或抛异常,从而阻断注入链
用 queryWhere 替代 raw where 避免手动拼接
直接写 where('id = '.$input) 或 whereRaw('id = '.$input) 是高危操作,绕过了所有框架层防护。应优先使用参数绑定式查询方法。
- 推荐写法:
where('id', input('id', 0, 'intval'))—— 利用 input 的过滤器提前转整型 - 复杂条件用闭包 + 绑定:
where(function ($query) { $query->where('id', input('id'))->where('status', 1); }) - 绝对禁止:
whereRaw("id = ".$_GET['id'])、where("id = {$_GET['id']}"),这类写法让类型检测完全失效 - 注意:即使开启了
auto_convert,whereRaw和query方法中的字符串插值也不会被转换,它们属于“绕过通道”
调试时如何确认类型转换是否生效
最直接的方式是开启 SQL 日志,看生成的语句里值是否已被格式化。比如传参 id=1%20OR%201=1,正常应看到 WHERE `id` = 1,而不是 WHERE `id` = '1 OR 1=1'。
- 开启日志:在配置中设
'log' => ['level' => ['sql']],然后查 runtime/log/ 目录下的日志文件 - 检查模型实例的
$this->getOptions()['where'],可看到条件数组中值是否已转为对应类型(如int(1)而非string(9) "1 OR 1=1") - 容易忽略的一点:控制器里用
Db::name('user')->where(...)不走模型类型定义,必须用模型实例(UserModel::where(...))才能触发$type转换逻辑
类型检测不是银弹,它只解决“本该是数字却传了字符串”这类基础错配;真正复杂的业务规则(比如用户名只能含字母数字下划线)还得靠验证器和白名单控制。别以为开了 auto_convert 就能躺平。



















