modsecurity在nginx上防御sql注入需满足三大前提:模块已编译加载(nginx -v含modsecurity)、secrequestbodyaccess on启用、后端透传原始请求体(fastcgi_pass_request_body或proxy_pass_request_body开启),缺一即导致request-942规则失效。

ModSecurity 在 Nginx 上不是“装上就能防 SQL 注入”的插件,它必须满足三个硬性前提:模块已编译进 nginx、SecRequestBodyAccess On 已启用、后端能收到原始请求体。缺一不可,否则所有 SQLI 规则(如 REQUEST-942-APPLICATION-ATTACK-SQLI.conf)形同虚设。
确认 nginx 真正加载了 ModSecurity 模块
很多配置失败的根源是模块根本没加载——nginx -V 输出里压根没有 modsecurity 字样。
- 执行
nginx -V 2>&1 | grep -o modsecurity,必须有非空输出(例如--add-dynamic-module=../nginx-modsecurity) - 若无输出,Debian/Ubuntu 用户可直接安装
nginx-mod-http-modsecurity包;CentOS/RHEL 用户基本需源码编译libmodsecurity+nginx-modsecurity - 验证动态链接是否生效:
ldd $(which nginx) | grep modsecurity,无输出说明模块未真正载入 -
load_module路径必须绝对准确,比如modules/ngx_http_modsecurity_module.so,错一个字符就报unknown directive "SecRule"
启用请求体解析与透传
OWASP CRS 的 SQLI 规则默认检查 ARGS 和 REQUEST_BODY,但 Nginx 默认不读取、也不转发 POST body,导致规则永远匹配不到攻击载荷。
Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
- 在
modsecurity.conf中必须显式写:SecRequestBodyAccess On - 若后端是 PHP-FPM,在
location块中加:fastcgi_pass_request_body on;;若用 proxy_pass,则加:proxy_pass_request_body on; - 漏掉其中任一配置,
ARGS变量为空,REQUEST-942-*.conf对 POST 类 SQL 注入完全失效 - 对
multipart/form-data请求,Nginx connector 解析不完整,建议加兜底规则:SecRule REQUEST_BODY "@rx (?i)(union\s+select|select\s+.*\s+from)" "id:1002,phase:2,deny,status:403,msg:'Raw SQLi in body'"
开启规则引擎并确保阻断动作生效
CRS 规则默认只记录不拦截,SecRuleEngine 必须设为 On,且规则末尾必须带 deny,status:403 或类似动作,否则只是“看戏”。
-
SecRuleEngine On必须写在server或location块内,不能只放在http{}顶层 - 检查 CRS 规则文件中是否含
deny,status:403,例如REQUEST-942-APPLICATION-ATTACK-SQLI.conf里的id:942100规则 - 绕过常见:攻击者用
sel%65ct、UNI/**/ON SEL/**/ECT等变形,需在规则中明确启用转换链,如t:urlDecodeUni,t:lowercase - 避免单点依赖:CRS 使用累加式异常分值(
TX:ANOMALY_SCORE),要确认SecResponseBodyAccess On和相关拦截阈值已配置
别忽略 multipart 请求和二次解码链路断裂
文件上传类接口(Content-Type: multipart/form-data)是 SQL 注入高危盲区,Nginx 的 ModSecurity connector 对这部分解析支持薄弱,且 URL 二次解码环节容易丢失。
-
ARGS_NAMES和ARGS在 multipart 场景下可能完全不触发,仅靠REQUEST_BODY匹配更可靠 - 双 URL 编码(如
%2527)在 Nginx → ModSecurity → CRS 链路中常被提前解码一次就终止,t:urlDecodeUni必须显式声明才能补全二次解码 - LibInjection Check(如
id:942100)虽高效,但无法覆盖所有语法变体,仍需正则兜底 + 异常分值机制协同
最易被跳过的其实是 fastcgi_pass_request_body on 和 SecRequestBodyAccess On 这两行——它们不报错、不警告,但会让整个 SQLI 防御静默失效。上线前务必用 curl -X POST -d "id=1' union select 1,2--" 实测响应状态码是否为 403。










