owasp-modsecurity / ModSecurity-nginx

ModSecurity v3 Nginx Connector
Apache License 2.0
1.48k stars 274 forks source link

'Host' header missing when HTTP3 is in use prevents "SecRule REQUEST_HEADERS:Host" rules from being effective. #305

Closed jsoranzo closed 1 year ago

jsoranzo commented 1 year ago

Hello Team and thanks for your work on the modsec connector for Nginx. We built nginx with modsec and the modsec connector using the official 'nginx-quic' branch for implementing HTTP3. We use nginx primarily as a global reverse proxy server for our web infrastructure, providing SSL/TLS encryption for our web apps as well as threats protection thanks to modsec. Everything is working fine apart from several rules we implemented which at the time seemed ineffective, for some unknown reasons. After some debugging (by enabling modsec's audit logs), it appears that the 'Host' header is missing when the clients request via HTTP3 (that header is not present in modsec's audit logs). That would explain our issue: since that header is unavailable to modsec, all rules like "SecRule REQUEST_HEADERS:Host" are ineffective when clients connect via HTTP3. We then checked with both HTTP1.1/2: the Host header is present in the audit logs, and our rules are applied successfully as they should. We tried to find a workaround by using the 'headers-more' module from openresty and applying custom inbound headers. However it seems like modsec's processing is done prior to our custom headers being injected, which makes such workaround hopeless. Not quite sure what to do next. It's also possible that the Host header not being present is an HTTP3 specification, possibly. It is to note that rules using REQUEST_URI are working normally via all protocols, including HTTP3. Any possible to suggest? Is anybody else experiencing the same? Thanks in advance for your help!

jwpemail commented 1 year ago

I had to disable 2 rules to get HTTP/3 working:

2023-05-25 disable HTTP/2 check (which affects quic and HTTP/3)

SecRuleRemoveById 920180

"Request Missing a Host Header"

SecRuleRemoveById 920280

martinhsv commented 1 year ago

Hello @jsoranzo ,

Your inquiry seems to be mostly focussed on particular rules you are using with ModSecurity. Questions and issues related to the engine itself (at the repo https://github.com/SpiderLabs/ModSecurity ) or the nginx connector (this repo) can be directed to to these locations but questions about particular rules are usually best addressed to the ruleset publishers.

However, I will make a couple of observations that may help:

First note that it is entirely normal in most deployments to have to exclude certain rules or write exceptions, no matter what ruleset one is using -- and that is particularly true for generic rulesets. Such rules generally try to identify suspicious content but often have some level of possibility of false positives.

Regarding the Host: header, for example, it is required in HTTP 1.1, therefore its absence may be a source of suspicion. However, that same requirement may not be in place for HTTP3.

In other words, modifying a request to add an extra header merely to have your rules work is likely not the best approach. Instead, if the absence of a Host: header is expected, you should feel free to disable the relevant rules either:

jsoranzo commented 1 year ago

Thank you for your comments. A precision: we're using the OWASP core rule set. Just as @jpopovitch, we had to disable a couple rules for HTTP3 to work properly with the set: 920180 and 920280. We also adjusted rule 900230 to allow the HTTP/3 protocol.

Now from our perspective, the main problem with not having that Host header present with HTTP3 clients is when we want to disable or adjust specific rules for specific domains. Our Nginx proxy servers serve many applications over multiple domains. The idea is to keep as many core rules enabled as possible (in order to provide the highest level of protection possible), and only disable the ones impacting our web apps' normal operations (false positives). Using the Host header allows us to easily set which rules we want to modify/disable and for which domain. I guess we'll have to adapt to that header's non-presence with HTTP/3, and find other ways to adjust rules, such as using REQUEST_URI instead as previously mentioned.