WordPress Login Protection With .htaccess

No ModSecurity? No problem (unless you're on nginx)! You can still do things to help protect yourself from the insanity of people hammering your server trying to log in to WordPress.

bandaided computerThe Brute Force attack on WordPress and other CMS apps is getting worse and worse right now. Some people don’t have Mod Security (or can’t get it to work on their server), and asked me if there was anything to be done. Yes, you can still protect your site from those brute forcers via .htaccess.

To be honest, I worried about posting this, since the last thing I want to do is to inspire hackers to do even more inventive things, but I can’t think of another way to get the word out. I want to say this: If your site is being hammered hard by these attacks, CONTACT YOUR WEBHOST RIGHT NOW. The best protections will be done on their end, because using WP to try and stop this still means people are hammering WP.

So okay, what can you do with .htaccess? Well, taking into account the ages old .htaccess block that has been posted up at WordPress.org, you can block comments made by people with out a Referrer Request, I made the logical extension!

### Blocking Spammers Section ###

# Stop protected folders from being narked. Also helps with spammers
ErrorDocument 401 /401.html

# Stop spam attack logins and comments
<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteCond %{REQUEST_URI} .(wp-comments-post|wp-login)\.php*
	RewriteCond %{HTTP_REFERER} !.*(ipstenu.org|halfelf.org).* [OR]
	RewriteCond %{HTTP_USER_AGENT} ^$
	RewriteRule (.*) http://%{REMOTE_ADDR}/$ [R=301,L]

So the rule does the following:

  1. Detects when a POST is being made
  2. Check to see if the post is on wp-comments-post.php or wp-login.php
  3. Check if the referrer is in your domain or if no referrer
  4. Send the spam-bot BACK to its originating server’s IP address.

The reason my referrer line has (ipstenu.org|halfelf.org) is because … well I have multiple domains on my multisite! If you don’t, you can just have it be one domain, but this lets me have one line instead of eight (yes, eight, you heard me). Not all of them are .org, but if they were, that line would look like this:

RewriteCond %{HTTP_REFERER} !.*(ipstenu|halfelf)\.org.* [OR]

Only make variable what you have to, eh?

Edit: If you’re using Jetpack for comments, you should also add in jetpack.wordpress.com as a referrer.

Above that, though, you saw the 401 rule, right? The 401 takes any errors, which can be abused by this, out of the hands of WP. However for this to work best, you have to actually make a 401.html file.

Here’s mine:

<title>401 Error - Authentication Failed</title>


<h1>401 - Authentication Failed</h1>

    <p>Through a series of highly sophisticated and complex algorithms, this system has determined that you are not presently authorized to use this system function. It could be that you simply mistyped a password, or, it could be that you are some sort of interplanetary alien-being that has no hands and, thus, cannot type. If I were a gambler, I would bet that a cat (an orange tabby named Sierra or Harley) somehow jumped onto your keyboard and forgot some of the more important pointers from those typing lessons you paid for. Based on the actual error encountered, I would guess that the feline in question simply forgot to place one or both paws on the appropriate home keys before starting. Then again, I suppose it could have been a keyboard error caused by some form of cosmic radiation; this would fit nicely with my interplanetary alien-being theory. If you think this might be the cause, perhaps you could create some sort of underground bunker to help shield yourself from it. I don't know that it will work, but, you will probably feel better if you try something.</p>


RepairThere are more WordPress specific tips and tricks on the WordPress Codex Brute Force Attacks which we Forum Volunteers have been working on all morning. If you want to do even more, then you’ll want to password protect your wp-login.php page, or perhaps whitelist it so only your IPs have access. Personally, I’m not doing that (I have ModSec working) and I’m not using any plugins. While the plugins are great, they still require WordPress to process something, which means that while they can, and will, prevent people from getting in, they won’t stop the traffic on your server.

I wish I knew more about nginx, but if someone can translate all those things to nginx, please post a link and share it! We need to know!

At a last gasp, CloudFlare and Sucuri CloudProxy both claim to stop this before it hits you. I don’t use either, as you may know, so I can’t speak for them, but if your host is unable of doing anything, and you can’t make anything work, you may as well try it.


    • I also really appreciate that you said your opinion of the what has become the common answer of password protecting wp-login and white-listing your IP.

    • Theoretical idea … you could white list your IP, then have a URL you can go to to automatically add your current IP in. If it’s a random URL that no one could guess, and you didn’t show it to anyone, then that should be sufficient to block all of this and would cause you only a minor hassle in having to click a link to add your current IP into a list. That includes a certain amount of security obscurity, but assuming no one finds the link then it should work just dandy.

    • Mika, do you know how many login attempts they’re attempting per minute ? I’m not sure if I need to plan for this attack or if I can just ride it out is it happens.

    • If your site is being attacked, e.g., someone’s trying to brute-force login, I recommend the plugin ThreeWP Activity Monitor. From its wordpress.org plugin page:

      Displays a multitude of user actions to keep the site administrator informed that all is well and that the blog or network is not being abused.

      I installed it yesterday and it immediately showed an attack in progress, from a multitude of IP addresses, all trying to access a non-existent “test” account using many different dictionary-based passwords. I can only assume they’d already exhausted their dictionary on my also non-existent “admin” account. They were trying, on average, about 2-3 login attempts per minute.

      After a 6 hour break, they tried various different usernames with random-type passwords, like “qwerty” username with “qnkvy” as a password. This attack only lasted about 25 minutes, using 11 different usernames/passwords, coming from unique IPs.

    • Due to the nature of these attacks, I cannot in good faith recommend ANY plugin. The plugins work fine, but they’re too late in the game to stop your server from going down.

      They can, and will, help you most days, but you have to stop these people before they get to WP, or the attacks will swamp your server. Also I don’t like having WP, or .htaccess, block IPs. If you’re that bad off, you should lock your wp-login.pho to your IP address only. Everything else isn’t enough.

  1. Your code you posted is cool the only problem is now you give apache more work to do πŸ™

    I just spent the last 2 weeks on our server hardening it.

    CSF FireWall and about 1500 permanent blocks
    Mod_Securety Standard out the box
    KeepAlive Off (The silent server killer)

    Wordfence Security http://wordpress.org/extend/plugins/wordfence/
    I just set it on 5 and then ran the free scan it works and you won’t believe how many fake google bots are out there

    robots.txt http://bloglines.co.za/robots.txt
    .htaccess remove all code just left the WordPress code

    define('NOBLOGREDIRECT', 'http://gymequipmentforsale.co.za/' );

    define('WP_DEBUG', false);
    define('WP_ALLOW_REPAIR', true);
    define('WP_POST_REVISIONS', false);
    define('AUTOSAVE_INTERVAL', 3600);
    define('WP_MEMORY_LIMIT', '96M');
    define('WP_MAX_MEMORY_LIMIT', '256M');

    Over all it worked for me and the botnet f… are gone for now

  2. I have another idea … You can’t block this via a plugin directly , but what about a plugin which modified your web server configuration file to block specific ips when they attempt to log into the admin user account?

    • I personally strongly dislike the idea of using WP to detect (and store) a valid IP and then write back to .htaccess (did you know I lock mine down so WP can’t? It’s how I keep myself a little safer from bad plugins)

      That plugin you describe is exactly what ModSecurity does when you tie it into CSF (or directly into IP Tables) and that’s what hosts are doing. It’s far better to do it before the attacker hits WP, as that saves your site from having to render PHP pages.

  3. Ryan asked how many per minute – I’m linking here to Hacker News because someone put up his log: https://news.ycombinator.com/item?id=5543055

    About 10 per minute from what he saw. Before it was about 100 per, but once all we hosts kicked in rules to says ‘Okay, you smart asses, only 10 tries before you’re punted.’ But to be honest, we were tracking how many times per IP not per minute. I prepared for it because while I seem not to have been hit yet, I don’t want to be, and rate-limiting failed logins is easy, and year-round safe. However the best preparation for this? Is server side, so hosting companies should be prepping.

    Liquid Web, Media Temple, and DreamHost I can tell you, with 100% confidence, are putting in server protections for you. I didn’t ask the others yet.

    (Also I should note: I have no idea what my passwords are πŸ˜‰ )

  4. I was talking to Noel Tock in private about this earlier. He has convinced (albeit indirectly) that plugins are a viable way to block this. I had been saying otherwise, but now I’m swaying towards being in favour of recommending plugins as a crude method of solving it.

    The load on your server is caused by hitting the users table, hashing passwords etc. But if a plugin is able to track attacks from a specific IP, then it would be able to efficiently stash it in the DB. Then when a bot comes back, all the plugin has to do (early on in the stack) is to check the database for that IP (simple query) and if it’s in there, then reject the request. It’s still polling WordPress, but is a heck of a lot more efficient than letting the bot go all the way through a complete login process.

    There are supposedly 90,000+ IPs involved in the attack, but from what I’m hearing from people, most of them are coming at them from a much smaller subset, so blocking the majority of them seems like it would be sufficient to stop the site from going down.

    It seems to me like something of this nature in core could be a handy way to mitigate these types of attacks. It’s not really WordPress’s job to do this, but if it can block it to some extent, then it’ll reduce the likely hood of anyone attempting it in future. It’s the same with minimum password functionality – if it had been rolled into core, then this attack wouldn’t have occurred as the attackers would have discovered that they couldn’t brute force anyones passwords, hence making the attack useless to them.

    Any opinions on this?

    • Oh I don’t disagree a plugin can do that. And Noel (and you) are on the right track with an idea that could help block that way. If you’re going to have WP block it, then yes, use something that blocks before the jerk logs in. But if you can stop them before they get that far, that would be even better.

      The main issue I have with using WP is most plugins are checking on login and that’s too late. The second problem with using a plugin is that I’m making WP do work it shouldn’t be doing. I don’t use a mini-coop to haul a boat, I use an SUV. WP is the mini to my server’s tank πŸ™‚

      Now should this be in core? Ehhhh yes and no. I say no because I think of user support, and how innocent and new many users are, and how much of a PITA it is to help them unlock an account today. I don’t even want to think about having to explain how to get your IP, and how to unlock it, because if you have an interface to do it with, the hackers can attack that. All you did was move the door. And if you make it ‘Edit the DB’ then no, hell no, no fucking way. Any time you think the best way to unlocking anything in WP is editing the DB, shut up and go sit in the WP forums for 2 hours and try to help people. When you’re ready to drink, you’ll understand what I mean.

      (Minimum password strength would be nice, though.)

    • What if it just blocked them for 30 minutes before unlocking their account again? That way the user would know they just need to wait 30 minutes before attempting to log back in again (coz it’d tell you that as an error message).

      Of course there’s always the risk some dimwit on the same IP as you is trying to lock you out of your own account, in which case they could just keep attempting to log in and you would never be able to get back in. Which I guess ties in with your concerns regarding users not knowing how to work around this.

      I’ll keep pondering this. Maybe there is a way to implement this sort of thing in an efficient manner.

      One other thing … the plugin could technically rewrite the server config files. WordPress already does that internally for htaccess rewrite rules, so it doesn’t seem like a big jump to extend that to IP blocking. I’m not sure I’d be that happy with it messing with my Nginx config rules though; something about that makes me a little queasy.

    • Of course there’s always the risk some dimwit on the same IP as you is trying to lock you out of your own account, in which case they could just keep attempting to log in and you would never be able to get back in. Which I guess ties in with your concerns regarding users not knowing how to work around this.

      Perfect example of this: Multisite Network. Family members have sites on the network. Grandma typos and locks everyone out.

      And that’s what we’d see in the forums, and that’s what we’d have to find a way to solve. Maybe if it logged which IPs were legit used by which account, and thus if keeps hammering, but it’s a known good IP address with Momstenu, then it doesn’t lock out? But now we’ve made our plugin heavier with more checks, which means a brute force will take up more CPU, and have the other impact I hate :/

      Which is really where I come down on all this. Strong Passwords and good server security. I trust WP’s native security, so all I have to do is brute force protect myself, and my server can do that. All servers can do that. So make the server do the work and treat it like all others brute force attacks. Imagine if we had awesome server security all over that said ‘You know, someone hammering on login scripts is probably a hack…’ (Course then people would use that as an excuse to write shit code – bleah).

      One other thing … the plugin could technically rewrite the server config files. WordPress already does that internally for htaccess rewrite rules, so it doesn’t seem like a big jump to extend that to IP blocking. I’m not sure I’d be that happy with it messing with my Nginx config rules though; something about that makes me a little queasy.

      Editing an nginx conf file, or a .htaccess, is not the same as what I view as ‘server config files’ though… If a plugin wants to touch my httpd.conf file, I will KILL IT WITH FIRE. Newbies keep the fuck out of that file!

  5. The 401.html goes in the root directory along with the modified .htaccess correct?

    Thank you for the guide BTW, I’ve linked to it in my blog. 😎

Comments are closed.

%d bloggers like this: