Reputation: 1735
I'm trying to configure modsecurity for Apache to limit the number of hits a given resource can be accessed per unit of time (let's say, 10 hits per minute per resource, no matter which ip address does the request). The resources have an url pattern in the form of "https://myhost/my-resource/my-resource-id"
# Limit the requests count by unit of time.
SecRuleEngine On
<LocationMatch "^.*/my-resource/.*">
# SecAction initcol:ip=%{REMOTE_ADDR},pass,nolog,id:132
SecAction initcol:uri=%{REQUEST_URI},pass,nolog,id:232
SecAction "phase:5,deprecatevar:uri.counter=10/60,pass,nolog,id:332"
SecRule URI:COUNTER "@ge 10" "phase:2,pause:10,deny,status:429,setenv:RATELIMITED,skip:1,nolog,id:432"
SecAction "phase:2,pass,setvar:uri.counter=+1,nolog,id:532"
Header always set Retry-After "60" env=RATELIMITED
</LocationMatch>
ErrorDocument 429 "Too Many Requests"
As I understand this snippet, it tells modsecurity "create a variable named uri for each request_uri and associate a counter for each, then decrement it of 10 each 60 seconds. If the current's uri counter reach the value of 10, fail with an error code 429, else increment it" which is what I need.
This configuration leads to "uri variable not found" error, which I don't understand why.
If I uncomment the 1st SecAction and change the remaining configuration to reference it, it works (returns a 429 after 10 quick calls), but obviously does not take the uri into account (it fails for any resource, eg. /my-resource/123 and /my-resource/456)
Could anybody give some help with this? All my attempts fails miserably and I'm not very familiar with Apache's config in general, so I guess I'm missing some important notion here.
PS: Apache is v2.4, mod-security is v2.9
Thanks!
Upvotes: 4
Views: 3563
Reputation: 1735
The configuration that works is as following:
# Limit the requests count by unit of time.
SecRuleEngine On
<LocationMatch "^.*/my-resource/.*">
SecAction initcol:resource=%{REQUEST_URI},pass,nolog,id:132
SecRule RESOURCE:COUNTER "@ge 10" "phase:3,pause:10,deny,status:429,setenv:RATELIMITED,skip:1,nolog,id:232"
SecAction "phase:2,setvar:resource.counter=+1,pass,nolog,id:332"
SecAction "phase:2,deprecatevar:resource.counter=10/60,pass,nolog,id:432"
Header always set Retry-After "60" env=RATELIMITED
</LocationMatch>
ErrorDocument 429 "Too Many Requests"
ndlr: change the collection name from "uri" to "resource" and adapt the phasing a bit
Then it works as expected (cf. modsecurity mailing list: https://sourceforge.net/p/mod-security/mailman/message/35889575/)
Upvotes: 1