thinkphp 的 where() 方法传字符串不防 sql 注入,必须用数组或条件表达式触发 pdo 预处理绑定;原生 query/execute 必须手动 bind;raw()/exp() 跳过所有防护,仅限可信来源;字段名、表名须白名单校验。

ThinkPHP 的 where() 方法本身不防 SQL 注入——只要传字符串且含用户输入,就等同于裸 SQL 执行。
where() 传字符串为什么等于裸奔
框架对 where('id = ' . input('id')) 这类写法不做任何绑定或转义,直接拼进 SQL 字符串后交给 PDO 执行。哪怕加了单引号、双引号、intval() 包裹,只要变量在引号内被 PHP 解析,就完全失效。
- 错误示例:
where("name = '{$_GET['name']}'")、where('status = ' . $status)、where("title LIKE '%" . input('q') . "%") - 正确替代:
where(['name' => input('name')])、where('status', 'eq', $status)、where(['title' => ['like', '%' . input('q') . '%']]) - 数组写法会触发 ThinkPHP 内部的
PDO::prepare()+bindValue(),值永远不参与 SQL 解析
query() 和 execute() 必须手动 bind(),否则就是开闸放水
Db::query() 和 Db::execute() 是原生 SQL 接口,框架默认不干预——你传什么,它就扔给数据库什么。不显式绑定,等于放弃所有防护。
- 危险写法:
Db::query("SELECT * FROM user WHERE name = '" . input('name') . "'") - 安全写法(位置占位):
Db::query("SELECT * FROM user WHERE name = ? AND status = ?", [input('name'), 1]) - 安全写法(命名占位):
Db::query("SELECT * FROM user WHERE name = :name", [':name' => input('name')]) - 注意:
IN子句不能直接bind([1,2,3]),必须动态生成占位符:$ids = [1,2,3]; $placeholders = str_repeat('?,', count($ids) - 1) . '?'; Db::query("SELECT * FROM user WHERE id IN ($placeholders)", $ids);
raw() 和 exp() 是“免死金牌”,但用错就真没救了
raw()(TP6)和已废弃的 exp()(TP5)本质是告诉框架:“这段我来负责,你别管”。一旦用了,框架跳过所有绑定、转义、类型检查,原样插入 SQL。
- 典型误用:
where('created_time > ' . raw(input('start')))、order(raw(input('sort'))) - 正确做法:排序字段、表名、字段名这类非值上下文,必须白名单校验:
in_array(input('sort'), ['id', 'name', 'create_time']) ?: 'id' - 如果真要用
raw(),只限绝对可信来源:后台配置项、硬编码枚举映射、服务端固定值
容易被忽略的“二次注入”和模拟预处理陷阱
有些写法看似安全,实则埋着雷:比如从数据库读出一条带恶意 payload 的数据,再拿去拼 SQL;或者 PDO 配置中 PDO::ATTR_EMULATE_PREPARES 被设为 true,导致预处理被客户端模拟,实际仍是字符串拼接。
- 验证是否真走绑定:开启
'sql_explain' => true和'debug' => true,查日志里是否有Binding: [123]记录;更可靠的是用 Xdebug 跟进think\db\Connection::execute(),确认调用了bindValue()而非直接execute($params) - 数字型参数别用
PDO::PARAM_STR绑定,否则可能索引失效;WHERE id = ?传字符串'123',MySQL 可能隐式转成全表扫描 - 字段名/表名永远不能靠
str_replace()或正则“过滤”,必须严格白名单:in_array($table, ['user', 'order']) ?: die();
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











