In recent days, many tech blogs have written about a distributed attack targeting WordPress and other content management systems. This brute-force attack focuses on compromising sites that use the admin user account. The attack is notable for its scale, as many hosts have seen reported degraded performance resulting from it.
There are plugin solutions, such as Limit Login Attempts, that can mitigate the effectiveness of this attack, but I wanted a solution that didn’t let the flood of attempts ever reach my server’s PHP processor. On this approach, there are numerous tutorials that recommend restricting access to wp-login.php
and the entire wp-admin
directory. This approach is problematic because WordPress’ Ajax endpoint exists within the wp-admin
directory, so it must be publicly accessible for many themes and plugins to function properly.
Since this latest attack targets wp-login.php
, I opted to place that file behind basic access authentication by modifying my server’s nginx configuration. This is a single-user site, so I don’t need to worry about managing users at both the server and WP levels.
location ~* /wp-login.php {
auth_basic "erick t. hitter WordPress Network Login";
auth_basic_user_file PATH_TO_AUTH_FILE;
PHP_CONFIGURATION
}
The ~*
tells nginx to match all requests for wp-login.php
regardless of casing (WP-LOGIN.php
, WP-login.php
, etc.), and also without regard to the directory the request was made to. I took this approach because my access logs revealed many requests to wp-login.php
in directories that didn’t exist, likely the bots’ attempt to uncover all possible locations for the file.
In the above example, PHP_CONFIGURATION
is replaced with whatever directives your configuration needs to pass PHP requests to the processor; in my case, I’m using PHP-FPM, and those settings appear there. It is necessary to redeclare these configuration settings within this new location
block since the existing declarations won’t be applied to requests handled by this new location
block.
Beyond ensuring that the Ajax endpoint is accessible, protecting only wp-login.php
also restricts this extra security step to login requests alone. Once I’ve logged in, and for as long as I remain logged in, I’m not prompted to provide the HTTP authentication credentials again. In other words, additional security without too great an annoyance for me.
To be clear, this change constitutes just one element of the login protections employed on my multisite network. The admin user doesn’t exist, I use a very strong password, and I’ve enabled a two-factor authentication plugin.
What are you doing to ensure your WordPress setup isn’t compromised by this latest attack?
Reference: http://arstechnica.com/security/2013/04/huge-attack-on-wordpress-sites-could-spawn-never-before-seen-super-botnet/