ThinkPHP6.0默认启用预处理机制,SQL注入风险大幅降低但非绝对免疫;需重点测试是否绕过安全机制,如手动拼接SQL、误用query()/execute()、where传入用户可控key、raw()含未过滤输入、调试模式泄露SQL等。

ThinkPHP6.0 默认已启用参数绑定与预处理机制,SQL注入风险大幅降低,但并非绝对免疫。测试重点不是“能不能注入”,而是确认开发过程中是否绕过了框架安全机制——比如手动拼接 SQL、误用 query() / execute()、未校验输入就直接进数据库操作等。
确认是否绕过框架安全机制
ThinkPHP6.0 的 Model 和 Db 类默认使用 PDO 预处理,只要全程走 find()、select()、where() 链式调用,基本不会产生注入。但以下写法是高危信号:
- 直接拼接字符串后调用 Db::query() 或 Db::execute(),例如:
Db::query("SELECT * FROM user WHERE id = " . input('id')) - 在 where() 中传入原始数组但 key 是用户可控变量(如
where([$k => $v]),而 $k 来自 $_GET) - 使用 raw() 方法且内容含未过滤的用户输入,例如:
where('status = ' . input('status')) - 开启调试模式(APP_DEBUG=true)且错误页泄露完整 SQL 语句——这虽不等于可注入,但极大方便漏洞验证
针对性测试注入点
ThinkPHP 常见注入入口集中在 URL 参数、表单字段、路由变量、请求头(如 X-Requested-With 被用于条件判断)等。测试时优先覆盖这些位置:
-
URL 查询参数:如
/user/detail?id=1→ 尝试?id=1' and sleep(3)--+,观察响应延迟;再试?id=1' and extractvalue(1,concat(0x7e,user()))--+看是否报错回显 -
POST 表单字段:登录、搜索、筛选类接口,用 Burp 或 HackBar 提交
username=admin' OR 1=1-- &password=123 -
路由变量:如定义了
Route::get('article/:id', 'index/article'),则/article/1'可能触发异常 -
JSON 请求体:若接口接收 JSON,检查是否对
data["order_by"]这类字段做白名单限制,避免"order_by":"id, updatexml(1,1,1)"类利用
识别 ThinkPHP 特有行为辅助判断
ThinkPHP6.0 对部分非法输入会自动截断或转义,需结合其特性设计 payload:
立即学习“PHP免费学习笔记(深入)”;
- 单引号可能被自动加斜杠(magic_quotes 已废弃,但框架内部可能二次处理),可尝试双引号闭合或无引号数字型场景
- 若
?id[]=1&id[]=2导致报错,说明后端用了in()但未校验数组元素类型,可试?id[]=1) and updatexml(1,1,1)-- - ThinkPHP 日志中若出现
SQLSTATE[42000]或PDOException且含 SQL 片段,说明存在未捕获的拼接逻辑 - 注意 __token__ 字段:若绕过 token 校验(如删掉该字段仍能提交),可能连带暴露未过滤的业务参数
绕过常见防护的思路
即使项目启用了 WAF 或中间件,也要验证其有效性:
- 大小写混淆:
SeLeCt、UnIoN替换关键词 - 内联注释:
/*!50000Select*/利用 MySQL 注释执行 - 编码绕过:URL 编码单引号
%27、空格%20,或 UTF-8 双字节空格%A0 - 利用 ThinkPHP 自动类型转换:传入
?id=1abc,若返回与?id=1相同结果,说明后端做了 int 强制转换;若报错,则可能未转换,值得深挖



















