How To

WordPress Login Protection with ModSecurity

If you have ModSecurity and root access, you can cold-stop people trying to brute force into WordPress on your server.

No ModSec? Check out WordPress Login Protection With .htaccess

LockIf you’re on Liquid Web servers, this was already done for you. If you’re not, you should still be able to use this code on your own ModSecurity instance. Since this is a way better method to block people than via a plugin, in my opinion, I thought it would be a good idea to share it here. With this rule, you won’t have quite as many http requests.

WordPress is a popular publishing platform which is known for its robust features, numerous templates, and large support community. Unfortunately, due to such popularity, WordPress is also constantly subject to attempts at exploiting vulnerabilities. Ensuring WordPress and any associated plugins are installed with the most current versions is an important means of securing your site. However, ModSecurity provides a significant amount of further security by providing an application firewall.

ModSecurity (also known as “modsec”) has proven itself useful in a variety of situations, and again this is true in assisting with WordPress brute force attempts resulting in a Denial of Service (DoS) attack. While a number of WordPress plugins exist to prevent such attacks, custom modsec rules can prevent such attacks for all WordPress installations on a server. Modsec immediately filters incoming HTTP requests, which assists against taxing server resources.

These rules will block access for the offending IP address for 5 minutes upon 10 failed login attempts over a 3 minute duration. These rules have been automatically updated in the custom rules for Liquid Web’s ServerSecure service. For customers without ServerSecure, these rules can be added to their custom modsec rules. To accomplish this, edit your custom modsec user rules and append the file with the rules provided below. For CPanel servers, this file is likely located at /usr/local/apache/conf/

SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},initcol:user=%{REMOTE_ADDR},id:5000134
<Locationmatch "/wp-login.php">
    # Setup brute force detection.

    # React if block flag has been set.
    SecRule user:bf_block "@gt 0" "deny,status:401,log,id:5000135,msg:'ip address blocked for 5 minutes, more than 10 login attempts in 3 minutes.'"

    # Setup Tracking.  On a successful login, a 302 redirect is performed, a 200 indicates login failed.
    SecRule RESPONSE_STATUS "^302" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:5000136"
    SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:5000137"
    SecRule ip:bf_counter "@gt 10" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0"

Source: Liquidweb and Frameloss and MNX Solutions

Logically, someone can extend this code to any file, like bb-login.php or Special:UserLogin, depending on where they’re being hacked.

ETA: Rarst asked if I’d have to use wildcards with Locationmatch since WP is often in a subfolder. I read the Apache doc on locationmatch and it says that it’s using regex, so it should just look for ‘/wp-login.php’ in the URL. If I wanted to only look for then I’d use ^wp-login.php instead. If I got that wrong, please let me know!

29 replies on “WordPress Login Protection with ModSecurity”

Rarst asked if I’d have to use wildcards with Locationmatch since WP is often in a subfolder. I read the Apache doc on locationmatch and it says that it’s using regex, so it should just look for /wp-login.php in the URL. If I wanted to only look for then I’d use ^wp-login.php instead. If I got that wrong, please let me know!

Notes people insist on tweeting me, rather than leaving comments (seriously?)

1) Yes it works in subdirectories
2) As of ModSec 2.7.3, you can use htaccess overrides again, but I doubt everyone’s on it
3) Original original source was frameloss –

By the way, if you leave a comment, you’re actually MORE likely to get a reply. Also it helps anyone who google’s and finds this page. Twitter is transient, folks 😉

Very cool.

I’ve been trying to get the nginx version mod_security up and running on my nginx VPS playground for a while (unsuccessfully but I’m not very dedicated). I’m going to check if it includes brute force protection like this and if not try to get it added.

Thanks for the idea.

PS. I’m utterly perplexed by your new avatar, “the hat” is so ingrained in my head…

The hat would hide my blue hair 😉 Pretend its an invisible fedora.

I would assume that mod security would always work the same way, so the brute force rules should be applicable be it apache or nginx, otherwise what the hell is the point of it?

Some of my sites are getting slammed by login attempts so I’m thinking of using ModSecurity. But I don’t understand the official installation instructions. They’re not basic enough for me. Do you have any suggestions for instructions for people who are clueless?

For example these instructions:

Edit to configure the Apache base and library paths. Compile with: nmake -f Install the ModSecurity module with: nmake -f install

What does “Compile” mean?

I’m running Windows 7 64-bit.

I installed mine with Apache (and that’s pretty common). Are you sure you don’t already have it installed? You can run this command to check : grep "modsecurity" /usr/local/apache/logs/error_log

That gave me this:

[Thu Apr 04 09:10:23 2013] [notice] ModSecurity for Apache/2.7.2 ( configured.

What server OS are you on?

It turns out those sites are running ModSecurity but since it’s shared I can’t make changes. Those sites are on inmotion hosting and I’m not the only customer getting slammed. They said they’re working on solutions from their end so I pointed the guy on the phone to this post. Here’s hoping they use this.

You run the command via shell (so you SSH in and type that)

Yeah, if you don’t have VPS/Dedicated access to a server, there’s very little you can use unless you’re on ModSecurity 2.7.3. If you ARE you can use this in your .htaccess file instead, though I’m not 100% sure of the formatting.

On Apache/Linux servers, we’ve found that once the modsec rule is in place, you can alleviate additional load by adding this to your sites .htaccess file:

ErrorDocument 401 default

This stops WP from trying to process any 404’s for 401.shtml, and results in a flat text file being served with no redirects being processed while modsec is blocking the IP.

Additionally on Linux servers, using configserver firewall (CSF) with LF_MODSEC enabled will ban IP’s in iptables if they continue abuse once modsec has blocked them.

I’d love a bit of help getting this configured on my server. I have a Mod Security area on my WHM panel. I tried cutting and pasting that info above into the config area. Tried locking myself out, but didn’t have any luck. But there is now some entries showing up that look like this…

Unable to store collection (name “ip”, key “”). Use SecDataDir to define data directory first.

And the action related to it was 200 — which makes me think I was close.

I’m attempting to do it via WHM. But I googled the file you said above and found it, and the only thing inside the file is what I placed in the WHM… which is what I cut and pasted from above. Is there another file I should be placing it in?

It really depends on your server. My file is FILLED with stuff, see, and … Huh (Oh you CAN edit it in WHM! Hah, I was still using command line).

Okay, put this at the top:

SecUploadDir /tmp
SecTmpDir /tmp
SecDataDir /tmp

SecRequestBodyAccess On

Yay! You may also want to create a real 401.html file, and redirect to it in .htaccess:

ErrorDocument 401 /401.html

That will help keep the load off WP. (I had done this for other reason, but my friend B suggested it.)

Hackers, maybe. But this sort of scripted attack isn’t looking for VPS or Dedicated or Slice or whatever. It’s looking for WordPress. A hacker is looking for ME. A cracker, or a script kiddie, is looking for destruction.

I’d put money down that this is a plot to infect our servers and then use them for zombie attacks. Probably DDoS. If I didn’t know better, I’d say it was anon, but this isn’t their style.

Thanks so much, I have installed this on my cpanel/WHM/configserver VPS, and it works like a dream. Now invalid logins are being blocked after 10 attempts, and the IP blocked for 5 minutes. Perfect.

Hi Mika,

For Nginx users there is an alternative to mod_sec:

In your main nginx.conf add to the http{} area:
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

Then edit your vhost file, or if one big nginx.conf file inside the server area:

location ~ \.php$ {
limit_req zone=one burst=5 nodelay;

Comments are closed.

%d bloggers like this: