-
Notifications
You must be signed in to change notification settings - Fork 1.7k
ModSecurity fails to parse request body with special characters when using JSON requestBodyProcessor #1879
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
Comments
@msamad I've managed to get this working fine by copying and pasting the request into Burp Suite like so: The audit logs says:
And debug logs suggests the JSON was parsed successfully:
I think it might be something to with the way the cURL is sending the content on the wire. If I simply add single quotes (') to the "--data" parameter like this: curl --request POST The request also went by the JSON parser just fine. |
thanks @victorhora for looking into this. Nginx seems to be doing the similar thing i.e. taking care of escaping - at least during the access log.
It will be nice if ModSecurity takes care of it when parsing. Your views? Thanks. |
@msamad, Afaik, the library that ModSecurity uses for parsing JSON (YAJL) should attempt to escape control chars such as \r which would explain why it gets parsed correctly when sending the request properly using HTTP clients. You can also test how YAJL parses data by using the json_verify tool that comes with YAJL
I've triggered the requests again using cURL without quotes (') to the "--data" parameter and the bytes on the wire (PCAP) shows that this leads to the JSON data being sent without double quotes (") around the values: While using cURL with quotes (') to the "--data" parameter leads to the JSON having double quotes (") around the values as per JSON standard (RFC-8259#section-7: Note also how the HTTP dissector of Wireshark is also able to correctly parse the data from packet. That being said, I believe that the behaviour of ModSecurity and YAJL is correct and no extra escaping is needed at least when using cURL to reproduce this. Maybe your Java client/library is not wrapping the values in double quotes for some reason? You may try a using a similar approach to confirm. |
Thanks @victorhora |
Hi @victorhora, So I sent the request using a java client to ModSecurity (Nginx) and got back a 400 as ModSecurity failed to parse the request body. WireShark though sees it as a proper JSON object, image below. I enabled request body logging in nginx access log Below is what I noticed when I tried calling the same using curl and java client. curl - using the single quote - the request passes without any issue
This is what I get in nginx access and modsecurity logs.
As this request passes, I purposely added
Now, without using the single quote - this gets rejected of course.
I get this in nginx access and modsecurity logs.
The above is bad because double quotes have been removed and even WireShark doesn't recognize it as valid json. Now when I make the call using Java client. I get this in nginx access and modsecurity logs.
The request gets rejected by modsecurity with failed to parse request body error but WireShark is able to recognize it as valid json. Notice that double quotes have not been removed and also no extra escape I verified the curl (using single quote) result and java result using
if |
Also tried it with Python script and got 400 because modsecurity failed to parse request body. Script:
I get this in nginx access and modsecurity logs.
This is same as what I get for java client. |
Hi @msamad I believe that the problem here is that some of the clients that generate the requests are actually interpreting the \r\n characters and instead of sending the \r\n characters in their "raw" ASCII format (0x5c 0x72 0x5c 0x6e), they are instead sending the \r\n as their actual control characters sequence (0x0d 0x0a). If you pay attention to the Wireshark capture compared to yours you can notice the differences clearly: In the same fashion, I've checked that the Python script example you posted also interprets the \r\n and send the newline bytes in the request with 0x0d 0x0a (probably due to the way Python or the Requests HTTP library interpret this and hence why it triggers the rule. "A string is a sequence of Unicode code points wrapped with quotation marks This leads me to believe that the JSON standard, prohibit control characters (0x0d 0x0a) directly on the JSON key or value fields. It seems to be the case with the json_verify tool: The content invalid.json file being like so:
Note: cat invoked with -A to show non printable characters (0x0d 0x0a) Hence why requests that get sent to ModSecurity and that are handed over to the JSON library (YAJL) for processing that contains these characters will always result in an error. Now, if you could somehow tell your client application to not process/ignore the \r\n and send the string as is, ModSecurity/YAJL should be able to process it properly. Alternatively, you could try adding an extra scape ("\"). If I try this with the Python script you've provided it works fine: And this is what ModSecurity says: debug_log:
audit_log:
|
Hi @victorhora, Escaping the The following python script results in ASCII sequence instead of control character sequence.
I needed to escape the json escape sequence for client's language/platform - feel dumb for not doing that but good to know the details. Some good explanation on stackflow
|
One more thing to mention that the following python script will be successful without escaping
Notice the |
Hi,
ModSecurity (v3.0.2) fails the JSON requestBodyProcessor for a request when there are special characters such as '\r', '\n' etc in the body.
e.g. Following request results in 400 Bad Request where rule 200002 fails.
ModSecurity transaction log
Nginx access log escapes the request body properly.
It seems that ModSecurity is not escaping the '\r', \n' etc which results in a failure when parsing into a JSON object.
Thanks.
The text was updated successfully, but these errors were encountered: