Block wp-login.php bruteforce attack

on
Site icon rtCamp

Block wp-login.php bruteforce attack

dynamic-social-image

Last night, a site in our managed-hosting network was under attack.

Following config thwarted the bruteforce attack successfully using Nginx’s Limit Req Module.

Nginx Settings

Global Settings

In /etc/nginx/nginx.conf file under http{..} block, add following

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

10m is size of zone. 1MB can hold 16000 states. I think this means 16000 unique IP addresses. In case you have way too many sites or very high traffic sites, you may want to increase it to 20MB or 100MB.

1r/s means 1 request per second is allowed. You cannot specify fractions. If you want to slowdown further, means less requests per second try 30r/m which means 30 requests per min, effectively 1 request per 2 second.

Per Site Setting

You can add something like below to server{..} block:

location = /wp-login.php {
    limit_req   zone=one  burst=1 nodelay;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
}

OR

location ~ \.php$ {
    location ~* wp\-login\.php {
        limit_req   zone=one  burst=1 nodelay;
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
    }
    #other rules
}

nodelay makes sure as soon as request limit exceeds, HTTP status code 503 (Service Unavailable) is returned.

Protecting other areas

On same lines you can protect other area as well. e.g. your contact form.

If you have contact form on every page, then may be you can add location of form’s action handler URL.

Other Changes

In case you want to return 444 (recommended) or any other code use following in http {..} block for global effect or with location {..} block for local-effect:

limit_req_status 444;

You can server custom error page using error_page directive.

Test

Logs

Use following command to monitor logs. Replace 503 with any other error code if you are using limit_req_status

tail -f /var/www/example.com/logs/*.log | egrep "login|503"

If your site is already under attack, you will see lines like below:

2013/08/23 04:17:03 [error] 256554#0: *99927 limiting requests, excess: 1.852 by zone "one", client: 1.2.3.4, server: example.com, request: "GET /wp-login.php HTTP/1.0", host: "exmaple.com"

1.2.3.4  is blocked IP.

Simulate Attack

You can use apache-bench to attack server:

ab -n 100 -c 10 example.com/wp-login.php

Other Notes

Whitelisting IP addresses

For wp-login example in this article you won’t need whitelisting as a real-human has no business to send multiple requests to wp-login.php at any moment.

Still, for some other purpose you may need to whitelist IP addresses.

In /etc/nginx/nginx.conf file under http{..} block, add a map{..} block like below:

map $remote_addr $rt_filtered_ip {
        default $binary_remote_addr;
        1.2.3.4 "";
        4.4.4.4 "";
}

1.2.3.4 and 4.4.4.4 are example of whitelisted IP’s. You can have any number of them. Add every IP on separate line. Make sure you use “” in second column for every IP. rate limit module ignores empty values.

Then you need to use variable $rt_filtered_ip

limit_req_zone $rt_filtered_ip zone=one:10m rate=1r/s;

Above simple method may not work if you want to whitelist a range of IP’s. For which you need to geo module.

geo $rt_filtered_ip {
    default        $binary_remote_addr;

    127.0.0.1      "";
    192.168.1.0/24 "";
    10.1.0.0/16    "";

    ::1            "";
    2001:0db8::/32 "";

    1.2.3.4        ""
}

Important: We haven’t tested geo-module example. So use at your risk.


Exit mobile version