新型SQL注入绕过手段的核心变化在于,攻击者不再直接拼接明显的SQL关键字或引号,而是利用数据库特性、编码差异和WAF规则盲区,把恶意载荷伪装成正常参数。比如利用JSON语法、HTTP参数污染、分块传输、字符集转换等方式,让防护设备看到的内容与数据库最终解析的内容不一致。要破解这类绕过,不能只依赖正则匹配或黑名单,必须从输入标准化、语义分析和数据库行为三个层面同时设防。
一、先理解新型绕过为什么能生效
传统SQL注入检测主要盯着单引号、union select、sleep、benchmark等特征。但新型绕过手段把攻击拆散、编码或变形,使单个请求中不出现完整特征。常见思路包括:利用数据库对字符串的隐式转换,比如MySQL会把十六进制0x61646D696E当作admin处理;利用注释符//插入关键字中间,比如un//ion sel//ect;利用URL编码、双重编码或Unicode同形字绕过关键字过滤;利用HTTP请求体中的JSON字段,因为很多WAF对JSON结构的递归解析不完整,只检查了外层字符串;利用分块传输编码把payload切分到不同块中,使WAF无法拼出完整攻击语句。
更隐蔽的一类是利用数据库方言差异。例如PostgreSQL支持美元符号引用的字符串,攻击者可以用$tag$内容$tag$替代单引号,很多WAF不认识这种语法。SQL Server支持方括号标识符,Oracle支持q'[内容]'引用,这些方言特性都能让基于MySQL规则的WAF失效。攻击者还会利用参数污染,同时提交多个同名参数,WAF检查第一个,而后端框架或数据库拼接时使用最后一个或合并所有值,造成检查与执行不一致。
二、识别新型绕过攻击的典型特征
在实际流量中,新型SQL注入绕过往往伴随以下信号:请求参数中出现大量编码字符,如%2527、%u0027、%bf%27等;Content-Type在短时间内频繁切换,尤其是application/json、multipart/form-data和分块传输交替出现;参数值中出现数据库注释符、十六进制串、科学计数法数字、JSON嵌套数组或对象;同一参数名重复出现且值不同;请求体长度异常但WAF未告警;响应时间在特定参数变化时出现稳定延迟,比如输入sleep函数变体后响应变慢。
要准确判断,不能只看单条请求,需要结合会话上下文。例如攻击者先发送一个正常查询探测字段数量,再发送带注释符的变形payload,最后发送时间盲注语句。单看每一步都可能无害,但串联起来就是完整攻击链。因此日志关联分析和基线行为建模比单纯特征匹配更有效。
三、防护破解方法一:输入标准化与规范化
第一道防线是在应用层或WAF层对输入做标准化。具体做法是:先对URL编码、Unicode编码、HTML实体编码进行递归解码,直到结果不再变化,同时限制最大解码次数防止编码炸弹;将字符集统一转换为UTF-8,并拒绝非法字节序列;对JSON、XML等结构化数据做完整递归解析,提取所有键值对,而不是只检查原始字符串;对分块传输的请求先重组完整body再检测;对同名参数按照后端实际处理逻辑合并或分别检测,最稳妥的做法是全部检测并拒绝存在多个同名参数且值不一致的请求。
标准化之后,再把参数值中的注释符、空白符、字符串连接符等做归一化处理。比如把//、--、#、/*! */等统一替换为空格,把十六进制、二进制、科学计数法数值统一转换为十进制字符串,把数据库方言引用符统一替换为单引号。这样可以让变形后的payload恢复成可识别的模式。
四、防护破解方法二:语义分析与语法树校验
单纯做字符串匹配永远追不上变形速度。更可靠的方式是对SQL语句做语法解析,生成抽象语法树,然后判断是否存在注入。具体实现上,可以在应用层使用预编译语句,从根源上消除SQL注入,这是最彻底的方法。对于无法改造的遗留系统,可以在WAF或数据库代理层部署SQL语法解析器,把请求中的参数代入SQL模板后做完整语法分析。
语法分析的重点是判断参数值是否改变了原SQL语句的结构。正常参数只会出现在字符串字面量或数值字面量位置,不会引入新的关键字、运算符、注释或子查询。如果解析后发现语法树中出现了参数值带来的SELECT、UNION、FROM、WHERE、AND、OR等节点,或者字符串字面量被提前闭合,就可以判定为注入。这种方法对编码绕过、注释绕过、方言绕过都有很好的检测效果,因为无论怎么变形,最终数据库解析出的语法结构一定包含恶意节点。
实际部署时,可以把SQL语法解析器集成到数据库访问层,对每一条拼接后的SQL做校验。对于ORM框架,可以开启其内置的SQL注入防护并定期更新规则。对于存储过程,要检查参数是否被动态拼接到EXEC或sp_executesql中。
五、防护破解方法三:数据库行为监控与响应分析
有些绕过手段连语法分析都难以发现,比如利用数据库函数副作用做时间盲注或报错注入,此时需要从数据库行为层面检测。具体做法包括:监控数据库慢查询日志,统计执行时间突增的SQL模板;分析数据库错误日志,查找包含敏感信息泄露的报错,如“You have an error in your SQL syntax”“ORA-01756”“Unclosed quotation mark”等;对数据库账号的权限做最小化,禁止应用账号访问系统表、执行xp_cmdshell、读写文件等;开启数据库审计,记录所有SQL语句及其来源IP、应用用户、执行时间。
时间盲注的检测可以结合响应时间基线。正常情况下,同一SQL模板的执行时间分布相对稳定,如果某个参数值导致执行时间显著偏离基线,且该参数值中包含sleep、pg_sleep、WAITFOR DELAY、benchmark等函数或变体,就应触发告警。报错注入的检测可以关注响应体中是否出现数据库错误信息片段,即使攻击者用注释符或编码隐藏了注入语句,数据库抛出的错误信息往往仍包含可识别的特征。
六、防护破解方法四:针对新型绕过手段的专项规则
针对前文提到的几类新型绕过,可以部署以下专项规则:
1. JSON注入绕过:对application/json请求体做递归解析,提取所有字符串值,对每个值执行与普通参数相同的SQL注入检测。同时检查JSON中的数字、布尔值、null是否被替换为字符串或对象,因为数据库驱动可能把它们转换为字符串后拼入SQL。
2. 分块传输绕过:在WAF或反向代理层强制重组分块请求,拒绝不完整或超长的分块序列。对于使用Transfer-Encoding: chunked且同时声明Content-Length的请求直接丢弃,因为正常客户端不会同时发送这两个头。
3. 参数污染绕过:检测请求中是否存在同名参数,如果存在且值不同,直接拒绝或合并后检测。对于后端框架可能只取第一个或最后一个参数的情况,要确保检测逻辑与后端一致,最安全的是对所有同名参数值都做检测。
4. 字符集绕过:限制请求字符集为UTF-8,拒绝包含非法UTF-8序列的请求。对于GBK、GB2312等宽字节注入,可以在应用层统一使用UTF-8编码并设置数据库连接字符集为UTF-8,避免宽字节转换。
5. 方言引用绕过:在检测规则中加入PostgreSQL的美元引用、Oracle的q引用、SQL Server的方括号标识符等模式。例如检测参数值中是否出现$[a-zA-Z0-9]*$或q'[或q"[等结构。
七、实战中的检测代码示例
下面给出一个Python示例,演示如何对参数值做标准化和基础检测,实际生产环境需要结合WAF或RASP部署:
import re
import urllib.parse
def normalize_input(value, max_depth=5):
"""递归解码并归一化常见绕过字符"""
if max_depth == 0:
return value
prev = None
current = value
while prev != current:
prev = current
# URL解码
current = urllib.parse.unquote(current, errors='ignore')
# 双重编码处理
if '%25' in current:
current = current.replace('%25', '%')
# 归一化注释符和空白符
current = re.sub(r'/\*.*?\*/', ' ', current, flags=re.S)
current = re.sub(r'--[^\n]*', ' ', current)
current = re.sub(r'#.*', ' ', current)
current = re.sub(r'\s+', ' ', current)
# 归一化十六进制和科学计数法
current = re.sub(r'0x[0-9a-fA-F]+', 'NUM', current)
current = re.sub(r'\b\d+\.?\d*[eE][+-]?\d+\b', 'NUM', current)
return current.strip()
def detect_sqli(value):
"""基于归一化后的值做语义特征检测"""
normalized = normalize_input(value)
patterns = [
r'\bunion\b.*\bselect\b',
r'\bselect\b.*\bfrom\b',
r'\binsert\b.*\binto\b',
r'\bupdate\b.*\bset\b',
r'\bdelete\b.*\bfrom\b',
r'\bdrop\b.*\btable\b',
r'\bexec\b.*\bxp_cmdshell\b',
r'\bsleep\s*\(',
r'\bbenchmark\s*\(',
r'\bwaitfor\s+delay\b',
r'\bpg_sleep\s*\(',
r"'\s*or\s+'1'='1",
r"'\s*and\s+'1'='1",
r'\$[a-zA-Z0-9]*\$.*\$[a-zA-Z0-9]*\$',
r"q'\[.*\]'",
]
for pattern in patterns:
if re.search(pattern, normalized, re.IGNORECASE):
return True
# 检测单引号闭合后出现SQL关键字
if "'" in normalized:
after_quote = normalized.split("'", 1)[1]
if re.search(r'\b(or|and|union|select|from|where)\b', after_quote, re.IGNORECASE):
return True
return False
# 示例测试
test_payloads = [
"1' union//select//password from users--",
"0x61646D696E",
"$tag$1' or '1'='1$tag$",
"1%2527%2520and%2520sleep(5)--",
"1' and (select count(*) from information_schema.tables)>0--",
]
for payload in test_payloads:
print(f"Payload: {payload}")
print(f"Detected: {detect_sqli(payload)}\n")
上述代码展示了标准化和检测的基本思路。实际生产环境中,还需要加入对JSON递归解析、同名参数处理、分块重组等逻辑,并且检测规则要持续更新。
八、纵深防御与持续改进
破解新型SQL注入绕过不能只靠单一技术。最有效的方案是纵深防御:应用层使用预编译语句和参数化查询,这是根除注入的首选;WAF层做输入标准化、语义分析和专项规则检测;数据库层开启审计、最小化权限、监控异常行为;同时建立安全基线,对应用日志和数据库日志做关联分析,及时发现攻击尝试。
此外,安全团队要持续跟踪数据库厂商的安全公告和社区公开的绕过技术,定期更新检测规则。可以搭建自己的测试环境,用公开的绕过payload库做回归测试,确保防护规则升级后不会漏报已知攻击。对于无法修复的遗留系统,考虑在数据库前端部署数据库防火墙或代理,对SQL语句做白名单校验,只允许符合业务逻辑的SQL模板执行。
最后要强调的是,任何基于黑名单的防护都会被新的绕过手段突破,只有结合输入标准化、语法分析、行为监控和最小权限,才能把SQL注入绕过风险降到最低。安全人员应当把重点放在理解数据库解析机制和攻击变形原理上,而不是单纯堆砌规则。
