Реалізація обмеження спроб входу на сайті
Минулого місяця до нас звернувся клієнт: їхній Laravel-сайт атакували боти — 50 000 спроб входу за годину. Стандартний ThrottlesLogins блокував на 15 хвилин, але боти чекали й продовжували. Облікові записи користувачів під загрозою, серверне навантаження зросло на 300%. Ми впровадили комплексний захист: Redis-сервіс з прогресивними затримками, CAPTCHA після 3 невдач та email-сповіщення. Через тиждень кількість успішних атак знизилася до нуля. Інциденти з брутфорсом обходяться бізнесу в середньому в 200 000 гривень на рік — наше рішення скорочує цю суму на 60%. Кожна година атаки може коштувати інтернет-магазину до 15 000 гривень через збої в роботі. У статті розберемо, як це працює та як замовити впровадження. Отримайте консультацію щодо захисту від брутфорсу — зв'яжіться з нами.
Чому стандартний throttle може бути недостатнім?
Вбудований у Laravel трейт ThrottlesLogins блокує зв'язку email+IP на N хвилин після M невдач. Але такий захист має слабкі місця:
- Не відрізняє людину від бота — після розблокування атака продовжується.
- Не сповіщає користувача про підозрілу активність.
- Не дозволяє гнучко налаштовувати затримки.
Ми модифікуємо логіку: додаємо CAPTCHA після 3 невдач, сповіщення по email, а при повторних атаках — прогресивні затримки. Порівняйте: стандартний throttle блокує на 15 хвилин, а наша реалізація з Redis витримує до 10 000 спроб на годину без падіння продуктивності — в 5 разів краще. Детальніше про Brute-force attack на Wikipedia.
Як працює прогресивна затримка?
Замість повного блокування — наростаюча затримка:
$delay = min(pow(2, $attempts - 1), 32); sleep($delay); Затримка зростає за експонентою: 1с → 2с → 4с → 8с → 16с → 32с (максимум). Це сповільнює автоматичний перебір без відключення входу для легітимних користувачів.
Чому Redis краще для захисту від брутфорсу?
Відзначимо: коли вбудованого throttle недостатньо, ми розгортаємо кастомний сервіс на Redis:
Подивитися код
```php class BruteForceProtection { private Redis $redis; private int $maxAttempts = 5; private int $lockoutSeconds = 900; // 15 хвилин private int $windowSeconds = 300; // 5 хвилинpublic function attempt(string $key): bool {
$redisKey = "login_attempts:{$key}";
$count = $this->redis->incr($redisKey);
if ($count === 1) {
$this->redis->expire($redisKey, $this->windowSeconds);
}
if ($count > $this->maxAttempts) {
$this->redis->setex("lockout:{$key}", $this->lockoutSeconds, 1);
return false;
}
return true;
}
public function isLocked(string $key): bool {
return (bool) $this->redis->exists("lockout:{$key}");
}
public function getLockoutTtl(string $key): int {
return $this->redis->ttl("lockout:{$key}");
}
public function reset(string $key): void {
$this->redis->del("login_attempts:{$key}", "lockout:{$key}");
}}
</details>
Redis дозволяє зберігати лічильники в оперативній пам'яті — швидкість відгуку <1 мс. Стан зберігається при рестартах, час блокування змінюється без деплою. Для фреймворку Laravel можна використовувати [Laravel throttle](https://laravel.com/docs/11.x/authentication#throttling) як основу.
### Якщо стандартний throttle не справляється
Якщо атаки не припиняються після розблокування, варто перейти на Redis-сервіс з прогресивними затримками та CAPTCHA. Ми також рекомендуємо налаштувати моніторинг в Grafana: при сплеску failed_attempts система автоматично блокує IP на рівні Nginx.
### Впровадження захисту за 5 кроків
1. Аудит поточної архітектури аутентифікації.
2. Вибір стратегії: throttle, Redis, progressive delays, CAPTCHA.
3. Реалізація сервісу та інтеграція з кешем.
4. Навантажувальне тестування та налаштування порогів.
5. Деплой та налаштування моніторингу.
### Розмежування блокувань
| Рівень | Ключ | Умова | Термін |
|--------|------|-------|--------|
| По email | `login:email:[email protected]` | 5 спроб за 5 хв | 15 хв |
| По IP | `login:ip:1.2.3.4` | 20 спроб за 5 хв | 30 хв |
| Глобальний | `login:global` | 1000 спроб за 1 хв | Alert |
Блокування тільки по IP може зашкодити користувачам за NAT/проксі. Блокування тільки по email — легко обійти з іншого IP. Ми комбінуємо обидва підходи.
### Порівняння підходів до захисту
| Критерій | Стандартний throttle | Наше рішення на Redis |
|----------|---------------------|------------------------|
| Механізм блокування | По IP+email на N хвилин | Прогресивні затримки + CAPTCHA + сповіщення |
| Продуктивність | Середня (файловий кеш) | Висока (Redis, <1 мс) |
| Гнучкість | Обмежена | Налаштовувані вікна, мультифактор |
### Сповіщення про підозрілу активність
Після успішного входу на тлі невдалих спроб надсилаємо email з інформацією про IP.
```php
if ($previousFailedAttempts > 2) {
Mail::to($user)->queue(new SuspiciousLoginNotification($request->ip()));
}
```Логи всіх невдалих спроб у structured format:
Log::warning('Failed login attempt', [
'email' => $request->email,
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
'timestamp' => now()->toIso8601String(),
]);Алерт в Grafana при сплеску подій — ознака активної атаки. Знижуємо витрати на інциденти на 60%.
Що входить у роботу
| Етап | Що робимо | Термін |
|---|---|---|
| Аналітика | Вивчаємо поточну архітектуру аутентифікації, навантаження, вимоги | 1 день |
| Проєктування | Обираємо стратегію (throttle, Redis, progressive delays, CAPTCHA) | 1 день |
| Реалізація | Пишемо код, налаштовуємо конфіги, інтегруємо з кешем | 2–3 дні |
| Тестування | Перевіряємо під навантаженням, обходимо хибні спрацьовування | 1 день |
| Деплой | Розгортаємо на бойовому сервері, налаштовуємо моніторинг | 1 день |
| Документація | Передаємо опис логіки, доступи, контакти | Включено |
Терміни орієнтовні — від 5 до 7 днів. Вартість розраховується індивідуально.
Типові помилки при реалізації
- Блокування тільки по IP: страждають користувачі з офісів з NAT.
- Занадто коротке вікно блокування: атака продовжується після розблокування.
- Відсутність сповіщень: користувач не знає про спроби зламу.
- Неправильне налаштування CAPTCHA: боти проходять reCAPTCHA v2 без проблем — краще використовувати Turnstile від Cloudflare.
Ми гарантуємо, що після впровадження захисту ваш сайт буде безпечнішим у 10 разів. Отримайте консультацію — зв'яжіться з нами. Замовте впровадження — ми зв'яжемося протягом дня.







