Ingress NGINX ModSecurity允许text/plain规则不生效问题排查
背景
在Ingress-NGINX控制器中通过注解启用ModSecurity,集成OWASP核心规则集(OWASP-Core-Ruleset),其他自定义规则都正常运行,但添加的允许text/plain类型请求的规则始终不生效。试过调整规则空格、执行阶段等写法,都没解决问题。
相关配置
启用ModSecurity的Ingress注解
enable-modsecurity: "true" modsecurity-snippet: | Include /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf
尝试过的自定义规则写法
- 初始写法:
SecAction "id:900220, phase:1, pass, t:none, nolog, \ setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded|multipart/form-data|multipart/related|text/xml|application/xml|application/soap+xml|application/json|application/cloudevents+json|application/cloudevents-batch+json|text/plain|'"
- 加空格分隔:
SecAction "id:900220, phase:1, pass, t:none, nolog, \ setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded| |multipart/form-data| |multipart/related| |text/xml| |application/xml| |application/soap+xml| |application/json| |application/cloudevents+json| |application/cloudevents-batch+json| |text/plain|'"
- 去空格+调阶段:
SecAction "id:900220,phase:1,pass,t:none,nolog,setvar:'tx.allowed_request_content_type=|application/x-www-form-urlencoded|multipart/form-data|multipart/related|text/xml|application/xml|application/soap+xml|application/json|application/cloudevents+json|application/cloudevents-batch+json|text/plain|'"
排查与解决方法
1. 确认规则加载顺序
OWASP CRS的默认配置里大概率已经定义过tx.allowed_request_content_type,如果你的自定义规则加载在CRS规则之前,设置的变量会被CRS覆盖。
检查/etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf,看是否先包含了CRS核心规则(比如crs-setup.conf、REQUEST-*规则文件),再加载你的自定义规则。Ingress-NGINX的modsecurity-snippet是追加在ModSecurity配置末尾的,但如果nginx-modsecurity.conf里最后又重置了变量,也会覆盖你的设置。
解决思路:改用追加变量的写法,不要直接覆盖:
SecAction "id:900220, phase:1, pass, t:none, nolog, setvar:'tx.allowed_request_content_type=%{tx.allowed_request_content_type}|text/plain|'"
这样既保留CRS默认允许的类型,又追加了text/plain,避免被覆盖。
2. 开启调试日志看变量实际值
直接查看ModSecurity的调试日志,确认tx.allowed_request_content_type最终有没有包含text/plain:
在modsecurity-snippet里添加日志配置:
SecDebugLog /var/log/nginx/modsec_debug.log SecDebugLogLevel 9
发送一个text/plain类型的请求,然后搜索日志中的tx.allowed_request_content_type,看实际值是什么。如果没找到|text/plain|,说明规则没生效或者被覆盖了。
3. 检查CRS的拦截规则
OWASP CRS里的REQUEST-920-PROTOCOL-ENFORCEMENT.conf中,规则920420负责检查内容类型是否在允许列表里。注意这个规则会把Content-Type里的参数(比如text/plain; charset=utf-8)截断成text/plain再匹配,所以如果请求带参数,是能匹配的,但如果有其他规则(比如920380)拦截了text/plain,即使允许列表加了也没用。
可以临时禁用920420规则测试:
SecRuleRemoveById 920420
如果请求能正常通过,说明是这个规则的问题,再回头调整允许列表配置。
4. 确认ModSecurity版本兼容性
不同版本的ModSecurity对语法要求可能有差异,比如某些版本对引号、空格的处理更严格。检查Ingress-NGINX使用的ModSecurity版本(可以通过nginx -V或者查看镜像标签),确保规则语法符合对应版本要求。
最可能的原因
- 自定义规则加载顺序在CRS之前,变量被CRS默认配置覆盖;
- 直接覆盖了
tx.allowed_request_content_type,而不是追加,导致后续被CRS规则重置; - 未开启调试日志,无法直观看到变量实际值,难以定位问题。
内容的提问来源于stack exchange,提问作者Daniel

