使用正则表达式过滤SQL关键字无法确保安全,这已成为行业普遍认知——因为正则本质上只是对字符串进行模式匹配,而SQL注入的核心在于语法注入。攻击者绕过正则检测的手段,往往比开发者编写的规则更加丰富多样。

以一个简单例子说明:大小写混写。例如 SeLeCt、%55NION、/**/UNION/**/SELECT 等常见绕过方式,正则表达式 b(select|union)b 根本无法检测到。即使启用了大小写不敏感标志,URL编码、Unicode编码(如 union)、宽字节编码(如 %A1%AA)等变体仍然可以轻松绕过。数据库解析器在执行前会先进行解码,而正则通常只对原始输入进行一次匹配。
正则无法匹配大小写混写与编码变形
正则表达式 b(select|union)b 会遗漏 SeLeCt、%55NION、/**/UNION/**/SELECT 等常见绕过方式。即便添加了 i 标志,仍然无法覆盖 URL编码、Unicode编码(如 union)、宽字节编码(如 %A1%AA)等变体。数据库解析器在执行前会先进行解码,而正则通常只对原始输入进行一次匹配。
无法识别语义合法但上下文危险的片段
例如,用户昵称为 O'Reilly,如果正则匹配单引号就会误报;又如搜索关键词包含 order by price,order 和 by 单独出现本无危害,但组合后可能被拼接到动态 ORDER BY 子句中。正则表达式无法感知字段用途、拼接位置、SQL结构层级,只能孤立地检查词汇。
完全无法防御二阶注入与盲注探测
- 二阶注入:第一次输入存入数据库(例如昵称
admin'--),第二次读取后拼接到新查询中,正则表达式在入库时未触发,只有在执行时才生效 - 盲注探测:
' AND SLEEP(1)--或' AND (SELECT COUNT(*) FROM users) > 0--不包含典型关键字,依靠行为而非词法触发,正则表达式基本无效
性能与维护成本随规则膨胀急剧上升
为了覆盖更多绕过方式,就需要添加更多分支、预查、否定逻辑,例如:/(bselectb|bun[i1]onb|/*.*?*/|;|--|#)/is。这种正则不仅难以编写和测试,还会由于回溯爆炸导致请求处理变慢;更麻烦的是,每次发现新的攻击载荷,都必须修改规则、重新测试、上线部署,永远跟不上攻击者的速度。
要真正防御SQL注入,必须让恶意输入根本无法变成SQL语句——使用 PreparedStatement、pg_query_params、cursor.execute(sql, params) 等机制将数据和结构彻底隔离。正则表达式最多作为日志审计的辅助手段,不应让它担任第一道防线。
