owasp-modsecurity / ModSecurity-nginx

ModSecurity v3 Nginx Connector
Apache License 2.0
1.56k stars 281 forks source link

Server Block and Http block modsecurity rule preference #211

Closed muradmomani closed 4 years ago

muradmomani commented 4 years ago

Hi,

I have the following section in my ngixn.conf

http {
...
...
...
modsecurity on;

    modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;

    modsecurity_rules '
    SecRuleEngine On
    SecRequestBodyLimit 13107200  
    SecRequestBodyLimitAction ProcessPartial 
    SecAction "id:900000,phase:1,nolog,pass,t:none,setvar:tx.paranoia_level=4"
    SecAction "id:900110,phase:3,pass,nolog,setvar:tx.inbound_anomaly_score_threshold=2,setvar:tx.outbound_anomaly_score_threshold=5"
SecAction "log,id:10002,phase:3,msg:"Paranoia_Level %{tx.paranoia_level} Anomalyinbound %{tx.inbound_anomaly_score_threshold} Abomalyoutbound %{tx.outbound_anomaly_score_threshold}""
SecAction "id:980145,phase:5,pass,t:none,log,noauditlog,msg:"Incoming and Outgoing Score: %{TX.ANOMALY_SCORE} %{TX.OUTBOUND_ANOMALY_SCORE}""
    SecRule REMOTE_HOST "@contains 127.0.0.1" "phase:1,nolog,pass,id:10010"
    SecRuleRemoveById 980130
    Include /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf

    ';
...
...
...

as can be seen, I changed the paranoia level to 4, and Anomaly threshold to 2,5 for inbound and outbound (this done Controller level), and I have a rule to print these values in the logs (id:10002)

And the following in my Server block :

SecRuleEngine On
 SecAction \"log,id:10006,phase:3,msg:"Paranoia_Level %{tx.paranoia_level} Anomalyinbound %{tx.inbound_anomaly_score_threshold} Abomalyoutbound %{tx.outbound_anomaly_score_threshold}\"\" 

Make the SecRuleEngine to On as enabling it in the controller will only run ModSecurity in detection mode but with it in the ingress will do rejection of illegal requests and printing the paranoia and Anomaly,

after making curl request that triggers as an attack for ModSecurity I figured the following in the audit log s (in the same order ): ModSecurity: Access denied with code 403 (phase 2). Matched "OperatorGe' with parameter 5' against variableTX:ANOMALY_SCORE' (Value: 5' ) [file "/etc/nginx/owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [li..............14"] [ref ""]

ModSecurity: Warning. [file "<<reference missing or not informed>>"] [line "3"] [id "10006"] [rev ""] [msg "Paranoia_Level 4 Anomalyinbound 5 Abomalyoutbound 4"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "10.24.0.13"] [uri "/helloworld"] [unique_id "159155804021.961114"] [ref ""] ModSecurity: Warning. [file "<<reference missing or not informed>>"] [line "7"] [id "10002"] [rev ""] [msg "Paranoia_Level 4 Anomalyinbound 2 Abomalyoutbound 5"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "10.24.0.13"] [uri "/helloworld"] [unique_id "159155804021.961114"] [ref ""]

if you looked more deeply you will notice that the order of the rules as follows id "10006" (defined in server block) then id "10002" defined in the http block, also both have different values for the inbound_anomaly_score_threshold and outbound_anomaly_score_threshold !

My Queries are :

  1. why do the two variables printed with different values between what server block see and what HTTP block see (keep in mind they were initialized in the HTTP block)

  2. if the server block implicitly overrides what being initialized in the HTTP block, then what is the idea of turning on ModSecurity on HTTP block, not server block level?

  3. what is the correct procedure of using ModSecurity enabled on the http block, is it to only load the modsecurity.conf and OWASP CRS once, for performance issues or something deeper than this?

Thanks in advance.

martinhsv commented 4 years ago

Hi @muradmomani ,

I'll see if I can clarify a few things:

(1) It's not so much that different context blocks 'see' different values. At any given moment there is only one value for tx.inbound_anomaly_score_threshold. As you have noted, 10006 inside the server block is executed earlier, and at that time '5' is the value (I'm assuming because you've set it with the CRS phase:1 rule 901100 ). Only later does 900110 (within the http block) execute resetting the value to '2', and then 10002 runs and prints out that current value '2'.

(2)(a) For rules like your 10006 and 10002, the nested server block within the http block does not really 'override' what is in the http block. Both 10006 and 10002 are valid ModSecurity directives and both will be executed. The only question is, in which order.

Likewise, 901100 (which sets the threshold to '5') and 900110 (which sets the threshold to '2') are both valid rules and will both be executed. In this case, however, 901100 is a phase:1 rule, while 900110 is a phase:3 rule. The latter rule is guaranteed to run later than the former, which means that in phase:5 the value will be what was set by the phase:3 rule.

(2)(b) I don't believe there is a universal right-or-wrong on where one specifies 'modsecurity on'. In my test setup, all modsecurity directives happen to be within the server block. I took my cue from some nginx setup guides like this one: https://www.nginx.com/blog/compiling-and-installing-modsecurity-for-open-source-nginx/

(3) See 2b above