Ой, ничего не найдено!

К сожалению, по вашему запросу пока ничего нет (но это только пока!), зато вы можете подписаться на нашу замечательную email-рассылку, чтобы не пропустить самое интересное в будущем.

  • 27

Fail2ban и брутфорс: как перестать кормить ботов

  • 4 минуты на чтение

Часть 3 из 14 · Серия «Сервер в бою»

В прошлой статье я обещал показать самый тревожный лог сервера. Выполняю. Если у вас есть VPS с публичным IP, откройте прямо сейчас:

grep "Failed password" /var/log/auth.log | wc -l

У свежего сервера, о котором ещё никто не должен знать, это число за сутки спокойно доходит до нескольких тысяч. Никто вас лично не взламывает — это фоновая радиация интернета: ботнеты круглосуточно сканируют все IPv4-адреса подряд и стучатся в каждый открытый SSH со словарём из root/123456, admin/admin и ещё пары миллионов комбинаций. Ваш сервер попал в этот список в первые же минуты после создания.

Опасно ли это? Если у вас нормальный пароль или вход по ключу — почти нет. Но «почти нет» — плохая политика безопасности, а кроме риска есть ещё и цена: каждая попытка входа — это работа sshd, запись в лог, крошка CPU. Тысячи попыток в день — и вы буквально кормите ботов ресурсами своего VPS. В этой статье мы поставим на дверь вышибалу — fail2ban, — настроим его для SSH и WordPress, а главное, обойдём грабли, на которые наступает каждый первый (включая граблю «забанил сам себя»).

Как это выглядит в auth.log: «до»

Сначала — посмотреть врагу в лицо, мы же договорились начинать с логов. Открываем:

tail -f /var/log/auth.log

И просто ждём. Долго ждать не придётся:

Jul  4 03:41:02 vps sshd[19204]: Failed password for root from 45.155.204.11 port 41522 ssh2
Jul  4 03:41:05 vps sshd[19204]: Failed password for root from 45.155.204.11 port 41522 ssh2
Jul  4 03:41:09 vps sshd[19208]: Invalid user admin from 45.155.204.11 port 41916
Jul  4 03:41:11 vps sshd[19208]: Failed password for invalid user admin from 45.155.204.11 port 41916
Jul  4 03:41:15 vps sshd[19213]: Invalid user oracle from 193.32.162.85 port 55210
SSD/NVMe в комплекте
Скорость, которую видно в первом же отклике
NVMe-диски, свежее железо и честные ресурсы без «соседей», которые съедают всю мощность. Разница чувствуется с первого запроса.
Разогнать проект

Методичный перебор: root, admin, oracle, postgres, user, test... Знакомый по прошлой статье однострочник покажет топ самых настойчивых:

grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head
   1847 45.155.204.11
    923 193.32.162.85
    411 118.25.6.39

Почти две тысячи попыток с одного адреса. Вручную банить такое бессмысленно — адресов сотни, и они меняются. Нужна автоматика.

Сначала — дверь, потом — вышибала

Честная оговорка перед установкой чего бы то ни было: fail2ban — не замена нормальной аутентификации, а дополнение к ней. Если вход на сервер возможен по паролю qwerty123, никакой бан после пятой попытки не спасёт — ботнету хватит и четырёх, просто с разных IP.

Поэтому базовая гигиена, десять минут, один раз:

1. Вход только по ключу. На своей машине: ssh-keygen -t ed25519, затем ssh-copy-id user@сервер. Проверили, что входит без пароля, — и только после этого:

2. Отключаем парольный вход и root. В /etc/ssh/sshd_config:

PasswordAuthentication no
PermitRootLogin prohibit-password
Запуск за 2 минуты
VPN, бот или пет-проект — поднимем за пару минут
VPN, Telegram-бот, своё облако или пет-проект — арендуйте сервер за пару минут и проверьте идею в деле уже сегодня.
Создать сервер

И systemctl restart ssh. Важно: не закрывайте текущую SSH-сессию, пока не проверили в соседнем окне, что новая открывается. Это правило номер ноль любых манипуляций с SSH — старая сессия остаётся вашим запасным выходом.

После этих двух шагов брутфорс становится математически бесполезным: подобрать ключ ed25519 перебором нельзя. Но боты об этом не знают и продолжат долбиться, засоряя логи и отъедая ресурсы. Вот теперь — вышибала.

Ставим fail2ban и понимаем, как он думает

apt install fail2ban

Идея fail2ban гениально проста, он делает ровно то, что мы делали в прошлой статье руками, только непрерывно: читает лог → ищет строки-признаки атаки по регуляркам (фильтр) → считает совпадения от одного IP → при превышении порога банит IP через файрвол на заданное время. Связка «какой лог + какой фильтр + какой порог + какое наказание» называется jail — камера.

Первая грабля ждёт прямо здесь. Конфиг по умолчанию лежит в /etc/fail2ban/jail.conf, и править его нельзя: при обновлении пакета файл перезапишется, и ваши настройки испарятся. Все свои изменения — только в отдельном файле:

nano /etc/fail2ban/jail.local

Разумный стартовый вариант:

[DEFAULT]
# кого не банить никогда (localhost и ВАШ домашний/офисный IP)
ignoreip = 127.0.0.1/8 ::1 203.0.113.50

# порог: сколько промахов за какое окно
maxretry = 5
findtime = 10m

# на сколько баним
bantime = 1h

# рецидивистам — больнее: каждый повторный бан длиннее
bantime.increment = true
bantime.maxtime = 1w

[sshd]
enabled = true

Перезапускаем и смотрим статус:

systemctl restart fail2ban
fail2ban-client status sshd
1 месяц бесплатно
Сервер с нуля — без боли и гугления каждой команды
Понятная панель, готовые шаблоны и поддержка, которая объясняет по-человечески. Поднимите проект, даже если SSH видите впервые.
Попробовать бесплатно
Status for the jail: sshd
|- Filter
|  |- Currently failed: 3
|  `- Total failed: 214
`- Actions
   |- Currently banned: 7
   `- Total banned:     19

Семь адресов уже сидят. Fail2ban начал отрабатывать в первые же минуты — не потому что он такой быстрый, а потому что стучатся действительно непрерывно.

Про ignoreip — отдельно и с нажимом: впишите туда свой IP до того, как понадобится. Классика жанра: админ настраивает fail2ban, потом возится с SSH-ключами, пять раз промахивается паролем — и наблюдает Connection refused от собственного сервера. Если IP динамический и меняется — хотя бы держите под рукой аварийную VNC-консоль провайдера (мы говорили о ней в первой статье): разбан оттуда делается одной командой:

fail2ban-client set sshd unbanip 203.0.113.50

Auth.log «после»: тишина в цифрах

Через сутки после включения сравните сами:

grep "Failed password" /var/log/auth.log | wc -l

Число падает на порядок — с тысяч до сотен и меньше. Не до нуля: каждому новому боту всё ещё дают его пять попыток, прежде чем захлопнуть дверь, — но методичный перебор словаря с одного адреса умер как жанр. А с bantime.increment постоянные «клиенты» постепенно уезжают в бан на неделю, и фон продолжает снижаться со временем.

Это, кстати, приятная особенность fail2ban: эффект видно в тех же логах, по которым мы диагностировали проблему. Метод «сначала смотрим» работает в обе стороны — и для поиска болезни, и для проверки лечения.

Уровень два: WordPress и другие двери

SSH — не единственная дверь, в которую ломятся. Если на сервере крутится WordPress, вторая по популярности мишень — форма логина wp-login.php и xmlrpc.php. Брутфорс здесь виден не в auth.log, а в access.log nginx — сплошные POST-запросы:

grep "POST /wp-login.php" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head
SSD/NVMe в комплекте
Пока вы это читаете, чей-то сайт уже летает
NVMe-диски, свежее железо и честные ресурсы без «соседей», которые съедают всю мощность. Разница чувствуется с первого запроса.
Разогнать проект

Fail2ban легко научить читать и этот лог. Создаём фильтр /etc/fail2ban/filter.d/wordpress-login.conf:

[Definition]
failregex = ^<HOST> .* "POST /(wp-login\.php|xmlrpc\.php)

И jail в наш jail.local:

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

Тонкость, о которую спотыкаются: этот фильтр считает все POST на логин, включая успешный вход настоящего админа. Для персонального блога, куда логинитесь вы один, maxretry = 5 — нормально: вы просто не промахнётесь пять раз за пять минут (а если промахнётесь — вы в ignoreip, правда ведь?). Для сайта с множеством живых пользователей порог стоит поднять, а по-хорошему — банить по коду ответа или логу неудачных входов самого WordPress. Начните с простого варианта, посмотрите неделю на fail2ban-client status wordpress-login — и подкрутите под свой трафик.

По тому же шаблону — «найди признак атаки в логе, напиши регулярку, заведи jail» — защищается что угодно: панель phpMyAdmin, форма логина вашего Laravel-приложения, почтовый сервер. У fail2ban из коробки уже есть десятки готовых фильтров в /etc/fail2ban/filter.d/ — загляните, ваша ситуация там наверняка предусмотрена. Проверить свежесочинённую регулярку на живом логе, не дожидаясь атаки:

fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress-login.conf

Типичные грабли: чек-лист

Соберём в кучу всё, обо что бьются на практике.

Грабля Симптом Лекарство
Правили jail.conf Настройки пропали после apt upgrade Всё своё — в jail.local
Забыли ignoreip Забанили сами себя VNC-консоль → unbanip, потом вписать свой IP
SSH на нестандартном порту Баны «не работают» fail2ban обычно берёт порт из конфига sshd сам, но проверьте port = в jail
Смотрят не тот лог Jail молчит при явной атаке Сверьте logpath с реальностью; на новых системах sshd может писать только в journald — тогда backend = systemd
bantime навсегда Список банов растёт вечно, в него попадают и живые люди с динамических IP Часы, не годы; для рецидивистов — bantime.increment
Fail2ban как единственная защита Пароль 123456 «под защитой» Сначала ключи и PasswordAuthentication no, потом всё остальное
Nginx за Cloudflare/прокси Банятся IP прокси, т.е. весь сайт Настроить real_ip_header, чтобы в логи попадал реальный IP клиента

Последний пункт — самый коварный, потому что стреляет не сразу: всё выглядит рабочим, пока однажды fail2ban не забанит IP-адрес Cloudflare и сайт не «упадёт» для всех сразу. Если между пользователем и nginx есть прокси — сначала научите nginx писать в лог настоящие адреса, и только потом натравливайте на этот лог баны.

от 0 ₽ на старте
Свой сервер по цене чашки кофе в неделю
Прозрачные тарифы без сюрпризов в чеке. Платите за то, что реально используете, и масштабируйтесь, когда вырастете.
Смотреть тарифы

Что в итоге

Полчаса работы — и картина меняется радикально: вход на сервер возможен только по ключу, словарный брутфорс SSH математически мёртв, боты после пятой попытки уезжают в бан с прогрессирующим сроком, WordPress-логин прикрыт, а auth.log из сплошного потока Failed password превратился в читаемый журнал, где настоящее вторжение (если оно когда-нибудь случится) будет видно, а не утонет в шуме. Именно это, а не «неуязвимость», и есть цель: снизить фон, чтобы слышать сигнал.

Кстати, о «слышать». Fail2ban защищает молча — а хотелось бы ещё и знать, что происходит: когда сервер под нагрузкой, когда кончается диск, когда сайт лёг. Пока что все наши инструменты реагируют постфактум: авария случилась — пошли читать логи. В следующей статье перевернём подход и научим сервер сообщать о проблемах самому — поставим Uptime Kuma и Netdata и разберёмся, как мониторить одинокий VPS, не превращая это в вторую работу.

VDS с первого дня

Свой сервер Siteko под полным контролем

NVMe-диски, root-доступ и честные ресурсы без «соседей». Поднимите VPN, бота или прод-проект и масштабируйтесь без тесных рамок.

  • Root-доступ полная свобода настройки под ваш стек.
  • NVMe и свежее железо скорость заметна с первого запроса.
  • Перенос бесплатно поможем переехать без простоя.
Выбрать VDS