Limiting the number of password attempts in the login form using Nginx or HAProxy using WordPress as an example

    Let's look at an example of WordPress as a way to enhance security by limiting the number of HTTP requests to the password form. This will protect the published blog from brute force (searching and breaking the password by sorting out all theoretically possible options from a specific character set or matching common passwords from the dictionary). This method, in principle, can be used to protect other web applications.

    The task can be implemented in Nginx using the ngx_http_limit_req_module [ 1 ] module , which acts as a front-end to Apache or the FastCGI web server, or using HAProxy [ 2 , 3 ], which acts as a load balancer in front of web servers.

    In both cases, the algorithm is as follows. During authentication, the browser accesses the address containing the substring "/wp-login.php". It is necessary to track it and limit the number of requests from one IP without affecting calls to all other addresses. Blocking parameters must be selected in such a way as not to inconvenience ordinary users. You should especially configure blocking when a large number of users from one IP address use the authorization form.

    Method number 1: Nginx

    configuration file is fixed on the advice from the comments. Thanks to VBart and J_o_k_e_R !

    http {
         <...>
         limit_req_zone $binary_remote_addr zone=login:10m  rate=15r/m;
         server {
              listen      80;
              server_name  frontend.example.org;
         location ~* /wp-login.php {
              limit_req  zone=login burst=4;
              proxy_pass        http://backend:8080;
              <...>
         }
         location / {
              proxy_pass        http://backend:8080;
              <...>
         }
    }
    

    Blocking parameters:

    limit_req_zone $ binary_remote_addr zone = login: 10m rate = 15r / m; Sets the parameters of the shared memory zone, which stores the state for different IP addresses. In our case, the states are stored in the “login” zone of 10 megabytes in size, and the average request processing speed for this zone cannot exceed 15 requests per minute. Processing speed can be set in requests per second (r / s) or in requests per minute (r / m).

    limit_req zone = login burst = 4;sets the login zone and the maximum size of the burst of requests (burst). If the speed of receipt of requests exceeds that described in the zone, then their processing is delayed so that requests are processed at a given speed. Excessive requests are delayed until their number exceeds the maximum burst size. If exceeded, the request ends with error 503.

    Method number 2: HAProxy

    In the backend section serving our blog, add the following lines [ 2 ]:
    tcp-request inspect-delay 10s
    tcp-request content accept if HTTP
    # brute force protection
    acl wp_login path_beg -i /wp-login.php
    stick-table type binary len 20 size 500 store http_req_rate(20s) peers local
    tcp-request content track-sc2 base32+src if METH_POST wp_login
    stick store-request base32+src if METH_POST wp_login
    acl bruteforce_detection sc2_http_req_rate gt 5
    acl flag_bruteforce sc1_inc_gpc0 gt 0
    http-request deny if bruteforce_detection flag_bruteforce
    

    When a POST request is found to the /wp-login.php page, a hash of three elements is saved: the HTTP Host header, the URL path, and the source IP. The user identified by the hash will be able to make five requests in 20 seconds; the sixth request will be blocked.

    Literature
    1. Ngx_http_limit_req_module module - nginx.org
    2. wordpress CMS brute force protection with HAProxy - blog.haproxy.com
    3. Better Rate Limiting For All with HAProxy - blog.serverfault.com

    Also popular now: