Реалізація обмеження спроб входу на сайті
Минулого місяця до нас звернувся клієнт: їхній 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 разів. Отримайте консультацію — зв'яжіться з нами. Замовте впровадження — ми зв'яжемося протягом дня.







