Brute force attacks are a big problem for many WordPress websites. If you haven't experienced one of these yet, count yourself lucky.
I was having issues on a client's website last week and the problem turned out to be a brute force attack.
So, I thought I'd post some information on these brute force attacks and share a plugin I wrote to prevent them.
What is a brute force attack?
A brute force attack is when a hacker hits your WordPress login with a large number of login requests using different usernames & passwords. The point of the brute force attack from the hacker's perspective is to try to guess a username & password combo to gain access to your website.
This is one of the many reasons why you should never use the name ‘admin' for your admin user and make sure you create a strong password … because it's one thing to be annoyed with a failed brute force attack and quite another for your site to be compromised by a successful brute force attack.
How do I know if I'm under attack?
Well it depends but what I've experienced has been a sudden drop in the responsiveness of a website (I've actually seen them become completely unresponsive due to the flood of login attempts — similar to a denial of service attack). Then when I check my apache access logs I see thousands of POST requests to my /wp-login.php script.
What can I do to prevent a brute force attack?
The most apparent way to prevent brute force attacks is to enable a second layer of authentication over your wp-admin … this is a great way to go but it can break some normal WordPress functionality (particularly the admin-ajax functionality that some plugins can rely on even on the front end of a website). This approach is solid (and should completely stop your brute force attacks) though and if you want to do this you can follow the steps in this excellent article from my buddies at Securi.
Because I didn't want to break the functionality of my front end ajax, I opted to write a plugin that implements three ways to prevent these attacks. The plugin is named WP Login Protector and I put it up on GitHub for anyone to download (I'm sure I'll get around to submitting it to the WP Repo soon) … here's a rundown of the methods it uses to prevent these attacks:
- POST Cookie Protection — This will set a cookie when an initial, GET request is made on the site (which happens when a human logs in). If the Cookie is not present on the POST request then the login is blocked.This effectively blocks non-human robots from successfully issuing a POST request to WordPress' login page.
- Block HTTP/1.0 POSTs — Block any login POST requests made with HTTP 1.0. Since it is common for bots to use HTTP 1.0 (and no modern browser that I know of sends HTTP 1.0 requests), this should effectively block them from attempting to login.
- Targeted Basic Authentication — This will add an extra layer of basic authentication to the WordPress login page. This is a more aggressive approach but should completely prevent any bots from even attempting a WordPress login.Unlike modifying your webserver configuration to add Basic Authentication, this approach will not break the functionality of nopriv ajax actions.
By default, when you install this plugin it will enable the first 2 methods listed above … but if you want the 3rd, all you'll have to do is check a box on the WP Login Protector settings page.
I can't guarantee that this will cover every scenario imaginable or that a hacker's script couldn't be modified to bypass the first 2 strategies this plugin employs … but I can say that it has completely blocked all brute force attacks on my client's site since it was installed.
Dr. Michael Haley says
Blair, I trust your plug-ins b/c pretty link is so AWESOME. We implemented a different unique strategy to stop attacks… but we’ll lose it every time we update WordPress… Oh well. What are you doing to prevent comment spam? I noticed you don’t even have a captcha here…???
Blair Williams says
I just use Akismet … it works great.
I’m not a huge fan of captchas … so I’ll generally take whatever measure I can before I resort to using them. 🙂
Dr. Michael Haley says
OK. Thank you for the reply. I do use Akismet, but still feel I have to sift through the spam comments in case a legit comment got trapped in their. Oh well. O.C.D. I guess. Thank you for making awesome plugins.
Avihay says
Very helpful, thank you
Richard says
You’re always looking out for me! We’re up and running.
Stewart V says
Blair, many thanks, we have been victims of several attacks over the last months so we will be deploying this plugin tomorrow. Many thanks for sharing and taking the time to produce this.
Cheers from the UK!
Stewart
Leanne says
Thanks Blair I will be trying this too. I use a kismet for spam comments but you have to manually send them all to spam. very annoying! Any ideas? . I set up another plug in to prove your not a robot but prefer not to have it, like you. Keep up your hard work. Love my pretty link. Cheers
Blair Williams says
I don’t actually have a solution that will automate comment spam more effectively than Akismet … there is a technique that can be used called a honeypot field that is typically very effective (in my experience, just as effective as a captcha) but is completely transparent to the user. I’m not sure if any plugins exist that add something like this already but it’s a great idea.
Todd says
We’e using PrettyLink which we love, will look to add this new plugin. Thanks!
Scott says
Thanks for the share of this brute force deterrent, I hope I never need it but glad to know it’s in force and ready for action if attacked.
Blair Williams says
Thanks… However, sometimes in the midst of an attack you may not be to do much with your site at all so it may be best to install this plugin *before* you get attacked.
Rainer says
I used Hostgator’s method of creating a new .wpadmin file and then adding some script to the .htaccess file. Now I have to go through 2 layers of authentication manually on every WP site on my first login. Would I still need your plugin? Would I still need to go through the extra level of security manually? Would they conflict if I have both? Thx in advance.
-Rainer
Blair Williams says
WP Login Protector will give you 3 options for protecting the wp-login.php script on your site … the most extreme (and bulletproof) is effectively the same as what you have setup through your web server right now (but with WP Login Protector there is no need to alter your apache files whatsoever, it can just add the second layer of basic authentication automatically). So my advice is to stick with what you have unless you’re having issues with some of the functionality on the front end of your site — or really can’t stand entering in credentials twice.
Richard says
I enabled “Basic Authentication” but have no clue what log in credentials to use… my WP credentials are Not accepted.
Do we need to make come new credentials in an .htaccess file?
This point is absent in your documentation.
Please Help clear this up.
Richard
Blair Williams says
Hmm … No need to make an .htpassword file or anything like that. It should use your WP credentials currently.
It uses WordPress’ built in wp_authenticate method.
https://github.com/supercleanse/wp-login-protector/blob/master/wp-login-protector.php#L109
Richard says
Blair
Thank you for replying. I would REALLY like to use your plugin but it refuses to play nice with my WP installation.
If you contact me Via the email I used for this post I’ll send you log in credentials so you can check it out.
I LOVE the idea of this plugin’s functions and would really like to put it into service. Sadly its not working presently.
Richard
Blair Williams says
Okay, after looking at the setup on your site I believe that the issue has to do with either a plugin or a web host conflict. You have numerous security and caching mechanisms (BPS Security, Better WP Security, CloudFlare, W3 Total Cache … to name a few) in place … WP Login Protector hasn’t been tested with all of these and assumes a pretty standard .htaccess configuration and caching setup. I did find, however, that the post protection in WP Login Protector *does* appear to work just fine with your setup … so at the very least, you can turn that on … otherwise you may have to disable some of these other plugins to see what the culprit is.
Richard says
Blair
Thanks for the info. I’m very sensitive to security and always want to implement every possible measure to eliminate the potential for hacking / brute force attacks. This is the reason that I’m so interested in WP Login Protector.
Hopefully WP Login Protector will mature to fully work with the other security plugins out there.
Richard
Blair Williams says
Haha … that probably won’t happen. WP Login Protector is, by design, an exceptionally lightweight plugin. I don’t plan on expanding it too much (other than patches that become necessary over time).
The plugins you’re running are much more complex … and some of them (which I have seen in the wild) will have you significantly change your .htaccess file and can alter the way WordPress behaves at a fundamental level. Frankly, I was surprised (and a bit impressed) to see your site working at all … no offense … I’d just expect that you’d have massive conflicts running all those heavy security plugins simultaneously (for example, I wouldn’t expect my plugin MemberPress to work alongside another membership plugin). However I’m not sure that this is your problem running this plugin … It appeared that your requests were being proxied (perhaps through cloudflare?) … I’m pretty sure that’s the reason the HTTP filtering doesn’t work … and possibly why the Basic Auth doesn’t work with the plugin for you.
I’m sorry the plugin didn’t work for you though … as I said above, it has been tested in a fairly standard WordPress environment. I can’t guarantee that it will work with every theme, plugin or hosting configuration in the world. But I can say that this plugin is a lightweight, clean and effective approach to preventing a brute force attack for the majority of WordPress websites out there…
Alex Miller says
Personally, I also like to add this to the bottom of the plugin (before the redirect function though) so that it saves on some server overhead (admittedly, not much). Of course you can never have a username “admin” but why would you when it’s the most common tried username?
// Disallow All ‘admin’ users
function no_admin( $user, $username, $password ) {
if($username == ‘admin’)
wlp_forbidden();
return $user;
}
add_filter(‘authenticate’, ‘no_admin’, 30, 3);
HowdyMcGee says
I was running into problems with “Password Protected” posts in wordpress where it would hit this plugin and return a 403. I added this to the bottom of the plugin and it seems to work fine now:
function wlp_forbidden() {
if(!post_password_required()){
header(“HTTP/1.0 403 Forbidden”);
exit;
}
}
Robert Dempsey says
Will this work on wp 3.8 as well Blair? I have not tested it there as yet. Wondering if you have as yet?
Lazy Admin says
Being the lazy admin that I am, and I like the WP Repository, are you planning on getting your plugin added to it any time soon?
Erich Senft says
Hello Blair,
First f all I’d like to thank you for this wonderful plugin. Unfortunately, I’ve managed to lock myself out of my main site after I activated all 3 levels, and then inadvertently changed the admin password with Lastpass. It won’t let me do a password reset as the extra login panel keeps popping up as soon as I click the lost password link. Not quite sure how to get myself out of this pickle, any advice would surely be appreciated. If it’s not possible, I think this would probably be a good time to go back to a flat html site again!
Thank you and best regards,
-Erich
salihu says
I have had many of these kinds of attacks on my wp sites and it is extremely frustrating. I’m deploying this asap. Thanks a lot.
Dudeski says
While this Plugin is great, I just wish the ‘Basic Authentication’ worked. I enable it and try to log out to test it and it prompts me for username / password, no big deal except that it never really authenticates. I’ll user the correct username / password but it never evaluates to true. At first I thought it was my plugins or my theme but even when I try a fresh install with Twenty Thirteen theme it still has the same negative result.