Securing WordPress from Brute Force Attacks by Country Blocking on Nginx
After having looked after a number of WordPress websites over the last 7 years or so it has become apparent that the number of brute force attacks specifically targeting WordPress is increasing. I know it isn’t a matter of if one of these attacks succeeded but when. This tutorial won’t completely get rid of all brute force attacks, but it should reduce them quite a lot.
As a totally unscientific observation I was going from around 10,000 attempted logons a day, to only a couple of dozens actually getting as far as authenticating. All this without inconveniencing either myself or my customers!
This tutorial will walk you through creating a geographical block on countries you don’t want to have access to your wp-login sections. You will need to be running Nginx and have SSH access. We won’t be using GeoIP but we will be using local config files. These instruction written for Ubuntu Server 14.04 and should work fine for any other distribution. We will be actively protecting the wp-login.php page with some filters.
Please bear in mind that this tutorial is very much part of a defense in depth approach and you should still have decent passwords and other protection mechanisms in place.
SSH onto your server as usual.
Lets start with some housekeeping, we will back up our existing configurations so if it comes to it then we can roll back our config.
mkdir /root/wordpress-backup/
cp /etc/nginx/sites-enabled/* /root/wordpress-backup/
We have a single dependancy we’ll need, make sure it’s installed:
apt-get install unzip
Now lets create the directory where our country IP lists will live:
mkdir /etc/nginx/country-lists/
cd /etc/nginx/country-lists/
Download the country lists and uncompress them:
wget http://firewalliplists.gypthecat.com/lists/nginx/nginx-countries.conf.zip
unzip nginx-countries.conf.zip
Now edit your sites config:
nano /etc/nginx/sites-enabled/[your config here]
What you’ll have to decide is which country or countries you want to allow from, and then we’ll be denying the rest.
What we are wanting to do is split down the php part of our config, the default one which comes with Nginx looks like this:
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
#
# # With php5-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# # With php5-fpm:
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
Change it so it looks like this and include the appropriate countries for your requirements:
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
location ~* wp\-login\.php {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
include country-lists/CA-allow.conf; #Allow Canada
include country-lists/AU-allow.conf; #Allow Australia
deny all; #If the country isn’t allowed block the rest
}
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
#
# # With php5-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# # With php5-fpm:
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
Now, lets test that the configuration as as we’d expect:
nginx -t
And you should hopefully get something like the following:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
If it does look like that you’re good to go! Give Nginx a restart:
service nginx restart
And now all your logons should be more protected.
In a couple of days (or even minutes depending on how attacked your site is!) run the command below to see your brute force protection at work:
grep 'wp-login.php' /var/log/nginx/access.log
Hopefully you’ll see lines which look like this:
213.[redacted].[redacted].105 - - [11/Jul/2015:08:05:32 +0000] "POST /wp-login.php HTTP/1.1" 503 221 "-" "-"
The 503 on that line tells us that specific brute forcer is getting denied when they’re trying to logon, which is exactly what we want!
3 Comments
Well, recently Brute force Attacks has immensely increased, becoming a dangerous factor for all WordPress users, but it is a thing, which is fight-able, I mean, by using security methods, we can move brute force attacks out of the window. Although, it can be difficult for newbies, who just got started with WordPress, but he/she can learn by reading posts online and then can implement security.
In my view, implementing only three tricks works very well, Changing Login Slug, A content Delivery network (CDN) and a Security Plugin, which bans IP address after a few Login attempts.
Thanks for commenting, I agree entirely that you certainly need multiple methods to secure your sites. GeoIP blocking I see very much as a defence in depth approach. Also another one I’ve had massive benefit from is either two factor on authentication or even a simple captcha instead. Gyp
Thanks for the information. How do you stop xmlrpc attack? Recently, I have been a victim of it and learned that it is enabled by default in WordPress. For a safety, I am using limit login plugin but I am not sure how good this plugin is