Fail2ban: свой фильтр для сканеров nginx и проверка fail2ban-regex

Готовые фильтры Fail2ban закрывают типовые случаи, но сканеры чаще всего стучатся в одни и те же служебные пути: /.env, /.git/config, wp-config.php.bak, xmlrpc.php. Свой фильтр по журналу доступа nginx блокирует их после нескольких попыток. Главная сложность — не написать выражение, а убедиться, что оно срабатывает на плохом и молчит на нормальном трафике. Ниже фильтр, проверка на примерах до включения и порядок запуска.
Статья опирается на логику направления «Сетевая безопасность» из методики зрелости Группы Сбер (источник); это методика для крупных компаний, мы используем её как ориентир и пересказываем своими словами. Проверка выполнена на Fail2ban 1.0.2 (Debian 12) командами fail2ban-regex и fail2ban-client -t с копией каталога настроек: работающая служба и её конфигурация не затрагивались. Установка и общие настройки: CrowdSec и Fail2ban.
Что должно получиться
| Уровень | Что это значит на практике |
|---|---|
| 2. Гигиенический | Публичные сервисы защищены от типовых атак, журналы ведутся и по ним действуют автоматические реакции |
Критерии сформулированы нами по мотивам методики, это ориентир, а не оценка соответствия.
Фильтр
Файл /etc/fail2ban/filter.d/nginx-scan.conf. Он ищет в журнале запросы к «подозрительным» путям, закончившиеся отказом (коды 400, 403, 404, 405, 444).
# /etc/fail2ban/filter.d/nginx-scan.conf
# Сканеры уязвимостей: обращения к служебным файлам и типовым целям, закончившиеся отказом.
# Формат журнала nginx по умолчанию (combined): АДРЕС - - [время] "МЕТОД ПУТЬ HTTP/x" КОД РАЗМЕР "referer" "agent"
# Fail2ban вырезает время из строки перед сопоставлением, поэтому на месте [время] в выражении стоят пустые скобки \[\]
[Definition]
failregex = ^<HOST> - \S+ \[\] "(?:GET|POST|HEAD|PUT) /(?:\.env|\.git/|\.aws/|wp-config\.php(?:\.\w+)?|phpmyadmin|pma/|xmlrpc\.php|cgi-bin/|vendor/phpunit)[^"]*" (?:400|403|404|405|444)
ignoreregex =
Ловушка: время вырезается из строки
Fail2ban находит в строке дату и убирает её до сопоставления с выражением. Поэтому на месте [12/Oct/2026:16:51:34 +0000] в выражении должны стоять пустые скобки \[\]. Первый вариант фильтра с \[[^\]]+\] не нашёл ни одной строки: 8 строк обработано, 0 совпадений, 8 пропусков. Если ваш фильтр «не работает», сначала проверьте именно это.
Проверка до включения
Образец журнала (8 строк: три запроса сканера с одного адреса, один с другого, обычный посетитель, страница 404 у посетителя, параметр .env в обычном запросе, прямое обращение к /.env с ответом 200):
203.0.113.5 - - [12/Oct/2026:16:51:34 +0000] "GET /.env HTTP/1.1" 403 146 "-" "Wget" "-"
203.0.113.5 - - [12/Oct/2026:16:51:35 +0000] "GET /.git/config HTTP/1.1" 404 146 "-" "curl/8" "-"
203.0.113.5 - - [12/Oct/2026:16:51:36 +0000] "POST /xmlrpc.php HTTP/1.1" 404 146 "-" "python-requests/2.31" "-"
198.51.100.9 - - [12/Oct/2026:16:52:01 +0000] "GET /wp-config.php.bak HTTP/1.1" 404 146 "-" "-" "-"
192.0.2.44 - - [12/Oct/2026:16:52:10 +0000] "GET / HTTP/1.1" 200 5120 "-" "Mozilla/5.0" "-"
192.0.2.44 - - [12/Oct/2026:16:52:11 +0000] "GET /blog/missing-page HTTP/1.1" 404 146 "-" "Mozilla/5.0" "-"
192.0.2.45 - - [12/Oct/2026:16:52:12 +0000] "GET /index.php?x=.env HTTP/1.1" 200 5120 "-" "Mozilla/5.0" "-"
192.0.2.46 - - [12/Oct/2026:16:52:13 +0000] "GET /.env HTTP/1.1" 200 20 "-" "Mozilla/5.0" "-"
Команда проверки на копии каталога настроек (рабочая конфигурация не затрагивается):
cp -a /etc/fail2ban /tmp/f2b
cp nginx-scan.conf /tmp/f2b/filter.d/nginx-scan.conf
fail2ban-regex -c /tmp/f2b access_sample.log nginx-scan --print-all-matched
Результат: Failregex: 4 total, Lines: 8 lines, 0 ignored, 4 matched, 4 missed. Совпали четыре запроса сканеров: три с адреса 203.0.113.5 (/.env с ответом 403, /.git/config и /xmlrpc.php с 404) и один с 198.51.100.9 (wp-config.php.bak). Не совпали: обычная главная страница, посетитель, наткнувшийся на несуществующую страницу блога, запрос с .env внутри параметра, и /.env с кодом 200.
Последняя строка важна по существу: ответ 200 на /.env означает, что файл с секретами отдаётся. Фильтр такие случаи не банит (бан пришёл бы слишком поздно): их нужно ловить оповещением и немедленно закрывать доступ. Закрытие служебных файлов в nginx: безопасная настройка nginx.
Настройка jail
# /etc/fail2ban/jail.d/nginx-scan.local
[nginx-scan]
enabled = true
port = http,https
filter = nginx-scan
# путь к журналу доступа nginx на вашем сервере (для контейнера: каталог, куда смонтирован журнал)
logpath = /var/log/nginx/access.log
maxretry = 3
findtime = 10m
bantime = 1h
maxretry = 3иfindtime = 10m: три попытки за десять минут; для порога подберите значения по своему трафику.bantime = 1h: для начала час; для повторных нарушителей используйте увеличивающийся срок (механизмrecidive).logpath: если nginx работает в контейнере, укажите каталог на хосте, куда смонтирован журнал (проверьте, что файл существует).
Проверка настройки без перезапуска и без изменения работающей службы:
cp nginx-scan.local /tmp/f2b/jail.d/nginx-scan.local
fail2ban-client -c /tmp/f2b -t
Ожидаемый результат: OK: configuration test is successful. Если журнала по указанному пути нет, проверка выдаёт ошибку Have not found any log file for nginx-scan jail: исправьте logpath.
Включение
- Разместите файлы в
/etc/fail2ban/filter.d/и/etc/fail2ban/jail.d/. - Выполните
sudo fail2ban-client -t, затемsudo systemctl reload fail2ban(илиfail2ban-client reload). - Убедитесь, что jail активен:
sudo fail2ban-client status nginx-scan. - Проверьте работу реальным запросом со своего тестового адреса в списке игнорируемых до включения бана, затем с другого адреса (мобильный интернет): три запроса к
/.envдолжны привести к бану этого адреса; снимите бан командойsudo fail2ban-client set nginx-scan unbanip АДРЕС. - Добавьте адреса администраторов в
ignoreip, чтобы не заблокировать себя.
Защита от ложных срабатываний
- Не включайте в фильтр пути, которые реально используют ваши приложения (
xmlrpc.phpнужен части WordPress-интеграций: уберите его из выражения, если пользуетесь). - Ограничивайте коды ответов: бан по
404для обычных страниц блога недопустим; список путей должен быть узким. - Перед включением прогоните фильтр по реальному журналу за неделю:
fail2ban-regex -c /tmp/f2b /var/log/nginx/access.log nginx-scan. Просмотрите адреса в результатах: среди них не должно быть ваших пользователей и сервисов мониторинга. - Если перед nginx стоит прокси или CDN, в журнале будет адрес прокси: настройте передачу настоящего адреса клиента, иначе забанится прокси.
- Связывайте блокировки с общей картиной: события бана видны в журналах и в правилах Wazuh.
Диагностика
| Симптом | Причина и что делать |
|---|---|
| 0 совпадений на строках, которые должны подходить | Время вырезано из строки: в выражении используйте \[\]. Проверьте формат журнала nginx (нестандартный log_format требует другого выражения) |
| Совпадают обычные посетители | Слишком широкий шаблон пути или код. Сузьте выражение и повторите проверку на журнале |
Have not found any log file |
Неверный logpath или журнал не доступен хосту. Укажите существующий путь |
| Бан не срабатывает на реальных сканерах | Адрес в журнале не тот (прокси) или jail не активен. Проверьте fail2ban-client status и содержимое журнала |
| Заблокировали сами себя | Нет адреса в ignoreip. Снимите бан и добавьте адреса администраторов |
Где это в модели зрелости
Материал относится к направлению «Сетевая безопасность» (материалы направления, карта зрелости). Автоматическая реакция на типовые атаки на публичные сервисы входит в требования к уровню 2; проверка фильтров на примерах делает эти реакции предсказуемыми.
Как проверить
- На образце журнала
fail2ban-regexнаходит строки сканеров и не находит нормальный трафик. - Фильтр прогнан по реальному журналу за неделю, ложных адресов нет.
fail2ban-client -tпроходит, jail активен, тестовый запрос с постороннего адреса приводит к бану, снятие бана выполнено на тесте.- Адреса администраторов в
ignoreip, ответы 200 на служебные файлы отслеживаются отдельным оповещением.
Источники
- Методика оценки уровня зрелости кибербезопасности компании, Группа Сбер: sberbank.ru.
- Документация Fail2ban: fail2ban.readthedocs.io; руководства
man fail2ban-regex,man jail.conf. - OWASP Top 10 (классы атак, на которые ориентированы сканеры): owasp.org. Международная практика, не российский норматив.






















