ThinkPHP 6.0 中 order() 引发 SQL 注入的本质是 ORDER BY 后字段名为标识符,无法参数化,必须通过白名单校验用户输入的排序字段;所有外部输入参与 order() 前须比对预设允许字段(如 id、create_time),不匹配则回退默认值,严禁字符串拼接、Db::raw() 或函数中嵌入用户输入。

ThinkPHP 6.0 中排序参数(如 order())引发的 SQL 注入,本质是字段名/关键字无法参数化,必须靠白名单校验来堵住漏洞。这不是框架没防护,而是 SQL 语法限制——ORDER BY create_time DESC 中的 create_time 是标识符,不是数据,PDO 预处理不支持绑定字段名。
所有 order() 调用前必须校验字段名
用户输入的排序字段(如 $_GET['sort'] 或 input('sort'))绝不能直接传给 order()。必须先比对预设白名单,匹配才使用,否则默认回退安全字段。
- 定义允许字段:例如
$allowedSorts = ['id', 'create_time', 'update_time', 'status', 'price']; - 获取并过滤输入:
$field = input('sort', 'id', 'trim|strtolower'); - 校验与赋值:
$realField = in_array($field, $allowedSorts) ? $field : 'id'; - 安全调用:
->order([$realField => 'desc'])或->order($realField . ' DESC')
警惕闭包和链式写法中的隐性拼接
以下写法看似用了查询构造器,实则绕过所有绑定机制:
-
->order(input('sort') . ' ' . input('order'))—— 字符串拼接,直接裸奔 -
->where(function ($q) { $q->order(input('sort') . ' DESC'); })—— 闭包内仍需独立校验 -
->order(Db::raw(input('sort') . ' DESC'))——Db::raw()完全放弃防护
只要出现 input()、$_GET、$_POST 等外部输入参与字符串拼接,就必须立即插入白名单判断。
避免用函数或表达式替代字段名
有人试图用数据库函数“增强排序逻辑”,例如 order("FIELD(status, 'draft','online','closed')") 或 order("LENGTH(title)"),但这类写法若字段名或参数来自用户输入,极易被注入。除非该函数及全部参数均为硬编码,否则一律禁止。
- ❌ 危险:
->order("FIELD(status, '" . input('states') . "')") - ✅ 安全:
->orderRaw("FIELD(status, 'draft','online','closed')")(仅限固定值) - 更推荐:将复杂排序逻辑移到 PHP 层做内存排序,或拆分为多个明确字段+白名单组合
上线前快速自查高危点
不用逐行读代码,用文本搜索定位风险位置:
- 全局搜
order(、->order,再人工确认括号内是否含input(、$_GET、$_POST - 搜
input(.*?sort|order|by|field)正则,看是否紧邻order()或group() - 重点检查分页接口、后台列表页、导出功能、自定义报表等涉及动态排序的模块
不复杂但容易忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











