nginx & fail2ban

Данная статья посвящена примитивной защите от DDoS-атак.

Примечание: видео материал можно посмотреть тут (Настраиваем fail2ban: защита от DoS и подбора паролей). Ниже изложен краткий конспект видео урока.

apt install fail2ban -y
apt install ipset -y

Примечание: ipset нам понадобиться ниже.

Делаем копию файла /etc/fail2ban/jail.conf jail.local, чтобы после обновления fail2ban настройки не «перетёрлись»:

cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Копия файла jail.local

Шаг 1.

Создаём блокировку для «частых запросов«в NGINX (подробнее об этом модуле тут).

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

server {
    ...
    limit_req zone=perip burst=5 nodelay;
}

Если скорость поступления запросов превышает описанную в зоне, то их обработка задерживается так, чтобы запросы обрабатывались с заданной скоростью. Избыточные запросы задерживаются до тех пор, пока их число не превысит максимальный размер всплеска. При превышении запрос завершается с ошибкой.

На примере выше указано: в среднем не более 1 запроса в секунду со всплеском не более 5 запросов (т.е. это некий буфер после наполнения, которого будет ошибка).

Примечание: 10m — это размер выделяемой памяти для хранения состояния.

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

В данном случае состояния хранятся в зоне “one” размером 10 мегабайт, и средняя скорость обработки запросов для этой зоны не может превышать 1 запроса в секунду.

В качестве ключа используется IP-адрес клиента. Обратите внимание, что вместо переменной $remote_addr используется переменная $binary_remote_addr. Длина значения переменной $binary_remote_addr всегда равна 4 байтам для IPv4-адресов или 16 байтам для IPv6-адресов. При этом размер состояния всегда равен 64 байтам на 32-битных платформах и 128 байтам на 64-битных платформах. В зоне размером 1 мегабайт может разместиться около 16 тысяч состояний размером 64 байта или около 8 тысяч состояний размером 128 байт.

При переполнении зоны удаляется наименее востребованное состояние. Если и это не позволяет создать новое состояние, запрос завершается с ошибкой.

Пример:

# файл конфига *.conf NGINX для сайта
limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s;

server {
    ...
    location /dev {
        ...
        limit_req zone=perip burst=5 nodelay;
    }
}

Если будет превышен указанный лимит, то в логах NGINX (/var/log/nginx/access.log) будут следующие строки:

...
10.10.6.100 - - [13/Oct/2022:03:51:12 +0000] "GET /dev/exists HTTP/1.1" 503 197 "-" "PostmanRuntime/7.29.2" "-"
10.10.6.100 - - [13/Oct/2022:03:51:13 +0000] "GET /dev/exists HTTP/1.1" 503 197 "-" "PostmanRuntime/7.29.2" "-"
...

И в /var/log/nginx/error.log:

2022/10/13 03:51:11 [error] 729700#729700: *38917 limiting requests, excess: 5.353 by zone "def_lkk", client: 10.10.6.100, server: lkk-sk.it-serv.ru, request: "GET /dev/exists HTTP/1.1", host: "lkk-sk.it-serv.ru"
2022/10/13 03:51:12 [error] 729700#729700: *38917 limiting requests, excess: 5.517 by zone "def_lkk", client: 10.10.6.100, server: lkk-sk.it-serv.ru, request: "GET /dev/exists HTTP/1.1", host: "lkk-sk.it-serv.ru"

Пользователь же увидит следующие HTML-код:

<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.20.2</center>
</body>
</html>

Шаг 2.

Настраиваем fail2ban. Переходим в файл /etc/fail2ban/jail.local и редактируем параметры:

banaction = iptables-multiport
banaction_allports = iptables-allports

на

banaction = iptables-ipset-proto6
banaction_allports = iptables-ipset-proto6-allports

Шаг 3.

Находим правило nginx-limit-req и приводим его к следующему виду:

#port    = http,https
#logpath = %(nginx_error_log)s
port     = http,https
enabled  = true
filter   = nginx-limit-req
action   = iptables-multiport[name=ReqLimit, port="http,https", protocol=tcp]
logpath  = /var/log/nginx/*error.log
findtime = 600
bantime  = 3600
maxretry = 4

enabled — указание на активность jail’а (включен/выключен);
port — здесь указываются порты, для которых будет работать наш фильтр. Можно указать словами или прописать конкретные значения (http, https, all, 22…);
filter — здесь указываем название нашего фильтра (имя файла до .conf), в нашем случае это new_filter;
logpath — это путь к файлу с логами, которые будет анализировать фильтр; поскольку мы будем работать с логами подключения, то и путь указываем к этим логам /var/log/nginx/*error.log;
maxretryfindtimebantime — параметры для поиска и бана (количество попыток, вызывающее срабатывание, время, за которое производится поиск и время бана; здесь они указаны в секундах, но можно для указания времени указывать часы, дни и недели, добавляя после значения hd и w соответственно.

Шаг 4.

В каталоге /etc/fail2ban/action.d создаём файл iptables-blocktype.local и добавляем туда следующий текст:

[Init]
blocktype = DROP

Данная настройка позволяет экономить ресурсы системы при защите от атак.

Шаг 5.

Проверяем работу fail2ban

ps afx | grep fail

Результатом должно быть:

Пример активности fail2ban

Примечание: не забываем после обновлений конфига перезапускать fail2ban:

systemctl restart fail2ban

Делаем специально запросы таким образом, чтобы была блокировка. Результатом будет:

iptables -L -v -n
Данные iptables

Смотрим информацию, которая хранится в fail2ban:

fail2ban-client status nginx-limit-req

Общие рекомендации:

# какие jail активные
fail2ban-client status
Список активных jail
# принудительно убрать конкретный IP из бана
fail2ban-client set nginx-limit-req unbanip 10.10.6.100
# принудительная блокировка IP по правилу jail
fail2ban-client set [name-of-jail] banip [ip-address]
# проверяем, как работает проверка 
fail2ban-regex /var/log/nginx/error*.log /etc/fail2ban/filter.d/nginx-limit-req.conf

Шаг 6.

Переключаемся на ipset. В файл /etc/fail2ban/jail.local комментируем строку action для jail=nginx-limit-req

Комментируем action и настраиваем jail на по умолчанию в banaction

Таким образом переключаемся на ipset. Перезапускаем fail2ban:

systemctl restart fail2ban

После повторного бана информацию, которая содержится в ipset

ipset -L
Информация о забанных IP в ipset
Так выглядит iptables

Полезные ссылки:

  • https://serveradmin.ru/nastroyka-fail2ban-dlya-zashhityi-wordpress/ — Защита админки wordpress с помощью fail2ban
  • https://nginx.org/ru/docs/http/ngx_http_limit_req_module.html — Модуль ngx_http_limit_req_module
  • https://www.youtube.com/watch?v=GEwjjuxXow0 — Настраиваем fail2ban: защита от DoS и подбора паролей
  • https://www.youtube.com/watch?v=mUiNYCrz-1M — Fail2ban — самое полное руководство по установке и настройке.
Print Friendly, PDF & Email

Добавить комментарий