Mod security

From TMM Wiki
Jump to navigationJump to search

General Information on modsecurity & modsececurity2

  • 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>

-->