opened image

Fail2ban: расширенная настройка - nginx, wordpress, custom jail

 

Стандартная установка fail2ban с jail для SSH работает из коробки, но реальная защита начинается с кастомных jail под конкретные приложения. Разберём создание jail для nginx (блокировка по 4xx/5xx), защиту WordPress (xmlrpc.php и wp-login.php), настройку recidive для бана рецидивистов и управление whitelist-ом.

 

 

Архитектура fail2ban

 

Fail2ban состоит из трёх компонентов:

  • Filter - регулярные выражения для разбора логов (/etc/fail2ban/filter.d/)

  • Jail - объединяет filter с параметрами (порт, лог, порог срабатывания, время бана)

  • Action - что делать при бане (iptables, ipset, sendmail и др.)

 

 

Цепочка: fail2ban читает лог → filter матчит строки → при достижении maxretry за findtime секунд → выполняется action (добавляет IP в iptables).

 

Версия fail2ban 1.0.2 установлена в Ubuntu 24.04. Конфиги в /etc/fail2ban/jail.d/ переопределяют дефолтные настройки - редактируйте только их, не трогая /etc/fail2ban/jail.conf.

 

sudo apt install fail2ban -y
sudo systemctl enable fail2ban
fail2ban-client version
# 1.0.2

 

 

Базовые настройки по умолчанию

 

Создаём /etc/fail2ban/jail.d/defaults.conf:

[DEFAULT]
# Время бана в секундах (1800 = 30 минут)
bantime  = 1800

# Период поиска нарушений
findtime = 600

# Число нарушений до бана
maxretry = 5

# Backend для чтения логов
backend = auto

# Метод бана (iptables-multiport быстрее ipfw)
banaction = iptables-multiport

# Whitelist - эти IP никогда не банятся
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

# Email при бане (если настроен sendmail)
# destemail = admin@example.com
# sendername = Fail2ban
# action = %(action_mwl)s

 

 

Jail для SSH (стандартный, для примера)

 

[sshd]
enabled = true
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime  = 3600
findtime = 300

 

 

Jail для nginx - блокировка по 4xx/5xx

 

Создаём filter /etc/fail2ban/filter.d/nginx-4xx.conf:

[Definition]
# Матчим все 4xx ответы, кроме 400 и 404 (слишком часты легитимно)
failregex = ^<HOST> -.*"(GET|POST|HEAD|PUT|DELETE).*" (4(?!0[04])\d{2}|5\d{2}) .*$

ignoreregex = 

 

Более строгий вариант - матчить только подозрительные 4xx:

[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD).*(\.php|\.asp|\.env|\.git|\.htaccess|wp-config|etc/passwd)" (400|403|404|405|429) .*$
ignoreregex =

 

Создаём jail /etc/fail2ban/jail.d/nginx-custom.conf:

[nginx-4xx]
enabled  = true
port     = http,https
filter   = nginx-4xx
logpath  = /var/log/nginx/access.log
maxretry = 15
findtime = 60
bantime  = 600

[nginx-5xx]
enabled  = true
port     = http,https
filter   = nginx-5xx
logpath  = /var/log/nginx/access.log
maxretry = 10
findtime = 60
bantime  = 1800

 

Filter для 5xx /etc/fail2ban/filter.d/nginx-5xx.conf:

[Definition]
failregex = ^<HOST> -.*" 5\d{2} .*$
ignoreregex = ^<HOST> -.*" 502 .* "Mozilla.*$

 

Тестируем filter до перезапуска:

sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf

 

 

 

 

Защита WordPress

 

WordPress атакуют постоянно - брутфорс wp-login.php и xmlrpc.php. Оба endpoint нужно защищать отдельно.

 

Filter для wp-login.php

 

/etc/fail2ban/filter.d/wordpress-login.conf:

[Definition]
# Неудачная авторизация WordPress возвращает 200 с ключевыми словами
# Используем лог nginx + специальный формат
failregex = ^<HOST> -.*"POST /wp-login.php.*" 200.*$

# Или через PHP-лог (если доступен)
# failregex = ^<HOST> -.*"POST /wp-login.php" 200

ignoreregex =

 

Для более точного обнаружения настраиваем Nginx logging с флагом неудачной авторизации. В WordPress добавляем action при неудачном входе через functions.php:

add_action('wp_login_failed', function($username) {
    $ip = $_SERVER['REMOTE_ADDR'];
    error_log("[wp-fail2ban] Authentication failure for user: $username from $ip");
}, 10, 1);

 

Тогда filter читает /var/log/php/error.log:

[Definition]
failregex = \[wp-fail2ban\] Authentication failure.* from <HOST>
ignoreregex =

 

 

Filter для xmlrpc.php

 

/etc/fail2ban/filter.d/wordpress-xmlrpc.conf:

[Definition]
failregex = ^<HOST> -.*"POST /xmlrpc.php.*" (200|403|405) .*$
ignoreregex =

 

 

Jail для WordPress

 

/etc/fail2ban/jail.d/wordpress.conf:

[wordpress-login]
enabled  = true
port     = http,https
filter   = wordpress-login
logpath  = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime  = 7200

[wordpress-xmlrpc]
enabled  = true
port     = http,https
filter   = wordpress-xmlrpc
logpath  = /var/log/nginx/access.log
maxretry = 3
findtime = 60
bantime  = 86400

 

XML-RPC атаки часто используют multicall - одним запросом проверяют сотни паролей. Поэтому maxretry = 3 здесь оправдан.

 

Ещё лучше - закрыть xmlrpc.php полностью в Nginx, если он не используется:

location = /xmlrpc.php {
    deny all;
    access_log off;
    log_not_found off;
}

 

 

 

 

Jail recidive - бан рецидивистов

 

Recidive - встроенный jail fail2ban, который банит IP на долгий срок, если они попались в другие jail несколько раз. IP банится на 1 неделю при 5 срабатываниях за 1 день.

 

/etc/fail2ban/jail.d/recidive.conf:

[recidive]
enabled   = true
logpath   = /var/log/fail2ban.log
banaction = iptables-allports
filter    = recidive
maxretry  = 5
findtime  = 86400
bantime   = 604800

# Логировать баны recidive отдельно
action = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
         mail-whois[name=%(__name__)s, dest="%(destemail)s"]

 

Filter recidive уже включён в стандартную установку. Он читает /var/log/fail2ban.log и матчит строки вида Ban 1.2.3.4.

 

Убедитесь, что fail2ban пишет логи:

ls -la /var/log/fail2ban.log
# Если нет - создаём:
sudo touch /var/log/fail2ban.log
sudo systemctl restart fail2ban

 

 

IP Whitelist - исключения из всех правил

 

Whitelist указывается в параметре ignoreip секции [DEFAULT]. Поддерживаются IP, подсети CIDR и DNS-имена.

 

В /etc/fail2ban/jail.d/defaults.conf:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 10.0.0.0/8 185.10.20.30

 

Динамическое добавление IP в whitelist без перезапуска:

# Добавить IP во все jail
sudo fail2ban-client set JAIL ignoreip 1.2.3.4

# Для конкретного jail
sudo fail2ban-client set sshd ignoreip 1.2.3.4

 

Если белый список нужно хранить в файле:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1
ignorecommand = /usr/bin/grep -cF <ip> /etc/fail2ban/whitelist.txt

 

 

Управление banами вручную

 

# Статус всех jail
sudo fail2ban-client status

# Статус конкретного jail
sudo fail2ban-client status nginx-4xx

# Список заблокированных IP
sudo fail2ban-client status nginx-4xx | grep "Banned IP"

# Разблокировать IP
sudo fail2ban-client set nginx-4xx unbanip 1.2.3.4

# Заблокировать IP вручную
sudo fail2ban-client set nginx-4xx banip 1.2.3.4

# Убрать IP из бана во всех jail
for jail in $(sudo fail2ban-client status | awk '/Jail list/{print $NF}' | tr ',' ' '); do
  sudo fail2ban-client set $jail unbanip 1.2.3.4 2>/dev/null
done

 

Проверить, заблокирован ли IP в iptables:

sudo iptables -L f2b-nginx-4xx -n | grep 1.2.3.4

 

 

Отладка и мониторинг

 

 

# Тест filter на логе
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf --print-all-missed

# Посмотреть лог fail2ban
sudo tail -f /var/log/fail2ban.log

# Перечитать конфиг без перезапуска
sudo fail2ban-client reload

# Проверить синтаксис всех конфигов
sudo fail2ban-client --test

 

 

 

 

 

Итог

 

Кастомные jail превращают fail2ban из SSH-защитника в полноценный инструмент защиты веб-приложений. Ключевые правила: findtime и maxretry устанавливают чувствительность, bantime - строгость наказания. Для WordPress xmlrpc.php достаточно 3 попыток за минуту. Recidive автоматически находит системных злоумышленников - IP, которые регулярно попадают в разные jail - и блокирует их на неделю без ручного вмешательства.