SQL注入至今仍是Web安全领域最致命的漏洞之一,而WAF(Web应用防火墙)作为防御的第一道门槛,其绕过与加固的对抗从未停止。攻击者早已不再使用简单的单引号探测,而是利用数据库特性、编码差异和正则逻辑缺陷来构造变形payload。本文直接从实战角度拆解当前主流的绕过手法,并给出对应的正则加固方案,不绕弯子。

注释符变形与内联注释攻击

常规的注释符如“-- ”、“#”、“//”早已被多数WAF规则覆盖,但攻击者利用MySQL特有的内联注释特性可以轻松绕过。例如“/*!50000union*/”这种写法,在MySQL中会被当作可执行语句解析,而很多WAF的正则表达式并未将感叹号后的数字组合纳入匹配范围。更隐蔽的变形是“/*!union*/”这种零版本号的写法,同样能被执行。攻击者还会将敏感关键字拆解后嵌入注释,如“un//ion”,WAF如果仅对连续字符串做匹配就会漏报。加固这类攻击的正则不能简单匹配“\/\*.*\*\/”,需要专门针对内联注释中的可执行内容编写规则,例如“\/\*![0-9]*[a-z]+”来捕获带版本号的可执行片段,同时配合对“\/\*.*关键词.*\*\/”这类拆解模式的检测。

空白字符与换行符替代技术

SQL语句中分隔关键字和参数的空白字符可以被多种不可见字符替代,这是WAF正则最容易忽略的盲区。MySQL允许使用制表符(%09)、换行符(%0a)、回车符(%0d)、垂直制表符(%0b)、换页符(%0c)以及反引号来替代普通空格。例如“union%0aselect”可以完全绕过仅匹配“union select”的正则规则。更高级的变形是利用MySQL对科学计数法的解析特性,如“1.e(union)”或“1.union”这种小数点加关键字的组合,在特定上下文中会被解析器忽略小数点前的数字而执行后续语句。加固方案不能只匹配空格,需要将正则中的“\s”扩展为“[\s%0a%0d%0b%0c%09]”,并对小数点与关键字相邻的模式增加检测,例如“\d+\.\s*(union|select)”这类规则。

大小写混合与双重编码绕过

多数WAF默认开启大小写不敏感匹配,但攻击者利用数据库函数和关键字的大小写变形只是基础操作。真正棘手的是双重编码,例如先将“union”进行URL编码得到“%75%6e%69%6f%6e”,WAF解码一次后还原出关键字并拦截,但如果攻击者对百分号本身再次编码,形成“%2575%256e%2569%256f%256e”,WAF解码一次后得到的是“%75%6e%69%6f%6e”这个字符串而非关键字,从而绕过检测,而Web服务器或应用层会进行二次解码还原出真正的payload。加固这类攻击需要WAF具备递归解码能力,正则层面则需要匹配百分号编码的嵌套模式,例如“%25[0-9a-fA-F]{2}”连续出现两次以上的特征。

等价函数与运算符替换

当WAF将“union select”、“information_schema”、“load_file”等关键字写入黑名单后,攻击者会转向功能等价的替代方案。例如“union distinct select”中的distinct不影响结果但能打乱正则匹配;“sleep(5)”可替换为“benchmark(10000000,md5(1))”实现同样的延时效果;字符串截取函数substring可替换为mid、substr、left、right;获取数据库名时不用database()而用“schema()”或直接从“@@datadir”中提取路径信息。运算符层面,“and”可替换为“&&”,“or”可替换为“||”,“=”可替换为“like”、“regexp”、“between”。加固的正则不能只做关键字黑名单,需要建立函数行为特征库,例如对延时注入的检测不应只匹配“sleep”,而应匹配任何包含大量循环操作的函数调用模式,如“benchmark\s*\(\s*\d+\s*,”。

宽字节注入与字符集欺骗

在GBK等宽字节编码环境下,攻击者利用“%df%27”这样的组合,让反斜杠转义失效。当PHP的addslashes函数在单引号前添加反斜杠(%5c)时,“%df%5c”恰好组成一个合法的GBK汉字“運”,单引号“%27”就逃逸出来了。WAF如果仅以UTF-8视角做正则匹配,根本看不到这个注入点。更隐蔽的是利用MySQL的字符集转换特性,通过“set names gbk”或“set character_set_client=gbk”改变会话字符集,配合“%bf%27”等高位字节组合实现注入。加固方案需要WAF在检测前明确当前会话的字符集,正则层面要关注“%[a-f0-9]{2}%[a-f0-9]{2}”这种连续编码组合,尤其是在GBK编码范围内(%81-%FE开头)的字节序列。

HTTP参数污染与分块传输

WAF通常对单个参数值做检测,攻击者利用参数污染将payload拆分到多个同名参数中。例如“?id=1&id=union&id=select”,后端语言如PHP取最后一个参数值,而WAF可能只检测第一个。更高级的是利用分块传输编码(chunked transfer encoding),将HTTP请求体拆成多个小块发送,每块中只包含payload的一部分,WAF如果等待完整请求体组装后再检测,性能开销巨大,很多WAF选择放行。加固这类攻击需要WAF在协议解析层面具备完整的参数拼接和分块重组能力,正则检测则要覆盖重组后的完整数据流,而非单块数据。

正则匹配加固的核心思路与示例规则

综合以上绕过手法,有效的正则加固不能停留在简单的关键字匹配,而需要构建多层次检测模型。第一层是协议解码层,完成URL解码、Unicode解码、Base64解码的递归展开;第二层是字符标准化层,将所有不可见空白字符、注释符号统一替换为标准空格;第三层才是语义检测层。以下是一组针对MySQL注入的加固正则示例:

# 检测内联注释中的可执行代码
\/\*![0-9]*[a-z]+.*\*\/

# 检测空白字符替代后的union select
union[\s%0a%0d%0b%0c%09\t]+(distinct|all)?[\s%0a%0d%0b%0c%09\t]+select

# 检测双重URL编码特征
%25[3-7][0-9a-fA-F]

# 检测宽字节注入特征
%[8-9a-fA-F][0-9a-fA-F]%[2-7][0-9a-fA-F]

# 检测benchmark延时替代
benchmark\s*\(\s*[0-9]{5,}

# 检测科学计数法绕过
\d+\.\s*(union|select|from|where)

这些规则需要配合WAF的上下文感知能力使用,例如在检测到“set names”或“character_set_client”语句时,自动启用宽字节检测模式;在检测到分块传输编码时,强制等待完整重组后再进入正则引擎。正则本身也要持续迭代,因为攻击者随时在挖掘新的变形手法。

从被动防御到主动对抗的思维转变

单纯堆砌正则规则永远追不上攻击者的变形速度。更有效的加固策略是在WAF中引入语法分析能力,将用户输入还原为SQL语法树,判断是否存在恶意的语义结构。例如无论“union select”如何变形、编码、加注释,最终在数据库解析器眼中都是一棵包含联合查询节点的语法树。正则匹配作为性能最优的过滤层仍然不可替代,但它应该定位为快速过滤明显攻击的第一道筛子,复杂变形交给语法分析引擎处理。同时,WAF的日志分析能力也需要加强,对每次拦截的payload做聚类分析,自动提取新的变形模式并生成建议的正则规则,形成检测能力的自进化闭环。

SQL注入绕过的本质是利用了WAF和数据库解析器之间的认知差异,加固的本质就是消除这种差异。理解数据库如何解析每一个字符、每一种编码、每一条注释,才能写出真正有效的正则规则。安全从业者需要持续跟进数据库厂商的更新日志,因为新的语法特性往往意味着新的绕过可能。