I hate visitors who just cannot use web sites for what they were intended. My particular annoyance of the past few weeks is people trying to break into the administrative section of our WordPress installations. Why? I guess because it is something to do to prove themselves as idiots… oh, I meant hackers. It used to be once, maybe twice a day, that someone would bang on the wp-login.php page, and then grow bored. Then it became once or twice an hour and they would try 5 or 10 times and give up. Over the past several days, the volume increased exponentially to the point where it was obviously an automated login hack script. While no one was getting through, the server performance took a serious hit each time someone did it until earlier this evening when the load resembled a DoS (Denial of Service) attack. With the help of our service provider, Liquid Web, we kept the server up and running.
Serious acts like these require serious action on our part. I reviewed the potential options:
- change from WordPress to another CMS
- rename the wp-login.php file to something secret
- move the wp-login.php file to another directory
- move the wp-login.php file to a secured directory
- find a plug-in to remedy the situation
Option 1 is unacceptable because we love WordPress. Option 2, while it seems simple enough, is not viable because it involves changing the WordPress code base and any reference to that file name which is frequent. Every time an update is made to WordPress, I would have to make the same changes, all making further problems if a change is not 100% correct. Options 3 and 4 are unacceptable for the same reasons, too. So, I started to look through the plug-ins directory to see what, if anything, had been written to remedy this. I found several that mechanically do what options 2, 3, and 4 do. This is unacceptable since if the developer decides to move on, get lazy, or, sadly, get sloppy, errors are introduced. More plug-ins alert, disallow, and dissuade, but all require some manual effort to truly correct the problem (i.e. blacklist IP addresses). So I put my thinking cap on and headed to Google, searching for some way to disallow access to only one page in a directory of many files.
I found a solution that required only a few lines in the .htaccess file which is used by the Apache web server. There is already in place on each instance of WordPress since we use mod-rewrite to pretty up the URLs within the WordPress instance. It involves using the FilesMatch directive. The code fragment in .htaccess looks like this:
ErrorDocument 403 http://...where to send them to... <FilesMatch "wp-login.php"> Order Deny,Allow Deny from All Allow from ...list of IP address(es) </FilesMatch>
The first line (ErrorDocument) defines where to send the visitor to if they fail the security check below there. If the file matches the expression after FilesMatch, I first deny all visitors while allowing any from a list of IP addresses. Granted, this limits me to working from home and other fixed private addresses that are hard-coded, but, since I have shell access from anywhere, I simply go in and remove the check temporarily so I can get signed on. After doing that, I sign in and then flip it back to nornal. Reminder, the true security is whether or not the person has the correct credentials (ID and password) from WordPress. This does not improve upon an already secured process, simply eliminates access to the sign-on page.
While this works for now, I am still researching other options. Please leave a comment if you have any good ideas!
An additional thought: In order to make search engines realize you don’t want that file picked up and farmed, you need to make sure of two things:
- Remove the login link from your sidebar and elsewhere. If they are scanning for links to farm, they will find it.
- Make sure that your sitemap.xml file does not have an entry for it. If you are using Arne Brachhold’s Google XML Sitemaps plug-in, you are fine.
I discovered this tonight when I saw a harvester coming through the web site and the 2nd page it swept up was that one!