Брутфорс-атаки — перебір паролів автоматизованими ботами — залишаються одним з найпоширеніших векторів злому. Щодня на типовий 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-подібні системи (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) виставлено суворіше, ніж реальний профіль навантаження форми — наприклад, користувач випадково надсилає форму двічі поспіль або браузер повторює запит через повільне з'єднання. Рішення — переглянути параметри зони обмеження під реальні сценарії використання, а не просто знижувати поріг блокування навмання.