高级SQL注入拦截依赖三件事:SecRequestBodyAccess On必开、t:urlDecodeUni和t:lowercase必加、CRS初始化规则必须在SQLI规则前加载,缺一不可,否则连admin' OR '1'='1等基础POST攻击都无法检测。

直接上结论:高级 SQL 注入拦截不靠堆正则,靠三件事——SecRequestBodyAccess On 必开、t:urlDecodeUni,t:lowercase 必加、CRS 初始化规则(REQUEST-901-INITIALIZATION.conf)必须在 SQLI 规则前加载。缺一不可,否则连 admin' OR '1'='1 这种基础 POST 攻击都检测不到。
为什么 SecRequestBodyAccess On 是第一道生死线
ModSecurity 默认只解析 URL 参数(ARGS),对 POST 请求体(比如登录表单、JSON API)完全不读——规则再强也形同虚设。
- 现象:攻击者用
POST /login提交username=admin'--&password=123,日志里查不到匹配记录,SecRule ARGS完全不触发 - 必须加:
SecRequestBodyAccess On(Nginx)或SecRequestBodyAccess On(Apache) - 额外注意:若请求体超大(如上传 JSON 超 1MB),需同步调大
SecRequestBodyLimit和SecRequestBodyNoFilesLimit,否则直接被截断丢弃,规则根本没机会运行
怎么让 @rx 规则真正“看得清”变形载荷
真实攻击几乎从不裸写 union select,而是用 URL 编码、大小写混用、空格替换成 %09 或换行符等手法绕过。硬写正则只会误杀+漏报。
- 解码必须显式调用:
t:urlDecodeUni处理%27union%20select,t:lowercase统一UnIoN SeLeCt - 空白符不能只写
\s:要匹配[[:space:]]+或\s+,覆盖%09(Tab)、%0A(LF)、%0D%0A(CRLF) - 注释符要前置捕获:攻击常写
id=1%23%0Aunion select,规则中得用(?:--|%23|/\*)[[:space:]]*开头,再接关键字 - 示例(补漏用,非替代 CRS):
SecRule ARGS "@rx (?:--|%23|/\*)[[:space:]]*(?:union|select|insert|delete|update)" "id:1002,phase:2,block,msg:'SQLi: Comment-prefixed keyword',t:urlDecodeUni,t:lowercase"
CRS 的 REQUEST-942-APPLICATION-ATTACK-SQLI.conf 怎么不白装
很多人启用了 CRS 却仍被绕过,问题往往出在加载顺序和变量初始化上——REQUEST_COOKIES、ARGS 这些变量在初始化规则跑完前全是空的。
- 检查 CRS 版本:v3.3+ 才有较完整的 LibInjection 集成;v4.x 推荐启用
crs-setup.conf中的SecAction "id:900100,phase:1,pass,nolog,initcol:ip=%{REMOTE_ADDR},initcol:user=%{REMOTE_ADDR}" - 加载顺序铁律:Nginx 中
modsecurity_rules_file加载的文件,必须先 includeREQUEST-901-INITIALIZATION.conf,再 includeREQUEST-942-APPLICATION-ATTACK-SQLI.conf - 别跳过评分机制:CRS 默认用
setvar:tx.anomaly_score=+%{tx.error_anomaly_score}累计得分,tx.inbound_anomaly_score_threshold控制拦截阈值。直接deny会误伤,建议先log,tag:'OWASP_CRS'观察一周再切block
上线前必须验证的三个真实场景
规则写完不等于生效。很多团队卡在“看似拦截了,其实只拦住了 20% 的变体”。重点验这三类:
-
POST /api/order?ref_id=123带 JSON body:{"customer_name":"test' OR '1'='1--"}—— 检查SecRequestBodyAccess和JSON解析是否开启(SecRule REQUEST_HEADERS:Content-Type "@contains application/json"后需t:jsonDecode) - URL 中含
%2527(双重编码的'):/search?q=test%2527%20or%201%3D1—— 验证t:urlDecodeUni是否递归解码(默认只解一层,需叠加t:urlDecodeUni,t:urlDecodeUni) - 业务参数含合法关键词:如论坛帖子标题为
MySQL UNION SELECT 教程—— 确保规则作用域精确到高风险参数(ARGS:search_query),而非全局ARGS
最易被忽略的是:LibInjection 检测(942100 等规则)依赖 libinjection C 库编译支持,静态编译的 Nginx 模块若没带该库,这部分规则实际无效——得看 nginx -V 2>&1 | grep -i libinjection 确认。

















