Table of Contents

WordPress 'brute force attack protection built in to LSWS

A ‘brute force’ login attack is a type of attack against a website to gain access to the site by guessing the username and password, over and over again. WordPress is the most popular CMS and therefore it’s a frequent target of these type of attacks. wp-login.php and xmlrpc.php pages are the most common target from brute force attack by POST method. WordPress doesn’t have any built in protection to prevent these types of attacks, hence you may need to find some third-party solutions.

Starting with version 5.2.3 of LSWS, LSWS has a built-in WordPress brute force attack protection system. It will protect shared hosting WordPress environments from large-scale DDoS attacks, which may bring down entire servers.

How Brute Force Protection works

The newly introduced WordPress Protection directive is: WordPressProtect (0|1|5-1000)

This directive can be placed in Apache configuration or .htaccess.

The above values specify the maximum numberwp-login.php and xmlrpc.php pages attempts allowed within 5 minutes before the IP is blocked.

This limit is handled using a quota system where limit = quota. Each POST attempt will decrease the quota by 1 with the quota increasing back to the set limit over time. The IP will be throttled starting at half of the limit, slowing more as the quota drops further. When the quota reached 0, the IP is blocked.

How to enable LSWS WordPressProtect feature on cPanel

As long as LSWS version is 5.2.3 or above, LSWS WordPressProtect feature is enabled by default and does not need any extra configuration in the LSWS WebAdmin GUI or in Apache configurations.

One may want to overwrite it on the server level, virtual host level or even the .htaccess level. What 's the logic behind it?

Setting it on Apache server level configuration will override the setting for Apache based virtual host, but there is no impact on LSWS native virtual host, which can only be controlled by LSWS native settings.

Setting it on Apache virtual host level configuration will override server level configuration as well as .htaccess level of configuration, which means server administrator's virtual host setting will override end user's setting in .htaccess.

Let 's look at some examples for WHM/cpanel EA4 environment:

After you run the following, WordPressProtect feature will be enabled globaly automatically:

/usr/local/lsws/admin/misc/lsup.sh -f -v 5.2.3 (or above version)

You may want to overide the default limit 10 to other value, such as 5. Then you will need to set it in server level of apache configuration file:

vi /etc/apache2/conf.d/includes/pre_main_global.conf

and add:

<IfModule Litespeed>
WordPressProtect 5
</IfModule>

which will set the limit to 5 for all virtual hosts.

You can also disable it globally as:

<IfModule Litespeed>
WordPressProtect 0
</IfModule>

No matter how the server level set, end user has ability to enable or disable it through .htaccess by placing the following:

<IfModule Litespeed>
WordPressProtect 15
</IfModule>

or

<IfModule Litespeed>
WordPressProtect 0
</IfModule>

However, as far as virtual host level setting is set(disabled or enabled), such as for http and domain examle.com, the feature is disabled in virtual host level include file, then directives in .htaccess will not have any effect anymore.

cd /etc/apache2/conf.d/userdata/std/2_4/$USER/example.com/
vi wordpress.conf
<IfModule Litespeed>
WordPressProtect 0
</IfModule>

To verify and check how server and virtual host level set, you may run the following command:

cd /etc/apache2/
grep -i -r wordpressprotect *

The design logic looks like the following:

Server Level VHost Level .htaccess Result
5xx5
5x2020
510x10
5102010

Real Testing

This test was conducted with WordPressProtect set to 10. We can see the time start to increase at Round 6 and finally get a connection error at Round 11.

Round:  1  Fail 0.626
Round:  2  Fail 0.615
Round:  3  Fail 0.605
Round:  4  Fail 0.581
Round:  5  Fail 0.595
Round:  6  Fail 1.619
Round:  7  Fail 2.615
Round:  8  Fail 3.611
Round:  9  Fail 4.602
Round:  10 Fail 5.604
Round:  11 Erro MSG:  ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response',))