ThinkPHP新版本(5.1+/6.x)默认禁用宽字节注入,因其强制UTF-8连接且不支持SET NAMES gbk;真实宽字节漏洞需同时满足:数据库连接指定gbk/big5、应用层手动单字节转义、TP未强制覆盖字符集。

ThinkPHP 框架本身在较新版本(5.1+、6.x)中已默认禁用宽字节注入的土壤——它强制使用 UTF-8 字符集连接数据库,且不再支持手动执行 SET NAMES gbk 类操作。因此,原生 TP 框架在标准配置下几乎不存在宽字节注入漏洞。但若项目存在非标准配置或历史遗留问题,仍需警惕绕过可能。
宽字节注入在 TP 中成立的前提条件
要让宽字节注入在 TP 环境中生效,必须同时满足以下三点:
- 数据库连接明确指定宽字节字符集(如
charset=gbk或charset=big5),且 MySQL 服务端实际支持该编码 - 应用层对用户输入做了单字节转义(如手动调用
addslashes()或错误复用旧版过滤逻辑),而非使用预处理或框架自带的参数绑定 - TP 的数据库驱动未强制覆盖连接字符集,或开发者通过
Db::execute('SET NAMES gbk')等方式主动切换了会话编码
常见误判场景:看似“宽字节”,实为其他漏洞
很多标为“TP 宽字节注入”的案例,实际是以下情况之一:
-
拼接式查询未走预处理:例如
Db::query("SELECT * FROM user WHERE name = '" . input('name') . "'"),此时无论编码如何,单引号都可直接闭合——这属于基础 SQL 注入,与宽字节无关 -
URL 解码 + 字符集不一致:前端传入
%df%27,TP 接收后未重编码就拼入 SQL;但若数据库连接是 UTF-8,%df%5c无法组成有效字符,反斜杠不会被“吞掉” -
自定义过滤函数缺陷:开发者自行写了类似
str_replace(["'", '"'], ['\'', '\"'], $input)的逻辑,又没统一编码上下文,导致多字节截断或解析错位
如何验证是否存在真实宽字节风险
可在测试环境中快速确认关键点:
- 查看数据库连接配置:
config/database.php中'charset'值是否为'gbk'或'big5' - 检查 SQL 执行方式:是否全部使用
where()、param()等参数化方法,还是存在query()/execute()拼接字符串 - 抓包观察请求与响应:传入
?id=1%df%27%20and%201=2%23,看是否报错或逻辑异常;再对比传?id=1%27%20and%201=2%23的行为差异
防御建议:从根源切断可能性
无需纠结“如何绕过”,而应确保以下实践落地:
- 强制数据库连接使用
utf8mb4,并在配置中显式声明'charset' => 'utf8mb4' - 禁用所有手动拼接 SQL 的写法,一律改用查询构造器或 ORM 方法(如
where('name', 'like', '%' . $kw . '%')) - 若必须兼容 GBK 旧系统,应在中间件中统一做 URL 解码 + 编码校验,拒绝含非法多字节序列的输入
- 启用 TP 内置的
sql_explain日志,定期审计是否有原始 SQL 字符串被动态拼入

















