最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
基于宽字节(GBK编码)的特殊SQL注入漏洞如何修复
时间:2026-07-01 09:46:46 编辑:袖梨 来源:一聚教程网
SET NAMES 'gbk'会触发宽字节注入,因其仅设置character_set_client等会话变量,未同步连接层编码上下文,导致addslashes()按单字节转义('→%5c%27),而MySQL用GBK解析时将%df%5c组合成汉字,“吃掉”反斜杠使%27逃逸;必须改用mysqli_set_charset()或SET character_set_client=binary等方案对齐编码。
为什么 set names gbk 会触发宽字节注入
因为 SET NAMES 'gbk' 只修改了 MySQL 的 character_set_client、character_set_results 和 character_set_connection,但没真正绑定连接层的字符集语义。PHP 调用 addslashes() 时按单字节处理(比如把 ' → ',即 %27 → %5c%27),而 MySQL 在解析时把前面一个高位字节(如 %df)和 %5c 拼成一个 GBK 宽字符(如 “運”),导致 %5c 被“吃掉”,%27 逃逸成裸单引号。
mysql_set_charset() 和 mysqli_set_charset() 是必须替换的点
这两个函数不仅发 SET 命令,还会同步设置连接层的字符集上下文,让 MySQL 在接收数据时严格按指定编码解析,避免宽字节“吞字”行为。不替换 SET NAMES 就等于没修。
-
mysql_set_charset("gbk", $conn)(已废弃,仅用于遗留代码) -
mysqli_set_charset($conn, "gbk")(推荐,需在mysqli_real_escape_string()前调用) - 如果用 PDO,必须显式设置
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4",且不能只靠 DSN 中的charset=gbk
mysql_real_escape_string() 不能替代预编译,但它是宽字节场景下的兜底手段
该函数内部会读取当前连接的实际字符集(由 mysqli_set_charset() 设置),再做符合该编码规则的转义——比如对 GBK,它知道 %df%5c 是合法双字节,不会盲目拼接反斜杠。而 addslashes() 完全无视编码,纯字节流操作,必然出问题。
- 必须确保
mysqli_real_escape_string()调用前,连接已通过mysqli_set_charset()设定好字符集 - 若传入空连接或未初始化连接,函数返回
false,容易被忽略导致绕过 - 它只防字符串型注入,数字型参数仍需
intval()或参数化
character_set_client=binary 是最硬核的防御方式
在查询前执行 mysqli_query($conn, "SET character_set_client = binary"),会让 MySQL 把客户端输入当作原始字节流处理,不再尝试按 GBK 解码。此时 %df%5c%27 不会被识别为“運'”,而是三个独立字节,MySQL 直接报错或截断,无法构成有效 SQL 语法。
- 这个设置只影响当前 query,需每次查询前重设(或封装进统一 query 函数)
- 它不解决乱码问题,但能彻底阻断宽字节注入链路
- 注意:不能和
SET NAMES混用,否则后者会覆盖前者
SET NAMES gbk + addslashes(),就等于门没锁死。
相关文章
- 明末渊虚之羽版本奖励错误如何补偿 07-01
- 原神峡谷盈月之镜解谜方法 07-01
- 末日进化如何升级人物卡 07-01
- 魔兽世界卡格罗什的命运背包位置在哪 07-01
- 沙石镇时光体力恢复方法大全 沙石镇时光快速回满体力的实用技巧 07-01
- 空洞骑士寻神者篇章攻略 07-01