Вопрос или проблема
Мой сервер в настоящее время атакован скрипт-киддисами. Я настроил fail2ban
, который правильно блокирует IP.
2020-01-07 05:51:45,639 fail2ban.actions [1656]: WARNING [nginx-botsearch] 123.207.92.128 уже заблокирован
2020-01-07 05:51:47,802 fail2ban.filter [1656]: INFO [nginx-botsearch] Найден 123.207.92.128 - 2020-01-07 05:51:47
2020-01-07 05:51:48,026 fail2ban.filter [1656]: INFO [nginx-botsearch] Найден 123.207.92.128 - 2020-01-07 05:51:48
2020-01-07 05:51:48,242 fail2ban.actions [1656]: WARNING [nginx-botsearch] 123.207.92.128 уже заблокирован
2020-01-07 05:51:49,228 fail2ban.filter [1656]: INFO [nginx-botsearch] Найден 123.207.92.128 - 2020-01-07 05:51:49
Статус: активен
Логирование: включено (низкий уровень)
По умолчанию: отказано (входящие), разрешено (исходящие), отказано (маршрутизация)
Новые профили: пропустить
Куда Действие Откуда
-- ------ ----
Везде ОТКАЗ В 123.207.92.128
Это первое правило
2020-01-07 05:51:45,639 fail2ban.actions [1656]: WARNING [nginx-botsearch] 123.207.92.128 уже заблокирован
2020-01-07 05:51:47,802 fail2ban.filter [1656]: INFO [nginx-botsearch] Найден 123.207.92.128 - 2020-01-07 05:51:47
2020-01-07 05:51:48,026 fail2ban.filter [1656]: INFO [nginx-botsearch] Найден 123.207.92.128 - 2020-01-07 05:51:48
2020-01-07 05:51:48,242 fail2ban.actions [1656]: WARNING [nginx-botsearch] 123.207.92.128 уже заблокирован
2020-01-07 05:51:49,228 fail2ban.filter [1656]: INFO [nginx-botsearch] Найден 123.207.92.128 - 2020-01-07 05:51:49
Но, как вы видите, IP уже заблокирован, и атакующий все еще может получить доступ.
Я удивляюсь, как это возможно?
Я протестировал это для моей локальной сети и обнаружил, что я все еще могу получить доступ к домену, но не к IP. Я думаю, что это потому, что используется IPv6. Но почему тогда я не получаю запись в логах для IPv6?
Мой домен настроен с использованием CNAME. Это имеет значение? Я не знаю, знает ли атакующий о домене, но он может быть перенаправлен на него.
Но, как вы видите, IP уже заблокирован, и атакующий все еще может получить доступ.
Эта проблема похожа на https://github.com/fail2ban/fail2ban/issues/2545
Коротко: поддержка соединения против ufw (поэтому я предлагаю не использовать его или расширить действие для прерывания соединения).
Но почему я не получаю запись в логах для IPv6?
Есть 2 причины:
- либо ваша версия fail2ban <= 0.9 (поддержка IPv6 впервые внедрена в 0.10);
- либо зарегистрированное сообщение выглядит немного иначе для IPv6, так что failregex больше не совпадает с ним (переписать failregex совместимо для обеих семей);
Обновление 1:
- либо (лучше) поместить правило для установленных соединений после цепочки с правилами fail2ban, либо просто удалить правило белого списка для установленных соединений;
- или вы можете использовать что-то вроде этого, чтобы завершить все установленные соединения с IP на оба локальных http/https порта:
ss -o state established -K "dst = [$ip] и ( sport = 80 или sport = 443 )"
Обратите внимание, что это требует современного ядра (версия >= 4.9, я предполагаю).
Вы также можете добавить это прямо в jail.local (без создания нового файла конфигурации действия):
[some-nginx-jail]
_killstmt = ss -o state established -K "dst = [<ip>] и ( sport = 80 или sport = 443 )"
banaction = %(known/banaction)s[actionban="<known/actionban><br>%(_killstmt)s"]
- или заставить nginx закрыть соединение по причине неудачной аутентификации (например, использовать собственное местоположение 40x с
keepalive_timeout 0;
, которое также может записывать ошибку в другой лог-файл, чтобы избежать “паразитного” трафика в смысле fail2ban, см. fail2ban/wiki/Best-practice#reduce-parasitic-log-traffic для получения дополнительной информации);
или просто сделайтеreturn 444;
в соответствующем местоположении, это заставит закрыть соединение (см. http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return для документации)
Как отметил @sebres (Большое спасибо!!), поддержка живых соединений является причиной этого поведения.
Вы можете ограничить количество запросов на поддержание соединения в nginx.
Отредактируйте /etc/nginx/nginx.conf
и добавьте
keepalive_timeout 20; # это уже было здесь, но установлено на 65.
keepalive_requests 20;
в секции http
.
Это должно ограничить живые соединения до 20 секунд и 20 запросов на соединение.
Для Apache должны быть аналогичные правила.
Дополнительно, вы также можете добавить эти правила в ufw. Преимущество в том, что вы можете использовать эти правила на любом желаемом порту. Но большинство этих атакующих скриптов используют порты 80 и 443.
Я не уверен, что эти правила могут привести к проблемам!
Как отметил @sebres в своем ответе, это поведение должно быть вызвано HTTP Keep-Alive
. Если вы хотите, чтобы fail2ban немедленно блокировал запросы от удаленного клиента, вы можете добавить цепочку, определяемую пользователем (например, before-established
) в ваши iptables и разместить ее непосредственно перед правилом ESTABLISHED,RELATED
в цепочке ufw-before-input
(запустите iptables -nv --line-numbers ufw-before-input
, чтобы их перечислить):
iptables -N before-established
iptables -I ufw-before-input <desired_position> -p tcp --dport 80 -j before-established
и сделать то же самое для ip6tables
. Если вы остановите UFW, правила должны оказаться в /etc/ufw/before.rules
и быть восстановлены между перезагрузками UFW. В противном случае добавьте две строки вручную (iptables-save -t ufw-before-input
для синтаксиса).
Чтобы использовать новую цепочку с fail2ban, вы можете создать новый файл действия в /etc/fail2ban/action.d
(назовем его before-established.conf
) со следующим содержимым:
[INCLUDES]
before = iptables-common.conf
[Definition]
blocktype = DROP
actionflush = <iptables> -F before-established
actionstart = <actionflush>
actionstop = <actionflush>
actioncheck = <iptables> -n -L before-established >/dev/null
actionban = <iptables> -I before-established 1 -s <ip> -j DROP
actionunban = <iptables> -D before-established -s <ip> -j DROP
[Init]
и использовать это действие вместо действия ufw.
Ответ или решение
Для решения проблемы, связанной с тем, что UFW
(Uncomplicated Firewall) и fail2ban
не блокируют скрипты атак на веб-сервер nginx
, важно понять, как функционируют обе технологии и какие нюансы могут помешать их правильной работе.
Теория:
fail2ban
— это программа, которая анализирует логи сервисов на предмет подозрительных действий (например, многочисленные попытки входа, запросы с ошибками и т.д.) и, если таковые обнаруживает, добавляет IP-адреса, с которых эти действия исходят, в бан-лист на определенный период. UFW
— это удобный интерфейс для iptables
, который облегчает управление настройками брандмауэра. Вместе они предоставляют способ автоматической блокировки вредоносного трафика.
Однако обнаруженная проблема говорит о том, что IP-адрес источника атаки всё еще может подключаться к серверу, несмотря на то, что был добавлен в список заблокированных. Это может быть связано с несколькими факторами:
-
HTTP Keep-Alive: Технология HTTP Keep-Alive позволяет одному соединению HTTP обрабатывать несколько запросов, что может приводить к тому, что уже забаненный IP-адрес не разрывает соединение немедленно после попадания в бан-лист. Это объясняет, почему после блокировки
fail2ban
, запросы могут продолжаться до истечения времени жизни соединения. -
Поддержка IPv6: Многие версии
fail2ban
, особенно до 0.10, не поддерживают IPv6 или требуют особой настройки регулярных выражений (failregex) для определения логов IPv6. Это может означать, что если атакующий использует IPv6, записи в логе могут не подходить под существующие правила фильтрации.
Пример:
В приведённой ситуации, несмотря на то, что fail2ban
успешно распознает и помечает IP-адрес 123.207.92.128
как заблокированный, он продолжает получать доступ к серверу, что указывает на наличие активных или "живых" соединений. Кроме того, использование CNAME может осложнять отслеживание, поскольку он скрывает исходный домен, но это, скорее всего, не основная причина проблемы, так как fail2ban
использует IP-адреса.
Применение:
Для решения этой проблемы возможно использовать несколько подходов:
-
Настройка Keep-Alive в Nginx: Убедитесь, что подключенные клиенты не могут злоупотреблять боле длинными сессиями. Это можно сделать, изменив
keepalive_timeout
иkeepalive_requests
в конфигурацииnginx
:keepalive_timeout 20; keepalive_requests 20;
Это ограничит время жизни и количество запросов в рамках одной связи.
-
Обновление и настройка fail2ban для IPv6: Убедитесь, что вы используете
fail2ban
версии не ниже 0.10, которая поддерживает IPv6. Проверьте и при необходимости перепишите регулярные выражения (failregex), чтобы учитывать формат IPv6. -
Управление правилами iptables: Менеджмент активных соединений может быть улучшен с использованием команды
ss
для уничтожения установленных соединений, или перемещением правилfail2ban
перед стандартными правилами для уже установленных соединений вUFW
. -
Изменение конфигурации UFW: Создайте цепочку iptables (например,
before-established
), которая идёт передESTABLISHED,RELATED
и управляет входящими соединениями до их установки в обычный порядок. Эта цепочка будет отвечать за своевременное разрыв соединений.
Применяя данные рекомендации, вы сможете значительно улучшить защитные механизмы вашего сервера, делая его более устойчивым к атакам и снижая вероятность обхода ваших защитных систем. Согласно политике IT безопасности, регулярная проверка и обновление приложений и конфигурационных файлов должна стать неотъемлемой частью обслуживания сервера.