数值型注入不触发单引号转义,因数字上下文无需引号,攻击者可直接输入1 OR SLEEP(5)等表达式改变查询逻辑;根本防御是类型校验加参数化,而非仅过滤引号。

数值型参数根本不会触发单引号转义
单引号转义(比如用 mysql_real_escape_string 或 addslashes)只对字符串字面量里的引号起作用,而数值型上下文压根不加引号。当 SQL 语句写成 WHERE id = $_GET['id'] 时,数据库期望一个数字,不是字符串——所以攻击者输入 1 OR SLEEP(5),拼接后变成:
WHERE id = 1 OR SLEEP(5)
这里没有单引号,转义函数完全不介入,SQL 解析器直接执行逻辑运算。
数字字段无法靠引号闭合,也就没有“逃逸”入口
字符型注入能成功,是因为攻击者靠 ' 打破原有字符串边界,再用 -- 或 # 注释掉后续逻辑。但数值型字段本身不带引号,不存在“闭合”这回事。你没法用单引号去“打断”一个纯数字位置,自然也谈不上转义防御是否生效。
- 输入
1' OR '1'='1→ 报错:语法错误,因为'在数字上下文里是非法字符 - 输入
1 OR 1=1→ 完全合法,直接改变查询语义 - 输入
1 UNION SELECT username,password FROM users→ 同样合法,且无需任何引号
类型混淆才是核心问题,不是字符要不要转
开发者误以为“过滤了单引号就安全”,其实是把 SQL 注入简化成了“引号问题”。但本质是类型失控:用户输入本该是整数,却被当成了表达式执行。真正该做的是强制类型校验 + 参数化,而不是在字符串层打补丁。
-
(int)$_GET['id']能拦住大部分非数字输入,但绕过手段很多(如1.0、+1) - 仅靠类型转换不能替代参数化——
WHERE id = ?才让数据库明确知道这是值,不是代码 - ORM 的
where('id', $input)或 PDO 的bindValue(':id', $input, PDO::PARAM_INT)才是从机制上切断风险
MySQL 和 PostgreSQL 对数字上下文的解析完全不依赖引号
主流数据库对数值型字段的处理是统一且宽松的:只要语法合法,就按表达式求值。这意味着 1 AND 2=2、1 ORDER BY 1、1 LIMIT 1,1 全部有效。而这些结构里:
— 没有单引号
— 不触发任何转义逻辑
— 不受字符集(如 gbk 宽字节)影响
— 也不吃注释符(-- 在数字后反而会报错)
换句话说,数值型注入不是“绕过”了转义,而是从一开始就没进入转义的管辖范围。
真正危险的从来不是单引号本身,而是你让数据库去解释用户输入的那一刻——无论它有没有引号。

















