SQL注入中0x十六进制字面量用于绕过字符过滤,因MySQL/SQL Server原生支持,防御必须前置到应用层:对所有用户输入用正则/0x[a-fA-F0-9]{2,}/扫描并拒绝,严禁解码检查;参数化查询须确保整个值走参数,禁用字符串拼接。

SQL注入里出现0x开头的十六进制字面量,说明攻击者在绕过字符过滤
数据库(尤其是 MySQL、SQL Server)允许用 0x414243 这种形式直接表示二进制/字符串,比如 0x414243 = 'ABC'。如果应用层只过滤了单引号、UNION、SELECT 等 ASCII 关键字,但没拦住十六进制字面量,攻击者就能把恶意 SQL 编成十六进制混入参数,绕过基础 WAF 或正则校验。
后端必须在解析前拒绝含0x前缀的输入,不能依赖数据库层拦截
靠数据库的 sql_mode 或权限控制拦不住——MySQL 默认就认 0x...,SQL Server 也支持 0x... 作为 varbinary 字面量;而且一旦拼进 SQL 字符串里,它早就在执行前被解释成原始字节了。防御动作必须前置到应用层:
- 所有用户输入(尤其 query string、form body、header 值)在进入业务逻辑前,用正则
/0x[a-fA-F0-9]{2,}/扫描,匹配即拒(HTTP 400 + 日志) - 不要试图“解码再检查”——
0x27就是单引号,解出来反而可能触发二次漏洞 - 若业务真需要传十六进制数据(如图片哈希、加密密钥),应限定字段名(如只允许
file_hash字段含0x),且做长度+字符集双重校验(仅限[a-fA-F0-9],长度为偶数,≤64)
参数化查询无法自动防住0x拼接,得看你怎么用
参数化本身安全,但前提是“整个值”走参数。常见翻车场景:
- 错误写法:
WHERE id = ' + req.query.id—— 即使id是数字,若前端传id=1 OR 1=1-- 0x414243,照样拼进去 - 正确写法:所有变量一律进
?或命名参数,且不参与字符串拼接。例如 Node.js 的pool.query('SELECT * FROM users WHERE status = ?', [req.query.status]) - 特别注意 ORM 的“原生查询”接口(如 Sequelize 的
query()、Django 的extra())——这些地方仍可能手动拼0x,必须人工审查
字符编码限制不是银弹,重点在输入语义而非字节范围
限制 Content-Type: application/json; charset=utf-8 或强制 iconv('gbk', 'utf-8') 对防 0x 注入基本无效。因为 0x414243 在任何编码下都是合法 ASCII 字符串,根本不会触发编码转换或截断。真正该做的:
- 对每个输入字段声明明确的语义类型(如 “手机号” “邮箱” “搜索关键词”),并用对应正则/库校验(如
isEmail()、isMobilePhone()) - 非自由文本字段(如状态枚举
active/inactive)直接白名单比对,拒绝一切非常量值 - 日志里记录原始请求体(含编码声明),方便回溯是否有人故意发
charset=latin1混淆解析
最易被忽略的一点:前端 JavaScript 的 encodeURIComponent() 不会编码 x 和数字,所以 0x41 经 URL 编码后仍是可读字符串,服务端收到时完全看不出异常——防御只能落在后端第一道入口,别指望客户端帮忙“净化”。











