ThinkPHP 5.0.18存在表达式注入风险,因where中字符串型表达式未严格校验,误用字符串传参可导致SQL注入甚至RCE;需识别危险写法、验证表达式解析路径、审计order/group/having等扩展点,并通过数组传参、字段白名单、升级版本及权限限制加固。

ThinkPHP 5.0.18 存在表达式注入风险,核心在于框架对 where 条件中传入的字符串型表达式未做严格校验,当开发者误用非数组方式传参时,可能触发 SQL 表达式拼接漏洞,导致 SQL 注入甚至 RCE(在特定组合下)。
识别典型危险写法
重点关注控制器中类似以下模式的数据库查询逻辑:
-
危险写法(字符串直传):
where('status', 'in', '1,2,3')或where('name', 'like', '%'.$_GET['q'].'%')—— 框架会原样拼入 SQL,无参数化保护; -
安全写法(数组传参):
where('id', 'in', [1, 2, 3])或where('name', 'like', "%{$_GET['q']}%")(需配合预处理机制); - 特别注意
exp类型条件,如where('score', 'exp', '>= (SELECT AVG(score) FROM user)'),若值来自用户输入且未过滤,极易引入子查询注入。
验证是否存在可利用表达式上下文
并非所有 where 调用都危险,需确认是否满足“表达式解析路径开启”条件:
- 检查是否使用了
Db::table()->where(...)->select()等原生查询链路(非模型自动转义场景); - 确认未启用全局参数绑定或未覆盖默认的
parseWhere解析逻辑; - 测试构造 payload:
?id[0]=in&id[1]=1,2,3)或?name[0]=like&name[1]=%a%') OR 1=1 --,观察报错或响应差异(如 MySQL 报错信息泄露、结果集异常扩大)。
关注高危函数与扩展点
除基础 where 外,还需审计以下易被忽略的注入入口:
立即学习“PHP免费学习笔记(深入)”;
-
order()方法:如order($_GET['sort']),直接拼入 ORDER BY 后,可注入id ASC, (SELECT ...); -
group()和having():同样接受原始字符串,having('count(*) > '.$_GET['n'])可绕过常规 where 过滤; - 自定义查询闭包:
where(function ($query) { $query->where('xxx', $_GET['v']); }),若内部未做二次过滤,即成盲点。
修复与加固建议
不依赖“不写错”,而应建立防御纵深:
- 强制统一使用数组传参形式,禁用字符串直传
in/like等操作符; - 对所有用户可控字段(
order,group,field)做白名单校验,例如只允许['id', 'name', 'create_time']; - 升级至 ThinkPHP 5.0.24+ 或 5.1.32+,官方已修复多处表达式解析绕过问题;
- 在数据库层限制应用账号权限,禁用
SELECT INTO OUTFILE、LOAD_FILE等高危操作。



















