addslashes在gbk环境下失效,因其仅做字节级转义(如'→%5c%27),而mysql按gbk解析时将%df%5c合成汉字(如「運」),导致%27裸露成单引号逃逸;需同时满足连接层为gbk、使用无字符集感知函数、表字段支持宽字节三条件。

addslashes() 为什么在 GBK 环境下失效
它根本不看字符集,只做字节级替换:遇到 ' 就插一个 (即字节 %5c),不管前后字节是否会被 MySQL 当成一个汉字。当输入是 %df%27,addslashes() 输出 %df%5c%27;MySQL 用 GBK 解析时,把 %df%5c 合成一个无效汉字(如「運」),%27 就变成裸露的单引号,直接进 SQL。
三个条件缺一不可,否则 payload 就是废码
宽字节注入不是随便传个 %df%27 就能打穿,必须同时满足:
- MySQL 连接层字符集设为
gbk/gb2312/big5(常见于SET NAMES gbk或旧版mysql_set_charset('gbk')) - PHP 层用了
addslashes()、mysql_escape_string()这类无上下文函数,而不是PDO::quote()或预编译绑定 - 表字段实际存储编码也得支持宽字节(如
CHARSET=gbk),否则 server 层内部转换可能截断或报错
为什么 %df 最常用,而不是其他高位字节
%81–%fe 都可能与 %5c 组成宽字符,但稳定性差异很大:
-
%df在绝大多数 GBK 环境下都能和%5c拼成合法双字节,不触发连接中断 -
%a1–%a9在部分 MySQL 5.5+ 中可能被识别为控制字符,导致 query 直接失败 - 如果用户输入里本来就有反斜杠,
addslashes()会产出%5c%5c,再拼%df就变成%df%5c%5c%27,MySQL 可能解析为「籠\'」——四个字节变两个汉字,%27依然逃逸
现代开发中真正该盯住的不是 %df,而是配置链断裂
还在被宽字节注入打中,往往不是因为没拦住某个字节组合,而是整个字符流链条没对齐:
- 仍在用已废弃的
mysql_*扩展,无法设置character_set_client=binary - 用
SET NAMES gbk替代更精确的SET character_set_connection=gbk, character_set_client=binary,导致 client 层仍按多字节解码 - 把
addslashes()当万能盾,却忽略它连0x00和的处理都不一致,更别说字符集博弈
最易被忽略的一点:连接字符集是否真生效,不能只看 SHOW CREATE TABLE,得查 SELECT @@character_set_client, @@collation_connection —— 表是 utf8mb4,连接是 gbk,照样中招。











