Короткий ответ
Комбинируют несколько уровней защиты: ограничение частоты попыток по IP и по аккаунту отдельно, временную задержку или блокировку после нескольких неудачных попыток, и постепенное усложнение проверки (например, CAPTCHA) после подозрительной активности, вместо одной жёсткой меры.
Как это работает подробнее
Лимит по IP защищает от массового перебора с одного источника, а лимит по конкретному аккаунту (независимо от IP) защищает от распределённой атаки credential stuffing с разных IP на один и тот же логин; после N неудачных попыток вводится растущая задержка или временная блокировка аккаунта на короткий срок.
Пример кода
example.txt
Попытка логина:
increment(counter_by_ip[ip])
increment(counter_by_account[username])
if counter_by_ip[ip] > 20/min or counter_by_account[username] > 5/min:
return 429 "too many attempts, try later"
if password invalid:
return 401 "invalid username or password" # одинаковое сообщение для всех случаевЧто использовать на практике
- Практика. Важно не раскрывать в ответе, существует ли аккаунт с данным логином (одинаковое сообщение «неверный логин или пароль» для обоих случаев), и логировать подозрительные паттерны для последующего анализа и алертинга; для API также полезны второй фактор аутентификации (MFA) и мониторинг необычной геолокации.
Подводные камни
- Риск. Ограничивают только по IP, что не помогает против credential stuffing с ботнета; блокируют аккаунт надолго после нескольких неудачных попыток, что превращается в DoS-вектор против конкретного пользователя; возвращают разные сообщения об ошибке для «нет такого пользователя» и «неверный пароль».