There is no two ways about it: having your server compromised sucks. Seeing your website defaced or infected with malicious scripts feels like a punch in the gut. Did you know that modern brute force tools can test millions of passwords per second? It takes around 15 minutes to crack an average password (eight symbols in length, consisting of mixed-case letters, numbers, and special symbols). Is there anything you can do to protect yourself?
Luckily, the answer is yes. Plesk 12 comes with a comprehensive set of security tools.We have got the ModSecurity support to protect web applications, and the automatic security hardening for WordPress. But today I would like to tell you about a different tool called Fail2ban. Fail2ban is effective against brute force attacks, and can be used to protect any service running on your server.
Here is how Fail2ban works:
- Fail2ban constantly monitors logs of the services it protects, matching every new log entry against a pre-defined set of rules.
- Once a suspicious entry is found in a log, Fail2ban notes the IP of the potential attacker and starts counting. Every time the IP performs suspicious activity, Fail2ban adds one to the counter.
- Once a pre-defined number of attempts is reached, Fail2ban can do two things:
- Send an email notification, and/or
- Ban the attacker’s IP for a pre-defined length of time.
In this article we will give step-by-step instructions illustrating how you can use Fail2ban to protect your WordPress installation from brute force attacks. To do so, we will need to follow these steps:
- Create a filter, which is a set of one or more regular expressions. The filter is used to search the logs for suspicious activity.
- Create a jail, which is a set of rules covering an individual scenario. The settings of the jail determine what is to be done once an attack is detected.
Step 1: Creating the filter.
To create a filter for WordPress, go to Tools & Settings > IP Address Banning (Fail2Ban), open the Jails tab, and click Manage filters > Add Filter. Give the filter a name, and paste the following into the Content field:
[Definition] failregex = ^<HOST> .* "POST .*wp-login.php HTTP/.*" 200 ignoreregex =
so that it looks like this:
As you can see, the filter contains a single regular expression, and it will trigger every time the WordPress login page is loaded – for example, after a failed authentication attempt.
Step 2: Creating the jail
To create the jail, return to the Jails tab and click Add Jail. Start by naming your jail and selecting the filter you have just created from the Filter menu. Once you are done, it is time to add the most important component of the jail – the actions.
Actions define what happens when a jail is activated. There are four preconfigured actions in Fail2ban:
- Ban the attacker on a single port.
- Ban the attacker on multiple ports.
- Ban the attacker on all ports.
- Send a notification email to a specified email address.
To add an action, select it from the Action menu and click Add. You can add any number of actions to a jail. You may need to customize the action to suit your needs (for example, to provide the desired mail address to send notifications to, or to specify what ports should be closed to the offending IP).
Once the actions are configured, you need to specify one or more log files Fail2ban will check for the signs of an attack – those go in the Log path field. To protect a specific WordPress installation, specify the path to its Apache access log files, found at:
/var/www/vhosts/<WordPress installation domain name>/logs/access_log
and
/var/www/vhosts/<WordPress installation domain name>/logs/access_ssl_log
You can specify more than a single log to protect multiple WordPress installations. Alternatively, you can use the * mask to protect all of them, like this:
/var/www/vhosts/*/logs/access_*log
Finally, there are two optional parameters you can set: the maximum number of failed login attempts and the IP address ban period. The first is the number of “strikes”, unsuccessful login attempts, leading to a ban; the second is the length of the resulting ban in seconds. For example, if you set the value of the first parameter to 3, and the second to 300, after a third unsuccessful login attempt the jail will trigger and ban the attacker for five minutes. If these values are left undefined for a jail, server-level Fail2ban settings are used.
You can see an example of a fully configured jail on the screenshot below:
Note that jails are created on a per-service basis (as in, one for SSH, one for SMTP etc.), but there can be multiple jails for a single service, covering different scenarios.
Once the jail is created, all that remains is to enable Fail2ban:
1. Go to Tools & Settings > Services Management and make sure that the IP Address Banning (Fail2ban) service is running.
2. Go to Tools & Settings > IP Address Banning (Fail2Ban), open the Settings tab and select the Enable intrusion detection checkbox.
3. Finally, open the Banned IP Addresses tab and click Switch On IP Address Banning.
Step 3: Action!
Now it is the time to test Fail2ban to make sure its protection works (let us assume that the settings of your jail match those on the screenshot above). Open the login page of your WordPress install and try logging in with incorrect login and/or password. Then do it again. And one more time for good measure. If you have set up everything correctly, you will not get another chance – the jail you created will activate and ban you for five minutes. And here is what was happening “under the hood” in the meantime:
- You try authenticating with incorrect credentials for the first time. The “POST /wp-login.php HTTP/1.0″ entry gets written to the Apache access log. As Fail2ban monitors this log, and the entry matches the regular expression defined in the filter, Fail2ban notices the authentication attempt and starts counting. Okay, maybe you mistyped your password. Mistakes happen.
- You try authenticating for the second time. Same as above, only the counter is now at two. This is getting suspicious, but Fail2ban gives you one more chance.
- You try authenticating for the third time. Okay, now this is getting downright fishy. Three strikes, you are out! Fail2ban creates a temporary rule in the iptables barring you from accessing the server and sends a notification to “[email protected]”.
If you do not actually get banned, it means that there is a misconfiguration somewhere. Here are some troubleshooting steps that may help:
- Make sure that the Fail2ban service is running, that intrusion detection is enabled, and that IP banning is turned on, as described above.
- Make sure that the jail is activated (by the way, all newly created jails are activated by default).
- Make sure that the filter you created actually catches the relevant log entries with the fail2ban-regex command.
The syntax of fail2ban-regex is as follows:
fail2ban-regex <path to the access_log file> /etc/fail2ban/filter.d/<filter name>
Look for the Failregex value in the output. If it is zero, the filter is configured incorrectly.
Naturally, Fail2ban can be used to protect any service on the server, not just WordPress. Using the examples provided above as reference, you can create custom filters and jails to fit your scenario.
Further information about Fail2ban is available here:
Fail2ban documentation:
http://www.fail2ban.org/wiki/index.php/MANUAL_0_8
Plesk documentation:
http://download1.parallels.com/Plesk/PP12/12.0/Doc/en-US/online/plesk-administrator-guide/73381.htm
Ref. devblog.plesk.com
Protecting your wordpress installations with fail2ban in Plesk 12
Good luck !
Comments from devblog.plesk.com website 🙂
9 Comments to “Protecting Your WordPress Installations With Fail2ban”
-
Hi,
Great to see this getting promoted – we’ve been using Fail2Ban for WP logins for a while now.
However, there is an issue with your suggested filter regex – that will catch ALL posts to wp-login.php, not just failed logins. Apache will return a 200 code on failed login and a 302 on success, so the filter regex should be:
failregex = .*] “POST /wp-login.php HTTP/.*” 200
Note that this will only work for WP installations in the webroot. I’m not sure how to adapt the regex to allow for installations in a subdirectory. By default, the Plesk Application installer installs WordPress into a subdirectory /wordpress (which is really annoying!).
Also, regarding the log path, your suggestion will only catch non-SSL WP logins, to allow for both SSL and non-SSL you would need to use “access*_log”.
We use this log path to track ALL Plesk domains, both SSL and non-SSL (on CentOS 6):
logpath = /var/www/vhosts/system/*/logs/access*_log
Hope that helps.
-
Correction … it would be pretty simple to modify the filter regex to accommodate for WordPress installations in a subdirectory — using a wildcard — but the performance hit would be too great to justify it.
-
Thanks for the comment, Gavin.
Truth be told, the article was meant to give a brief overview of Fail2ban and its capabilities rather than provide comprehensive instructions. Good catch about the HTTP status code and the need to parse both access_log and the access_ssl_log though! As for the regular expression, we will discuss it internally and hopefully come up with a solution (which we will be sure to post in the comments).-
We have run a few tests, and it looks like the following regular expression does an admirable job of protecting WordPress installations in subdirectories:
failregex = ^ .* “POST .*wp-login.php HTTP/.*” 200
I updated the article taking your feedback into account – thanks again for sharing!
-
Hi again,
Great, glad to help.
I just realised we’re not matching in the failregex, as you are — is there any actual need or benefit in matching the in the regex? (Ours seems to work fine without it).
Thanks for the wildcard tip.
-
The way I understand it, there are no hard and fast rules for writing regular expressions (other than those governing the syntax, obviously). So I see no problem with your failregexp differing from the one we used – as long as it works, I reckon you’re fine.
-
Just realised that the < and > tags are being stripped out. I do have the <HOST> in my regex. Silly me.
-
-
-
-
> By default, the Plesk Application installer installs WordPress into a subdirectory /wordpress (which is really annoying!).
Since Plesk 12.1 first app will be installed into webroot by default.-
Great news! Thanks.
-
-