Блокировка IP на MITIGATOR с Nginx и fail2ban
Описана настройка следующей схемы защиты web-сервера:
- Nginx модулем
ngx_http_limit_reqвыявляет превышение лимита запросов; - fail2ban анализирует
error.log, куда Nginx пишет о превышениях; - IP добавляется в список заблокированных через MITIGATOR API.
Клиент MITIGATOR API
Имеется скрипт mitigator.py (скачать)
для управления MITIGATOR, в частности, для временной блокировки IP-адреса
через MITIGATOR API. При необходимости скрипт можно доработать самостоятельно
для совершения любых других действий на MITIGATOR. Скрипт использует только
стандартные модули, работает с Python 2.7+ и Python 3.
Для запуска скрипта нужна учетная запись MITIGATOR и ID политики защиты
(например, 42 в URL .../policies/42 при заходе на MITIGATOR).
Также скрипт принимает IP и время блокировки в секундах.
Описание всех параметров печатается с ключом --help (-h).
Настройка Nginx
Модуль ngx_http_limit_req встроен в Nginx и позволяет ограничить количество
запросов в секунду (RPS) через конфигурацию Nginx.
Лимит на запросы относится к зоне (zone). Обычно зоной является IP клиента (то есть ограничиваются запросы от него) или URI на сайте (ограничиваются запросы к нему), но возможны и более сложные комбинации параметров запроса.
Зоны описываются в контексте http. Опишем зону perip (per IP), способную
отслеживать превышение лимита в 10 RPS для любого из 10 млн. IP-адресов.
Для этого в добавим в /etc/nginx.conf через промежуточный файл строку:
mkdir -p /etc/nginx/nginx.conf.d
cat > /etc/nginx/conf.d/limit-req.conf <<'END'
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;
ENDЧтобы применить этот лимит к части сайта (контекст location), то есть
не позволять обращаться с одного IP к странице более 10 раз в секунду,
используется следующая директива в /etc/nginx/sites-available/default
(если ограничиваются запросы для сайта по умолчанию):
server {
...
location / {
...
limit_req zone=perip burst=20 nodelay;
}
}Здесь burst=20 позволяет всплески активности до 20 RPS (но в среднем
не более 10 RPS, как описано для зоны), а nodelay означает, что запросы
сверх лимита сбрасываются, а не ожидают своей очереди (актуально при DDoS).
Обновим конфигурацию Nginx:
nginx -s reloadКогда лимит превышается, в error.log появляются строки такого вида:
2019/01/11 09:27:12 [error] 155#155: *142 limiting requests, excess: 20.200 by zone "perip", client: 10.0.1.254, server: _, request: "GET / HTTP/1.1", host: "10.0.2.254"Настройка fail2ban
Утилита fail2ban анализирует логи и при обнаружении в них заданных признаков выполняет действия по блокировке. Также fail2ban позволяет управлять списками заблокированных адресов.
Разместим скрипт блокировки:
install mitigator.py /usr/local/binСоздадим новое действие fail2ban, которое будет вызывать скрипт:
cat >/etc/fail2ban/action.d/mitigator.conf <<'END'
[Definition]
actionban = \
/usr/local/bin/mitigator.py \
--server "<server>" \
--user "<user>" --password "<password>" \
--no-verify \
--policy <policy> \
tbl block --ip <ip> --time <bantime>
actionunban = \
/usr/local/bin/mitigator.py \
--server "<server>" \
--user "<user>" --password "<password>" \
--no-verify \
--policy <policy> \
tbl unblock --ip <ip>
ENDМетки <server>, <user>, <password>, <policy>, <ip> и <bantime>
нужно писать как есть — это параметры, которые при выполнении действия будут
автоматически заменены на правильные значения. Ключ --no-verify нужен, если
MITIGATOR работает с самоподписанным сертификатом, и необходимо отключить его
проверку.
Создадим ограничение (jail), которое будет блокировать IP по записям
в error.log:
cat >>/etc/fail2ban/jail.local <<END
[nginx-limit-req]
enabled = true
logpath = %(nginx_error_log)s
banaction = mitigator[server=mitigator.local, user=admin, password=admin, policy=42, bantime=600]
ENDМодуль nginx-limit-req поставляется с fail2ban и находит нужные строки.
В строке banaction=... указываются актуальные параметры действия: сервер,
имя пользователя, пароль, ID политики. Для примера время блокировки 10 минут.
Перезагрузим правила fail2ban:
fail2ban-client reloadПроверка работы
Трафик должен идти через MITIGATOR, должна быть включена общая защита и защита выбранной политики.
Имитировать атаку можно утилитой httperf:
httperf --server 192.0.2.20 --num-conn 100При успешной настройке через несколько секунд после запуска httperf
на сервере можно видеть, что fail2ban отработал:
$ fail2ban-client status nginx-limit-req
Status for the jail: nginx-limit-req
|- Filter
| |- Currently failed: 1
| |- Total failed: 65
| `- File list: /var/log/nginx/error.log
`- Actions
|- Currently banned: 1
|- Total banned: 1
`- Banned IP list: 192.0.2.10На MITIGATOR можно в карточке TBL политики проверить, что IP атакующего (192.0.2.10 в примере) находится в списке временно заблокированных.
Разблокировать IP можно как через MITIGATOR, так и через fail2ban:
fail2ban-client set nginx-limit-req unbanip 192.0.2.10Если какой-то IP блокировать через fail2ban не нужно, а добавлять его в «белый список» (WL или TWL) на MITIGATOR нежелательно, можно игнорировать IP на уровне fail2ban:
fail2ban-client set nginx-limit-req addignoreip 192.0.2.10Если fail2ban не отработал, ошибки можно наблюдать в его журнале:
tail -f /var/log/fail2ban/fail2ban.log