正则清洗不能防SQL注入,因其无法覆盖宽字节、编码混淆、函数嵌套等绕过方式;真正有效的是参数化查询、白名单校验字段名、最小数据库权限。

正则清洗不能防SQL注入,别再写了
正则表达式做输入清洗,对SQL注入基本无效。它既无法覆盖所有绕过方式,又容易因规则宽松放行恶意载荷、或规则严格误杀合法输入。真实攻击者早就不靠 ' 或 UNION 明文出现来注入了——用宽字节、注释符、编码混淆、函数嵌套,WHERE id = 1 AND (SELECT ...) 这类结构连正则都难识别边界。
为什么 preg_replace + 黑名单永远漏报
常见做法是用 preg_replace 过滤 SELECT、INSERT、--、/* 等关键词,但问题极多:
- 大小写绕过:
SeLeCt、%53%45%4c%45%43%54(URL编码)都不匹配 - 内联注释干扰:
SEL/**/ECT、SELEC/*abc*/T拆开关键词仍可执行 - 空格非必须:
SELECT(id)FROM在 MySQL 中合法,且无空格就逃过空格依赖型正则 - 函数嵌套绕过:
EXTRACTVALUE(1,CONCAT(0x7e,(SELECT ...)))里没有一个关键词在黑名单中
真正该用的三件事:参数化 + 白名单 + 最小权限
防御SQL注入只有三条硬路,缺一不可:
- 所有动态拼接的查询,必须用
mysqli_prepare或PDO::prepare+bind_param,变量进?占位符,数据库引擎自动隔离语义 - 若必须拼接表名/字段名(如动态排序),只允许从预定义白名单中取值:
$valid_fields = ['name', 'created_at', 'status'];,用in_array($input, $valid_fields, true)校验 - 数据库连接账号去掉
FILE、PROCESS、GRANT OPTION等高危权限,限制只能查指定库表
正则唯一能用的场景:格式校验,不是防注入
正则可以且应该用在「输入是否符合业务格式」上,和SQL安全无关:
- 邮箱:
/^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i - 手机号(国内):
/^1[3-9]\d{9}$/ - 订单号(固定前缀+数字):
/^ORD-\d{8,12}$/
这些正则失败时直接拒绝请求,不尝试“清洗后入库”。清洗=伪造信任,而SQL注入的本质,就是你信了不该信的字符串。
最常被忽略的一点:ORM 框架里的 where 方法如果接受数组或键值对,通常默认参数化;但如果传入的是拼接好的字符串(比如 where("status = '" . $_GET['s'] . "'")),那 ORM 也救不了你——得看实际生成的 SQL 是什么,不是看用了什么框架。










