-
Notifications
You must be signed in to change notification settings - Fork 282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ModSecurity False Positive with respect to logging in ModSec audit + NGX error logs due to NGINX behavior with error_page directive #182
Comments
Hmm actually looks like if we took this specific snippit: Then even executing the log phase logic of modsec would get avoided and save the incorrect logging. Didn't realize we could just take |
^ So following up on that test, seems to add that does indeed prevent the audit log from being written with the incorrect information. But ngx error output still receives the bad log saying we 403'ed but we really didn't since this was a tcp connection timeout on proxy and was sent to client as 504:
Which must actually be storing this message in an earlier phase prior to the error_page directive because the request method: POST is logged correctly in the Mod Sec message. What phase/code is executing printing this ^ message? It HAS to be after the error_page directive has messed things up, so maybe the rewrite or header filter phase? Still digging and testing to confirm! EDIT - Actually on re-evaluation doing this also prevents valid blocking tx's making it into the audit_log too. So can't use this technique alone as it just straight up prevents audit logs seemingly for us. |
Well honestly less to change if we just do it here, I see no major drawbacks, ModSecurity should really not intervene on error_page directive paths for internal redirects at all (http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page) :
Edit - this does not work either... |
Ugh, and then the above code stops the invalid ngx error logging BUT it also prevents me from getting valid audit logs too. The std out still has the valid error logs though. Still digging for what can be done to get the best of both worlds here. |
Yeah trying to do hacky checks around short circuiting with the
Reference: http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page @victorhora @defanator looking at past PR's you both have been playing with trying to make this Module more friendly with the |
Hi @jeremyjpj0916 , Re:
One option is to simply turn off ModSecurity for the error page. E.g.
|
@martinhsv That may work, but lets say that mod security itself is going to block a tx upon request and sets a 400/403 response and error_page is set to handle 400's as well. Will we then also just lose the tx error and or audit log entry for 400 response blocked transactions all together? I will run a quick test to confirm(I fear we lose either the audit and/or error log record) but it is a good idea I hadn't thought of. |
@martinhsv Took a nap but got around to testing your idea there. Yep the behavior seen when attempting such a suggestion is the error log does still work on a blocked HTTPStatus 400 tx, but audit logs on the transaction are missing(which is vital for our debugging purposes in our use case), which means that audit logging is taking place in the nginx log phase running after the error_page directive internal redirection has occurred. My test to prove it out was a simple invalid JSON payload that would not parse properly. |
Hi @jeremyjpj0916 , Ah, yes, I guess you're probably hitting owasp-modsecurity/ModSecurity#2237 . A couple of other options that might be useful as workarounds leave modsecurity on in the error location, but remove the rules causing the false positive (I tried these with the most recent ModSecurity-nginx in github)
In this case you may get the audit log output, as well as a double report in nginx's error.log. (Note that there are some nuances, for example, this presupposes that the original detection was, in fact, not against 920170.) A second option could be to disable rules more broadly:
With this option you would only get the single report in error.log. You would also get some output in audit_log, but it looks like the 'messages' section (i.e. section 'H') is empty. This might be acceptable if one is ok with having audit_log output as a cue to cross-reference against the content in error.log I realize neither of these options are ideal, but I thought I'd mention them as possible workarounds, if they happen to be useful for your needs. As yet another alternative, you could consider attempting strategy similar to one recently posted by @theseion here: #152 |
@martinhsv Yeah had not given that too much thought but I could remove rule by id for example on the rule triggered by seeing GET with HTTP Body in the error log which would remove most of the noisy the false positives because error_log always sets method to GET, but then you also would be losing the valid blocked audit logs for folks who actually used GET but sent a HTTP Body payload too (some API clients make these mistakes heh). So its kinda a two way street with no easy workaround that actually prevents losing legitimate logs and stopping the noise. The fix I think still is simply prior to error_page redirect preserving the original request HTTP Method and request URI detected(hopefully mod security can save this in the tx context somehow during the access phase) and then we just in this connector do something like:
As mentioned in earlier post above. |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days |
Still relevant. |
The "nostale" tag has been set for this one too @jeremyjpj0916. We'll get to it when possible. Thank you. |
Hi, I think I found one more way that might help. It is to use a named location for the error page instead of a URL, like so:
Then NGINX won't change the request method to GET and full audit log will appear with correct messages in part H.
EDIT: I just noticed the reference to #152 (comment) which seems to use the same solution (although in a little more complicated way) |
@hator So to talk to your specific idea could we use this one for example? https://github.com/Kong/kong/blob/master/kong/templates/nginx_kong.lua Where I just replace here: with
And then replace: https://github.com/Kong/kong/blob/master/kong/templates/nginx_kong.lua#L234
And that will keep NGINX from resetting the HTTP Methods and such that comes with error_page redirection woes? If so that is awesome and I am glad we got a fix in mind here. Kong the app I use itself wrote some logic that helped workaround these issues but it still was hitting me with ModSecurity. If so I think no fix needed since its really an nginx behavior issue, but it would be good if we could document this somewhere outside of this issue, just not sure where in ModSecurity it should live. |
@jeremyjpj0916 Using a named location for 400 error page has an unfortunate effect that it will not work, when handling an invalid HTTP method. It will display a stock NGINX error page with 500 error. This is due no method being set by the request (because it is invalid) and by the error page -- the same reason why it solves this problem with modsecurity. You can try that yourself by doing The configuration I use has two locations for error handling:
I haven't yet figured out why I have to disable modsecurity in when handling 400, but it would cause the same problem as using a named location, i.e. 500 and stock error page, even when no rules are blocking the request. Sorry for the offtopic, this discussion should probably move elsewhere :) |
Okay, so 400 HTTPStatus is problematic still, but your solution should help for 403's and 504's my Kong instance treats as a connection/read timeout's going into the error_page redirect causing some audit logging false positives. Appreciate the insight. EDIT - Had to re-evaluate the named locations for |
Okay starting from the top again I recognize the issue is So the solution to our problem is how do we store and persist the original client HTTP Method Header that was sent? I was chatting with @airween on this problem and he had a smart observation that in the rewrite phase: http://www.nginxguts.com/phases/ , which comes prior to proxying and error_page redirection that we could grab the original method, as its set here: https://github.com/SpiderLabs/ModSecurity-nginx/blob/master/src/ngx_http_modsecurity_rewrite.c#L145 Now I am willing to bet that when internal redirection via
cc @victorhora @martinhsv @zimmerle ? Wish I was more familiar with building ngx modules in C as this seems a simple task yet I don't see how to set and persist something to access it later easily in sample codes I am browsing. Added a stack overflow post too to see if open source community there runs into any ideas: |
Wallarm CEO Ivan made the comments:
|
I think I had an epiphany on this today in my ponderings since is the last step in getting ModSecurity Nginx "productionalized" for us. Rather than write the above code options. ^ I think we can look at this past PR change around relevant stuff, This was good to get log phase still actively doing its thing even during an error_page redirect, I think the mistake with this PR was deciding to allow the request "phases" to re-process data, I think the state prior to this PR merge was good logic, the log phase was all that really needed edited. Testing this theory now, I imagine modsec tx context maintains the request data seen befroe the |
Added my own PR as the solution to my stack overflow too: https://stackoverflow.com/questions/61805876/nginx-module-code-error-page-directive-problems/61950152#61950152 |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days |
Stahp closing thingsssssss |
Given the 'nostale' tag, this item should not have been closed by the bot. |
indeed, yalls bot is misbehaving. |
@jeremyjpj0916 thanks for digging into this! I was trying to compose a minimal test for nginx connector to demonstrate the issue without having entire CRS ruleset included and enabled, and I'm still having troubles to do that. I was also checking another issue (#90) and noticed that in current connector code there may be scenarios when audit log entries do not appear (while they definitely should) if Could you please assist in making a minimal reproducible configuration that demonstrates an issue reported here and addressed in #204? TIA! |
@jeremyjpj0916 could you please check that 4f26b48 resolves at least some of the issues you've been observing? TIA. |
If I get some time I will take a look but no promises as my current gig keeps me busy, been over a year since I was messing with this stuff and have long had workarounds I probably won't be touching again, as this modsecurity tooling in nginx ended up not being performant enough to realistically serve large volumes of traffic so we isolated it to a really small use case we don't spend much time on nowadays. |
Nginx handles `error_page` via `ngx_http_internal_redirect`, and audit log in `ModSecurity-nginx` is trigged in the next handler. In nginx's code, it's harded to `GET` for non-`HEAD`, refers https://github.com/nginx/nginx/blob/master/src/http/ngx_http_special_response.c#L618-L621: ```c if (r->method != NGX_HTTP_HEAD) { r->method = NGX_HTTP_GET; r->method_name = ngx_http_core_get_method; } ``` This patch use `method_name` from `request_line` to fix this issue. This should fix method name in owasp-modsecurity#182, and solve owasp-modsecurity#258.
Nginx handles `error_page` via `ngx_http_internal_redirect`, and audit log in `ModSecurity-nginx` is trigged in the next handler. In nginx's code, it's harded to `GET` for non-`HEAD`, refers https://github.com/nginx/nginx/blob/master/src/http/ngx_http_special_response.c#L618-L621: ```c if (r->method != NGX_HTTP_HEAD) { r->method = NGX_HTTP_GET; r->method_name = ngx_http_core_get_method; } ``` This patch use `method_name` from `request_line` to fix this issue. This should fix method name in owasp-modsecurity#182, and solve owasp-modsecurity#258.
Decided to pull out my comment to a separate issue since its unrelated to the other issue I raised originally:
I was trying to limit the relevant to 400's and 403's for capturing blocked transactions by ModSecurity:
SecAuditLogRelevantStatus "^(?:4((00)|(03)))"
Yet I see the audit log in RelevantOnly mode still also capturing 504 status messages as well for some reason.
SO this one is an interesting case. I am 100% sure on why 504's were making it into the audit logs even through its regex was set to 400's and 403's because I saw odd behavior in other apps too that hook into NGX with logged values not matching what the client really sent.
Firstly take a gander here(the app we run on nginx + openresty), leveraging the error_page directive:
https://github.com/Kong/kong/blob/3.7.0/kong/templates/nginx_kong.lua#L94
Then take a gander here at how Kong or OpenResty can be patched for such situations:
Kong/kong#5073
openresty/openresty#396
So what happens is when NGINX does an internal redirect via error_page, and the CTX of the client HTTP METHOD gets reset to GET always, so the NGINX ModSec audit/error logs are thinking REAL 504 timeout transactions are now a GET with a HTTP body(client sends req body) in the audit log logic(The Method the client actually used in the originating request was a POST), so it saves an blocked error log w 403 in the audit log file section H, for the transaction BUT the real transaction was a 504 and it was presented to the client as a 504, just internal logging and record keeping Modsecurity-nginx is not handling these scenarios where error_page directive gets used by folks leveraging the NGINX web server.
The fix could easily be if yall added a custom mod security http method variable to the tx context in the pre-access phase taking the original
r->method
to track the Method before the error_page directive internal redirect and read that custom mod sec http method variable after in the audit/error log phase logic after the redirect has occurred as the source of truth rather than the current ngx contextsr->method
(which would be reset to always be GET at that time). Will save on the noisy invalid logs.Ex of current behavior(Upstream times out in reverse proxy call, we hit error_page directive, http method gets reset to GET internally, triggering ModSec to log this tx as a block in error + audit log incorrectly when it was really just a harmless timeout):
ModSecurity-nginx: latest master branch
The text was updated successfully, but these errors were encountered: