ThinkPHP 5.1.24聚合查询注入漏洞源于max()等方法的字段参数未经parseKey合法性校验,导致用户可控字段名被反引号包裹后直插SQL引发上下文逃逸。

ThinkPHP 5.1.24 的聚合查询注入漏洞,核心问题是 max()、min()、count()、sum() 等方法的第一个参数(字段名)被用户直接控制,而框架在 parseKey 中未做合法性校验,导致反引号包裹后拼入 SQL,形成字段上下文逃逸。
确认风险调用点
搜索项目中所有聚合函数调用,重点关注字段名是否来自用户输入:
-
db()->max(input('col'))、$model->count($request->param('field'))这类写法高度可疑 - 检查参数来源:包括
input()、param()、get()、post()及其带前缀变体(如input('sort.field')) - 若字段名是硬编码字符串(如
'price')、常量或配置项,则不构成风险
验证 parseKey 是否绕过过滤
该漏洞依赖于 parseKey($key, $strict = true) 在聚合场景下的缺陷逻辑:
- 进入
thinkphp/library/think/db/Builder.php的aggregate()方法 - 观察是否调用了
$this->parseKey($key, true) - 再跟进到
thinkphp/library/think/db/connector/Mysql.php的parseKey(),确认其返回值为`' . $key . '`,且无正则过滤或白名单限制
快速探测是否存在漏洞
构造简单 URL 参数触发语法错误即可判断:
- 访问
/index/test?col=id%60)%23(解码后为id`)#) - 若返回 MySQL 错误如
Unknown column 'id`)#'或syntax error near `id`)#`,说明字段名已直插 SQL - 进一步尝试
col=id%60)from%60users%60where%60id%60=1%23,观察是否影响查询逻辑或泄露信息
修复与加固措施
必须从调用源头切断风险,不能依赖通用输入过滤:
- 字段名严格限定白名单:
$allowed = ['id', 'price', 'create_time']; if (!in_array($col, $allowed)) throw new Exception('Invalid field'); - 改用条件分支代替动态传参:
if ($col === 'price') { $result = db()->sum('price'); } elseif ($col === 'score') { $result = db()->avg('score'); } - 升级至 ThinkPHP 5.1.26 或更高版本(官方已修复
parseKey在聚合场景下的缺陷) - 生产环境关闭调试模式:
'app_debug' => false,防止 SQL 报错信息泄露敏感结构
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











