Mod security
- The ruleset(s) provided by modsecurity/modsececurity2 will affect NATS processes and these rules are enabled by default. These default ruleset(s) need to be disabled so they will not get used.
- Host can create custom rules that only apply for things outside of NATS
- Host's responsibility to ensure that these rules don't affect NATS functions on NATS domain & linkdomains
Example Custom Rules for ModSecurity2
https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)
You can create customized rules with modsecurity2, to rate-limit by ip, request vars being sent, etc. These are example rules that will rate-limit requests and prevent bot spam. You can use these rulesets as a reference, but be aware that you are responsible for your configuration and that you should NOT use the default rulesets provided by modsececurity2.
Member Signup Throttling
Rate-limit to 75 requests to signup/signup.php using the same password or email within a 10 minute period.
<Location /signup/signup.php> # needs to be enabled to read POST data SecRequestBodyAccess On # jump to SecMarker if signup[password] variable is not passed in request SecRule ARGS:signup[password] "^$" "phase:2,id:'981041',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS1" # set 'RESOURCE' to value of signup[password] if it is not blank SecRule ARGS:signup[password] ".*" "phase:2,id:'1',chain,t:none,nolog,pass" SecAction initcol:RESOURCE=%{ARGS.signup[password]} # enforce an existing block SecRule RESOURCE:bf_block "@eq 1" \ "id:2,phase:2,deny,\ msg:'Password \"%{ARGS.signup[password]}\" blocked because of suspected brute-force attack'" # set or increase count of how many times a signup[password] value was used and have it expire after 600 seconds SecRule ARGS:signup[password] ".*" "phase:5,id:3,t:none,nolog,pass,setvar:RESOURCE.bf_counter=+1,expirevar:RESOURCE.bf_counter=600" # check for too many requests for a single signup[password] value and block future requests that contain that value SecRule RESOURCE:bf_counter "@ge 75" \ "id:4,phase:5,t:none,pass,\ setvar:RESOURCE.bf_block,\ setvar:!RESOURCE.bf_counter,\ expirevar:RESOURCE.bf_block=600" # jump to this point if signup[password] is not passed in request SecMarker END_BRUTE_FORCE_PROTECTION_CHECKS1 # jump to SecMarker if signup[password:1:6:16:::password_check] variable is not passed in request SecRule ARGS:signup[password:1:6:16:::password_check] "^$" "phase:2,id:'981042',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS2" # set 'RESOURCE' to value of signup[password:1:6:16:::password_check] if it is not blank SecRule ARGS:signup[password:1:6:16:::password_check] ".*" "phase:2,id:'5',chain,t:none,nolog,pass" SecAction initcol:RESOURCE=%{ARGS.signup[password:1:6:16:::password_check]} # enforce an existing block SecRule RESOURCE:bf_block "@eq 1" \ "id:6,phase:2,deny,\ msg:'Password \"%{ARGS.signup[password:1:6:16:::password_check]}\" blocked because of suspected brute-force attack'" # set or increase count of how many times a signup[password:1:6:16:::password_check] value was used and have it expire after 600 seconds SecRule ARGS:signup[password:1:6:16:::password_check] ".*" "phase:5,id:7,t:urlDecode,nolog,pass,setvar:RESOURCE.bf_counter=+1,expirevar:RESOURCE.bf_counter=600" # check for too many requests for a single signup[password:1:6:16:::password_check] value and block future requests that contain that value SecRule RESOURCE:bf_counter "@ge 75" \ "id:8,phase:5,t:none,pass,\ setvar:RESOURCE.bf_block,\ setvar:!RESOURCE.bf_counter,\ expirevar:RESOURCE.bf_block=600" # jump to this point if signup[password:1:6:16:::password_check] is not passed in request SecMarker END_BRUTE_FORCE_PROTECTION_CHECKS2 # jump to SecMarker if signup[email] variable is not passed in request SecRule ARGS:signup[email] "^$" "phase:2,id:'981043',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS3" # set 'RESOURCE' to value of signup[email] if it is not blank SecRule ARGS:signup[email] ".*" "phase:2,id:'9',chain,t:none,nolog,pass" SecAction initcol:RESOURCE=%{ARGS.signup[email]} # enforce an existing block SecRule RESOURCE:bf_block "@eq 1" \ "id:10,phase:2,deny,\ msg:'Email \"%{ARGS.signup[email]}\" blocked because of suspected brute-force attack'" # set or increase count of how many times a signup[email] value was used and have it expire after 600 seconds SecRule ARGS:signup[email] ".*" "phase:5,id:11,t:none,nolog,pass,setvar:RESOURCE.bf_counter=+1,expirevar:RESOURCE.bf_counter=600" # check for too many requests for a single signup[email] value and block future requests that contain that value SecRule RESOURCE:bf_counter "@ge 75" \ "id:12,phase:5,t:none,pass,\ setvar:RESOURCE.bf_block,\ setvar:!RESOURCE.bf_counter,\ expirevar:RESOURCE.bf_block=600" # jump to this point if signup[email] is not passed in request SecMarker END_BRUTE_FORCE_PROTECTION_CHECKS3 # jump to SecMarker if signup[email:1:1:128:::email_check] variable is not passed in request SecRule ARGS:signup[email:1:1:128:::email_check] "^$" "phase:2,id:'981044',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS4" # set 'RESOURCE' to value of signup[email:1:1:128:::email_check] if it is not blank SecRule ARGS:signup[email:1:1:128:::email_check] ".*" "phase:2,id:'13',chain,t:none,nolog,pass" SecAction initcol:RESOURCE=%{ARGS.signup[email:1:1:128:::email_check]} # enforce an existing block SecRule RESOURCE:bf_block "@eq 1" \ "id:14,phase:2,deny,\ msg:'Email \"%{ARGS.signup[email:1:1:128:::email_check]}\" blocked because of suspected brute-force attack'" # set or increase count of how many times a signup[email:1:1:128:::email_check] value was used and have it expire after 600 seconds SecRule ARGS:signup[email:1:1:128:::email_check] ".*" "phase:5,id:15,t:none,nolog,pass,setvar:RESOURCE.bf_counter=+1,expirevar:RESOURCE.bf_counter=600" # check for too many requests for a single signup[email:1:1:128:::email_check] and block future requests that contain that value SecRule RESOURCE:bf_counter "@ge 75" \ "id:16,phase:5,t:none,pass,\ setvar:RESOURCE.bf_block,\ setvar:!RESOURCE.bf_counter,\ expirevar:RESOURCE.bf_block=600" # jump to this point if signup[email:1:1:128:::email_check] is not passed in request SecMarker END_BRUTE_FORCE_PROTECTION_CHECKS4 </Location>
Plus script Throttling
Rate-limit the *plus scripts (as well as approved,upgraded,duplicate, and submit scripts) to 75 requests from the same ip address within a 10 minute period
<LocationMatch "/signup/(upgradeplus|approved|upgraded|upsellplus|packageplus|tokenplus|cancelplus|duplicate|verifyplus|signupplus|submit).php"> SecAction initcol:IP=%{REMOTE_ADDR},pass,nolog,id:21 # enforce an existing block SecRule IP:bf_block "@eq 1" \ "id:22,phase:2,deny,\ msg:'IP \"%{REMOTE_ADDR}\" is being throttled'" SecRule REMOTE_ADDR ".*" "phase:5,id:23,t:none,nolog,pass,setvar:IP.bf_counter=+1,expirevar:IP.bf_counter=600" SecRule IP:bf_counter "@ge 75" \ "id:24,phase:5,t:none,pass,\ setvar:IP.bf_block,\ setvar:!IP.bf_counter,\ expirevar:IP.bf_block=600" SecMarker END_BRUTE_FORCE_PROTECTION_CHECKS5 </LocationMatch>
Affiliate Login Throttling
Rate-limit affiliate login attempts to 100, but also dynamically increase rate-limiting to 5 if there are more than 1000 login attempts within a 5 minute period
#Bruteforce checking for affiliate login #Block ip if X amount of hits to internal.php containing user and pass params <Location /internal.php> # needs to be enabled to read POST data SecRequestBodyAccess On # jump to SecMarker if user variable is not passed in request SecRule &ARGS:user "@eq 0" "phase:2,id:'30',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS6" SecRule ARGS:user "^$" "phase:2,id:'31',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS6" # jump to SecMarker if pass variable is not passed in request SecRule &ARGS:pass "@eq 0" "phase:2,id:'32',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS6" SecRule ARGS:pass "^$" "phase:2,id:'33',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS6" SecAction initcol:IP=%{REMOTE_ADDR},pass,nolog,id:34 # enforce an existing block SecRule IP:bf_block "@eq 1" \ "id:35,phase:2,deny,msg:'IP \"%{REMOTE_ADDR}\" is being throttled, too many affiliate login attempts'" # check if we're getting a ton of login attempts SecAction initcol:RESOURCE=%{REQUEST_FILENAME},pass,nolog,id:39 SecRule REQUEST_FILENAME ".*" "phase:5,id:41,t:none,nolog,pass,setvar:RESOURCE.bf_counter=+1,expirevar:RESOURCE.bf_counter=300" SecRule REMOTE_ADDR ".*" "phase:5,id:36,t:none,nolog,pass,setvar:IP.bf_counter=+1,expirevar:IP.bf_counter=300" # increase throttling if we're under attack # start throttling after 5 requests SecRule RESOURCE:bf_block "@eq 1" "id:38,phase:5,chain,msg:'too many login attempts occuring, increase throttling',t:none" SecRule IP:bf_counter "@ge 5" "t:none,\ setvar:IP.bf_block,\ setvar:!IP.bf_counter,\ expirevar:IP.bf_block=300" # increase throttling if more than 1000 login attempts total SecRule RESOURCE:bf_counter "@ge 1000" \ "id:40,phase:5,t:none,pass,\ setvar:RESOURCE.bf_block,\ setvar:!RESOURCE.bf_counter,\ expirevar:RESOURCE.bf_block=300" # throttle ip after 100 requests SecRule IP:bf_counter "@ge 100" \ "id:37,phase:5,t:none,pass,\ setvar:IP.bf_block,\ setvar:!IP.bf_counter,\ expirevar:IP.bf_block=300" # jump to this point if user or pass is not passed in request SecMarker END_BRUTE_FORCE_PROTECTION_CHECKS6 </Location>
-->