Брутфорс-атаки — перебор паролей автоматизированными ботами — остаются одним из самых распространённых векторов взлома. Ежедневно на типичный VPS-сервер приходится тысячи попыток подбора пароля к SSH и веб-формам. Многоуровневая защита делает такие атаки нерентабельными.
fail2ban: автоматическая блокировка атакующих
apt install fail2ban -y
# /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600 # Блокировка на 1 час
maxretry = 5 # После 5 неудачных попыток
findtime = 600 # В течение 10 минут
[sshd]
enabled = true
port = ssh,2222
logpath = /var/log/auth.log
[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log
[nginx-limit-req]
enabled = true
logpath = /var/log/nginx/error.log
systemctl enable --now fail2ban
Управление fail2ban
fail2ban-client status sshd
fail2ban-client set sshd unbanip 1.2.3.4
fail2ban-client set sshd banip 5.6.7.8
grep "Ban " /var/log/fail2ban.log | tail -20
Rate Limiting в Nginx
http {
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/m;
}
server {
location /wp-login.php {
limit_req zone=login burst=3 nodelay;
limit_req_status 429;
}
}
Геоблокировка через GeoIP2
apt install libnginx-mod-http-geoip2 -y
http {
geoip2 /var/lib/GeoIP/GeoLite2-Country.mmdb {
$geoip2_data_country_code country iso_code;
}
map $geoip2_data_country_code $allowed_country {
default 0;
UA 1; RU 1; PL 1; DE 1;
}
}
server {
if ($allowed_country = 0) { return 403; }
}
Защита формы входа через CAPTCHA
Для WordPress используйте плагин Cloudflare Turnstile или hCaptcha. Для собственных форм:
// PHP: проверка hCaptcha
$response = file_get_contents('https://hcaptcha.com/siteverify', false,
stream_context_create(['http' => ['method' => 'POST',
'content' => http_build_query([
'secret' => 'YOUR_SECRET_KEY',
'response' => $_POST['h-captcha-response']
])]]));
$result = json_decode($response);
if (!$result->success) { die('CAPTCHA failed'); }
echo "ignoreip = 127.0.0.1/8 ВАШ_IP" >> /etc/fail2ban/jail.local
Частые ошибки настройки защиты
| Сообщение или симптом | Причина |
|---|---|
| Unable to find logfile при старте fail2ban | Путь logpath не совпадает с реальным расположением лога на дистрибутиве — например, CentOS пишет в /var/log/secure, а не /var/log/auth.log |
| nginx: [emerg] limit_req_zone duplicate zone | Зона с одинаковым именем объявлена в нескольких конфигах, которые подключаются одновременно |
| Легитимные пользователи получают 429 Too Many Requests | Значение rate или burst выставлено слишком строго для реального профиля нагрузки формы |
| Собственный IP заблокирован fail2ban после теста | IP не был заранее добавлен в ignoreip — автоматическая разблокировка наступит только через bantime |
Уровни защиты: что от чего защищает
| Инструмент | Что защищает | От какой атаки |
|---|---|---|
| fail2ban | SSH и веб-формы по логам | Перебор паролей по логам сервисов |
| Rate limiting Nginx | HTTP-эндпоинты | Массовые запросы с одного IP |
| CAPTCHA | Формы регистрации и входа | Автоматизированные боты без реального браузера |
| Геоблокировка | Весь трафик из региона | Атаки с известных проблемных регионов |
Когда одной защиты недостаточно
- Атака идёт с тысяч разных IP одновременно (ботнет) — здесь fail2ban бессилен, нужна защита на уровне провайдера или Cloudflare
- Пароли действительно слабые — никакая защита от перебора не заменит переход на надёжные пароли и SSH-ключи
- При целевой атаке на конкретный сайт CAPTCHA обходится платными сервисами распознавания — добавляйте поведенческий анализ (например, Cloudflare Turnstile учитывает это)
- Rate limiting настроен только на Nginx, а приложение слушает порт напрямую в обход прокси
Проверка результата
# Текущий статус джейла sshd
fail2ban-client status sshd
# Симуляция превышения лимита запросов
for i in $(seq 1 10); do curl -s -o /dev/null -w "%{http_code}\n" https://example.com/wp-login.php; done
Если цикл выше не показал ни одного кода 429 — правило limit_req не применяется к этому location, проверьте конфиг Nginx через nginx -T. Смежные темы — базовая настройка fail2ban и DDoS-защита Nginx и Cloudflare.
fail2ban на разных дистрибутивах: где искать логи
Путь к системному логу аутентификации отличается между дистрибутивами, и это самая частая причина, по которой готовый jail.local «не работает» после копирования с другого сервера. Ubuntu и Debian пишут попытки входа по SSH в /var/log/auth.log, а RHEL-based системы (CentOS, AlmaLinux, Rocky Linux) — в /var/log/secure. Перед первым запуском fail2ban на новом сервере всегда проверяйте актуальный путь командой ls -la /var/log/ | grep -E "auth|secure", а не копируйте конфиг вслепую.
Частые вопросы
Поможет ли fail2ban, если атака идёт с тысяч разных IP-адресов одновременно?
Практически нет — fail2ban блокирует конкретный адрес после превышения порога неудачных попыток, а при распределённой атаке с огромного числа разных IP каждый адрес успевает сделать лишь пару попыток и не попадает под блокировку. Нужна защита уровнем выше — на стороне провайдера или через сервис вроде Cloudflare, который видит картину по всему трафику, а не по логам сервера.
Как не заблокировать самого себя во время настройки защиты?
Прежде чем ужесточать правила, нужно заранее добавить собственный IP-адрес в список исключений fail2ban — тогда сервис не станет банить его вместе со всеми остальными при проверках и тестах. Если доступ всё же пропал, обычно достаточно подождать истечения срока блокировки или снять бан через другой канал доступа, например консоль провайдера.
Останавливает ли CAPTCHA автоматизированных ботов полностью?
Не полностью — при целевой атаке на конкретный сайт CAPTCHA можно обойти с помощью платных сторонних сервисов распознавания, которые решают задачку за реального человека на стороне. Поэтому CAPTCHA стоит рассматривать как один из уровней защиты, а не как окончательное решение, и дополнять её поведенческим анализом или комбинировать с rate limiting и fail2ban.
Почему после настройки rate limiting легитимные пользователи иногда получают ошибку слишком частых запросов?
Обычно причина в том, что значение частоты запросов или всплеска (burst) выставлено строже, чем реальный профиль нагрузки формы — например, пользователь случайно отправляет форму дважды подряд или браузер повторяет запрос из-за медленного соединения. Решение — пересмотреть параметры зоны ограничения под реальные сценарии использования, а не просто снижать порог блокировки наугад.