Even Easier Brute-force Login Protection for Wordpress

Here’s another *easy* way to help with those pesky wordpress brute-force logins we have been hearing about.  Most automated attacks make a lot of assumptions.  Like where your blog’s login page is located, and what information is needed to login via that page.  It’s really easy to take those assumptions and make them wrong.  The trick is doing it in a way that doesn’t mess up your real users, and can be done without modifying source code. I am writing this for the much-outdated Apache 2.2, since that’s what my server is running.  The 2.4 version can easily (and more elegantly I might add) do the same thing, but uses different modules.  This example uses only mod_rewrite and mod_usertrack, which should make the scope a little wider, since it’s something that many users will be able to implement in a .htaccess file. So, this is so laughably simple to setup (only 7 lines in the config file!) that you might think it’s useless (and in a week or two it could be,) but the simple truth is most brute-force hacking tools can’t do a lot of things that a real web-browser does all the time.  Like follow 302 redirects, and use session cookies.  It’s very easy to do this with Apache in a way that doesn’t break the login process for normal users, but will trip up many automated attack tools. So the premise is this, if requests are being generated by a real user that user will likely visit via a link (or maybe even a saved bookmark) to the login page, they will fill out a form, and then submit it.  If it’s an attack script, it’s likely got the POST target hard-coded.  So here’s an easy way to deal with that.
  1. When a request comes into the login page, check if there is a session setup for it.
  2. If the session is valid, process the request.
  3. If it isn’t, perform a 302 redirect to a (rewritten) version of the login page that will set the session.  (Discarding, and ignoring the POST form data in the case of a login attempt!)
It’s really that simple.  Of course there are some gotchas … the session data (either name or value) should be hard to guess without following the 302, and setting the actual cookie, and the URL that sets the session should also be unique to the site.  Unfortunately, mod_usertrack wasn’t built for this, and the session payload is a fixed value (mod_session in 2.4 offers much better options.)  So to do this without any external components to Apache 2.2, I decided that a unique cookie name is good enough.
(session-redirect.apacheconf) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  RewriteEngine On
   # This can be placed within your conf file for apache or possible a .htaccess
   #	It performs some very rudimentary session-based redirection that breaks 
   #	automated login attack scripts that don't handle redirects and session tracking.
   #
   # If this cookie isn't set, then redirect to a (rewritten) version of the login page that sets the cookie.
   #   This will short-circuit automated posts, and force an attacker to perform session tracking.
   #   It's also possible to use mod_security to track these values.
   #
   # Sorry, I used to generate random values as I served this from my server, but I moving away from
   # 	a static site :(
   #
   RewriteCond %{HTTP_COOKIE} !ac8bf83d1adc0471b7d4c593
   #         Change this value ^^^^^^^^^^^^^^^^^^^^^^^^
   RewriteRule /wp-login.php /wordpress-login-63e40526.php [R,L]
   #                        Change this value ^^^^^^^^
   <Location /wordpress-login-63e40526.php>
   #  Change to same as above ^^^^^^^^
	   CookieTracking on
	   CookieExpires 30
	   CookieName ac8bf83d1adc0471b7d4c593
   #    same as first ^^^^^^^^^^^^^^^^^^^^^^^^
   </Location>
   RewriteRule /wordpress-login-63e40526.php /wp-login.php [NE]
   #  yes, one more time        ^^^^^^^^
I can already hear your thoughts … but that doesn’t validate anything!  True, but if you really want you can do that through by adding on mod_security’s session tracking on top of the above measures.  See here and here for more on that.