Рассмотрим на примере WordPress способ усиления безопасности при помощи ограничения количества HTTP-запросов к форме ввода пароля. Это позволит оградить опубликованный блог от брутфорса (поиска и взлома пароля путем перебора всех теоретически возможных вариантов из определенного набора символов или подбора по словарю распространенных паролей). Данный способ, в принципе, можно использовать и для защиты других веб-приложений.
Задача может быть реализована в Nginx с помощью модуля ngx_http_limit_req_module [1], выступающем в роли фронт-энда к Apache или веб-сервера FastCGI, или же с помощью HAProxy [2, 3], выступающем в роли балансировщика нагрузки перед веб-серверами.
В обоих случаях алгоритм работы следующий. При аутентификации браузер обращается по адресу, содержащему в себе подстроку "/wp-login.php". Необходимо отследить ее и ограничить количество запросов с одного IP не затрагивая обращения по всем остальным адресам. Параметры блокировки необходимо подобрать таким образом, чтобы не создавать неудобств обычным пользователями. Особенно внимательно следует настраивать блокировки в том случае, когда формой авторизации пользуется большое количество пользователей с одного IP-адреса.
Способ №1: Nginx
http {
<...>
limit_req_zone $binary_remote_addr zone=login:10m rate=15r/m;
server {
listen 80;
server_name frontend.example.org;
location / {
if ( $request_uri ~* /wp-login.php) {
return 405;
}
if ( $request_uri !~* /wp-login.php) {
return 406;
}
error_page 405 = @login;
error_page 406 = @data;
}
location @login {
limit_req zone=login burst=4;
proxy_pass http://backend:8080;
<...>
}
location @data {
proxy_pass http://backend:8080;
<...>
}
}
Параметры блокировки:
limit_req_zone $binary_remote_addr zone=login:10m rate=15r/m; Задаёт параметры зоны разделяемой памяти, которая хранит состояние для разных IP-адресов. В нашем случае состояния хранятся в зоне “login” размером 10 мегабайт, и средняя скорость обработки запросов для этой зоны не может превышать 15 запросов в минуту. Скорость обработки можно задать в запросах в секунду (r/s) или в запросах в минуту (r/m).
limit_req zone=login burst=4; устанавливает зону login и максимальный размер всплеска запросов (burst). Если скорость поступления запросов превышает описанную в зоне, то их обработка задерживается так, чтобы запросы обрабатывались с заданной скоростью. Избыточные запросы задерживаются до тех пор, пока их число не превысит максимальный размер всплеска. При превышении запрос завершается с ошибкой 503.
Способ №2: HAProxy
В секцию backend, обслуживающую наш блог, добавляем следующие строки [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
При обнаружении POST-запроса к к странице /wp-login.php сохраняется хэш из трех элементов: заголовка HTTP Host, URL-пути и IP источника. Идентифицируемый на основе хеша пользователь сможет сделать пять запросов за 20 секунд; шестой запрос будет заблокирован.
Литература
- Модуль ngx_http_limit_req_module — nginx.org
- wordpress CMS brute force protection with HAProxy — blog.haproxy.com
- Better Rate Limiting For All with HAProxy — blog.serverfault.com
Автор: foboss