nginx正则拦截sql注入效果有限,因其仅能匹配uri和参数中的显式攻击特征(如union select、1=1),无法解析sql语义、处理post body、防御编码绕过或盲注,仅可作外层粗筛,不能替代waf或应用层防护。

为什么直接用Nginx正则拦截SQL注入效果有限
因为Nginx的ngx_http_rewrite_module只在请求路径、参数名/值(需配合$args或$request_uri)上做字符串匹配,无法解析SQL语义,也看不到POST body里的payload。所谓“拦截SQL注入”,实际只是拦住常见攻击特征串,比如union select、1=1、or 1这类明显模式——它防不住编码绕过、大小写混淆、注释符分隔等变体,更防不住逻辑型或盲注。
真实生产环境里,靠Nginx正则只能作为最外层的“粗筛”,不能替代WAF或应用层输入校验。
哪些变量能用于匹配SQL注入关键词
必须明确:Nginx默认不解析请求体,所以$request_body在rewrite或if中不可用(除非启用lua-resty-waf或用nginx-module-vts等扩展)。能安全、稳定使用的只有:
-
$request_uri:完整URI(含path+query),适合匹配URL中明文出现的select%20from、exec%20xp_等 -
$args:仅query string部分(不含?),适合检查参数值是否含' or '1'='1 -
$uri:仅path部分,对路径遍历类攻击有用,但对SQL注入价值低
注意:if ($args ~* "union[[:space:]]+select")这种写法在高并发下有性能隐患,且Nginx官方不建议在location外大量用if。
实用且不过度误杀的正则写法示例
以下规则放在server或location块内,用return 403或deny all终止请求:
if ($request_uri ~* "(?:union\s+select|insert\s+into|drop\s+table|exec\s+xp_|sleep\(\d+\)|benchmark\()") {
return 403;
}
if ($args ~* "(?:'\s*(?:or|and)\s*'\d+\s*=\s*'\d+|--|\b(?:union|select|insert|update|delete|drop|create|alter)\b)") {
return 403;
}
关键点:
- 用
(?:...)非捕获组减少开销 -
\s+代替空格,兼容制表符、换行等空白 -
\b确保匹配完整单词,避免误杀user_id里的id - 避免写
select.*from——太宽泛,容易误伤正常接口如/api/select_user - 不要试图匹配所有编码形式(如
%20、+、%u0020),Nginx默认不解码$request_uri,但$args是解码后的,所以两处正则逻辑要分开设计
绕过方式和必须规避的坑
这些看似“加固”的写法,反而会暴露更多问题:
- 用
if ($request_uri ~* "union") { ... }:小写UNION或UnIoN就绕过,加i标志又易误杀(如username) - 匹配
1=1:正常业务参数如?status=1&active=1全被干掉 - 在
http块里全局写if:会导致所有server继承,连静态资源都受影响 - 依赖
$request_body却没配client_max_body_size和proxy_buffering off:body被截断或缓存后根本匹配不到
真正该投入精力的地方,是让应用层对所有用户输入做参数化查询,并在日志里记录触发规则的原始$request_uri和$args,用于持续优化规则——而不是指望一条正则挡住所有攻击。











