ThinkPHP 5.1 默认通过PDO预处理防SQL注入,但手动拼接、raw()/exp()误用、动态字段/表名、用户控制数组键名等场景仍存在风险,需规范写法并配合白名单、升级版本等措施。

能防住大部分基础 SQL 注入,但不是绝对安全,关键看你怎么写代码。
默认机制确实做了防护
ThinkPHP 5.1 对 where()、find()、select()、update() 等链式方法,默认启用 PDO 预处理 + 参数绑定。只要传参方式规范,比如:
$user = Db::name('user')->where('id', input('id'))->find();$list = User::where(['status' => 1, 'name' => ['like', '%' . input('q') . '%']])->select();
这类写法中,用户输入会被当作纯数据传入预处理语句,SQL 结构和数据完全分离,天然防注入。
但这些地方默认不防护
框架不会替你校验“看起来像变量”的东西,以下写法哪怕在 5.1.31 也会出问题:
立即学习“PHP免费学习笔记(深入)”;
-
手动字符串拼接:如
where('id = ' . input('id'))或where("title like '%" . input('kw') . "%') -
误用 raw() / exp():如
where('id', 'exp', ['eq' => input('id')])若 input('id') 是1 OR 1=1,就直接进 SQL -
动态字段/表名:如
order(input('sort') . ' desc')或field(input('fields'))—— 字段名无法参数化,必须白名单控制 -
数组键名被用户控制:这是 5.1.25 的高危漏洞根源,例如
insert($_GET['data'])中$_GET['data']键名为id`)等恶意内容,会直接拼入字段位
配置项影响实际防护效果
有些安全能力依赖正确配置,否则形同虚设:
-
app_debug = false:开启调试模式时,报错可能泄露表结构、字段、路径,方便攻击者构造 payload -
url_route_must = true:防止通过?s=xxx绕过路由和中间件校验 -
default_return_type和var_export类输出若未过滤,也可能引发二次注入或信息泄露
真正靠谱的防御要靠开发习惯
框架只是工具,最终防线在人:
- 所有数据库操作优先用数组条件,不用字符串拼接
- 用户输入的字段名、表名、排序方向等,必须走白名单:
in_array($field, ['id', 'name', 'create_time']) - 原生 SQL(
Db::query())务必手动绑定参数,别传裸变量 - 升级到 5.1.31+ 并禁用旧版(5.1.25 及之前存在已知绕过漏洞)
- 生产环境尽早迁移到 TP6.3+ 或 TP8.0+(5.1 系列已停止官方维护)



















