I am trying to find/create a Mod_Security rule to detect & block multiple login failures on the latest version of Joomla. I found an answer from March 2015 here: https://serverfault.com/a/646608/960638 but in my own tests it does not detect login failures. Even with logging enabled it's not detecting anything. I suspect the code is outdated.
I found another ModSec rule published by IT Octopus at https://www.itoctopus.com/a-modsecurity-rule-to-block-brute-force-attacks-on-a-joomla-website
The code is below. I tested it on a server but I found it was too sensitive and it blocked me after I logged in + out of Joomla (with correct credentials).
<Location /administrator>
SecDefaultAction phase:2,deny,status:403,log,auditlog
SecRule IP:bf_counter "@eq 5" "id:1000002,phase:2,log,block,expirevar:IP.bf_counter=3600,msg:'IP address blocked because of a suspected brute force attack on the Joomla website'"
SecRule ARGS:option "@streq com_login" "id:1000000,phase:2,chain,t:none,log,pass,msg:'Multiple Joomla authentication failures from IP address', setvar:IP.bf_counter=+1"
</Location>
Next, I found a ModSecurity rule at http://artefact.io/brute-force-protection-modsecurity/ and it's the one I've been using on my servers for many months. It's been working really nicely until yesterday when we found a bug. A client has 10 Joomla websites and they found when they logged into them (with correct credentials) it resulted in their IP being restricted. I was able to replicate this during my own testing.
Therefore the code below is the best code we've found yet but the com_login / login lines don't seem to distinguish between login failures and successful logins. It works to prevent general brute force but it doesn't work when a client has many Joomla sites and is legitimately accessing multiple installs at once. This is the code:
# Joomla Brute Force
SecAction "phase:1,pass,setvar:TX.max_requests=6,setvar:TX.requests_ttl=180,setvar:TX.block_ttl=900,initcol:ip=%{REMOTE_ADDR},nolog,id:5001000"
<LocationMatch "/administrator/index.php">
SecAction "phase:2,chain,nolog,id:5001022"
SecRule REQUEST_METHOD "^POST$" "chain"
SecRule ARGS_POST_NAMES "^username$" "chain"
SecRule ARGS_POST_NAMES "^passwd$" "chain"
SecRule ARGS_POST:option "^com_login$" "chain"
SecRule ARGS_POST:task "^login$" "chain"
SecAction "setvar:ip.request_count=+1,expirevar:ip.request_count=%{TX.requests_ttl}"
SecRule IP:request_count "@ge %{TX.max_requests}" "phase:2,drop,setvar:ip.blocked=1,expirevar:ip.blocked=%{TX.block_ttl},log,msg:'Joomla brute force. Blocking for %{TX.block_ttl} seconds',id:5001023"
</LocationMatch>
Finally, I read some posts that suggested "the P3P header is returned after a successful login" and this could be used in a ModSecurity rule. It was suggested by @godzillante here: https://serverfault.com/a/646608/960638
It uses ModSecurity phase 5 (analysing the log files) so I'm not sure if this is a disadvantage. And more importantly, in my testing I couldn't get it to work. Even with logging enabled, it didn't detect failed logins and didn't restrict access. Here is the code:
SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},id:5000144
<Locationmatch "/administrator/index.php">
SecRule ip:bf_block "@gt 0" "deny,status:401,log,id:5000145,msg:'ip address blocked for 5 minutes, more than 5 login attempts in 3 minutes.'"
SecRule RESPONSE_HEADERS:P3P "streq 0" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000146"
SecRule RESPONSE_HEADERS:P3P "!streq 0" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000147"
SecRule ip:bf_counter "@gt 5" "t:none,setvar:ip.bf_block=1,expirevar:ip.bf_block=300,setvar:ip.bf_counter=0"
</locationmatch>
My objective here is to improve the code "Joomla Brute Force" (above) because it does block brute force flooding but unfortunately it also blocks users when they are legitimately logging into Joomla a lot. I need code that can tell the difference between a login failure and a successful login to Joomla.
I've been working on this for some time so I'm reaching out to the community here. Thanks in advance!