黑名单过滤在sql注入防护中本质失效,因其仅做字符串匹配而数据库执行语法树;如union//select、%75nion、/!50000union*/等变形可绕过大小写、注释、编码检测,且waf与数据库解析存在语义鸿沟。

黑名单过滤机制无法彻底阻断高级SQL注入绕过——不是规则写得不够多,而是它从底层逻辑上就无法匹配数据库执行的真实语义。
黑名单匹配的是字符串,数据库执行的是语法树
当你在代码里写 preg_replace('/union|select/i', '', $input),你是在对原始请求字符串做线性扫描;而 MySQL 接收到的最终查询是经过 URL 解码、变量拼接、空格归一、注释剥离后的语法结构。两者根本不在同一抽象层级。
常见错误现象包括:
- 输入
id=1%20UNION%20SELECT被放行:因为 %20 是 URL 编码空格,过滤器若在解码前扫描,看到的是%20UNION%20SELECT,不匹配union - 输入
UnIoN/**/SeLeCt成功执行:大小写+注释组合绕过/union|select/i的简单正则 - 输入
/*!50000UNION*/ SELECT绕过 WAF:MySQL 把/*!...*/当作可执行内联注释,而多数 WAF 规则直接跳过所有/*开头的内容
空格、分隔符和括号的多样性让“切词”失效
SQL 解析器允许大量合法替代空白的方式,而黑名单很难穷举所有上下文组合。
使用场景中典型绕过方式有:
一款AI工具,主要用于Monitor and clean up invalid Codex authentication files in CPA. Check quota status, disable files returning 401 errors, and perform dual verification before deletion.,适合需要提升相关任务效率的用户。
-
%09(Tab)、%0a(换行)、%A0(NBSP):部分 WAF 未将它们纳入空白字符白名单 -
/**/不仅能替代空格,还能跨关键字拆分,如SEL/**/ECT→ 实际执行为SELECT - 括号包裹子句:
UNION(SELECT(1),database(),user())可绕过“关键字+空格”的检测逻辑 - 反引号或方括号:
SELECT`password`FROM`users`在某些 MySQL 版本中合法,但黑名单通常不覆盖标识符包裹语法
双写、编码、函数嵌套构成系统性绕过链
攻击者不是单点突破,而是构造多层变形,让黑名单在任一环节失守即全线崩溃。
容易踩的坑包括:
- 只做一次替换:
str_replace('union', '', $input)导致ununionion→union,双写绕过直接生效 - 忽略编码上下文:输入
sel%65ct(%65 是 e 的 URL 编码),过滤器看到的是sel%65ct,数据库解码后却是select - 未处理函数调用:
CONCAT(CHAR(117),CHAR(110),CHAR(105),CHAR(111),CHAR(110))可动态拼出union,完全脱离关键字字面匹配 - 混淆大小写与注释混合:
uNIoN%09SeLecT同时触发大小写、URL 编码、空白字符三重绕过
真正有效的防御必须脱离字符串层面
参数化查询(Prepared Statements)之所以可靠,是因为它把“数据”和“结构”在驱动层就做了隔离——用户输入永远进 bind 参数,不会参与 SQL 解析;而黑名单还在试图用文本规则模拟语法分析,注定失败。
复杂点在于:很多老系统用的是拼接式 ORM 或原生 mysql_query(),强行加参数化可能引发兼容性问题;更隐蔽的风险是,开发者以为加了 addslashes() 或 mysqli_real_escape_string() 就安全了,却忽略了这些函数在非单引号上下文(比如数字型参数、ORDER BY 子句、表名位置)完全无效。










