Ограничение скорости и защита от перебора перед продакшеном
Один лимит на IP не защищает API от перебора и легко блокирует живых пользователей. Чек-лист поможет разделить лимиты по операциям, выбрать место для проверки и проверить систему до выхода в продакшен.

Если поставить один лимит на IP для всего API, вы получите ложное чувство защиты: атакующий сменит адреса, а пользователи за общим NAT начнут видеть 429. Перед продакшеном нужно отдельно ограничить вход в систему, восстановление пароля, отправку кодов и обычные запросы, а затем проверить, что лимиты работают одинаково на всех экземплярах приложения. Ниже — практический чек-лист для HTTP API за Nginx 1.25+ с Redis 7.x или другим общим хранилищем счётчиков.
Сначала разделите две разные задачи
Ограничение скорости защищает ресурс от слишком большого числа запросов. Защита от перебора препятствует угадыванию паролей, кодов подтверждения и других секретов. Эти механизмы пересекаются, но не заменяют друг друга.
- Rate limit. Сдерживает поток запросов к API, чтобы один клиент не занял соединения, CPU или лимиты внешнего сервиса.
- Brute-force protection. Учитывает не только частоту запросов, но и число неудачных попыток для учётной записи, номера телефона, email или конкретной операции.
- Защита от распределённой атаки. Не позволяет обходить лимит простой сменой IP-адресов.
Хороший лимит отвечает не на вопрос «сколько запросов разрешить IP», а на вопрос «какой ресурс мы защищаем и что считать одной попыткой».
Сноска. Token bucket — алгоритм с «ведром» токенов: каждый запрос расходует токен, а токены постепенно пополняются. Он позволяет пропускать короткие всплески, сохраняя среднюю скорость ниже заданного порога.
Проверьте, что именно вы ограничиваете
До настройки лимитов составьте карту дорогих и чувствительных операций. У них не может быть одного общего порога: запрос списка товаров и проверка пароля имеют разную цену и разные последствия ошибки.
- Аутентификация: вход по паролю, обновление токена, проверка одноразового кода.
- Восстановление доступа: запрос письма, SMS или ссылки для сброса пароля.
- Регистрация и приглашения: создание аккаунта, отправка приглашения, подтверждение контакта.
- Дорогие операции: экспорт, поиск по большим объёмам данных, генерация отчёта, вызов платного внешнего API.
- Обычный трафик: чтение публичных данных, работа личного кабинета и запросы мобильного клиента.
Для каждой операции зафиксируйте ключ лимита. Это может быть IP-адрес, идентификатор пользователя, отпечаток сессии, email, номер телефона или комбинация нескольких признаков. Не используйте единственный ключ там, где атакующий может менять его без существенных затрат.
Выберите место для проверки
У ограничения на границе сети есть преимущество: запрос отбрасывается до приложения и не расходует его пул соединений. Но Nginx не знает, была ли попытка входа успешной, поэтому не может сам корректно считать ошибки пароля для конкретного аккаунта. Проверка в приложении видит бизнес-контекст, но выполняется позже.
| Слой | Что ограничивать | Плюсы | Риски и цена |
|---|---|---|---|
| CDN или WAF | Общий поток, географию, очевидный мусор | Снижает нагрузку до вашей инфраструктуры | Мало контекста о пользователе; правила зависят от поставщика |
| Nginx или ingress | Запросы по IP, маршруту и группе клиентов | Дёшево отбрасывает лишний трафик | На нескольких узлах нужен общий или согласованный лимит |
| Приложение | Ошибки входа, код подтверждения, действия аккаунта | Видит результат операции и бизнес-правила | Запрос уже дошёл до приложения; нужна защита от гонок |
| Общее хранилище | Счётчики между экземплярами API | Единое состояние при горизонтальном масштабировании | Появляются задержки, отказоустойчивость и срок жизни ключей |
Практичная схема обычно многоуровневая: грубый лимит на CDN или Nginx, точный лимит чувствительной операции в приложении, а счётчики — в общем хранилище. Это не означает, что каждому проекту нужны все четыре слоя. Добавляйте слой только тогда, когда он закрывает конкретный обход или снижает нагрузку.
Сверьте лимиты с моделью угроз
IP — только один из признаков
IP-адрес полезен для внешнего периметра, но плохо подходит как единственный идентификатор. За одним адресом могут находиться офис, мобильный оператор, университет или домашняя сеть. У атакующего, наоборот, могут быть прокси и ботнет.
Для входа проверяйте несколько независимых условий:
- ограничение общего числа запросов с IP, чтобы защитить периметр;
- ограничение попыток для конкретной учётной записи или нормализованного email;
- ограничение комбинации «IP плюс аккаунт», чтобы усложнить распределённый перебор;
- отдельный лимит на выдачу подсказки о существовании аккаунта, если такой ответ возможен.
Не стройте ключ на непроверенном заголовке вроде X-Forwarded-For. Сначала настройте список доверенных прокси и убедитесь, что приложение получает реальный адрес клиента только от них. Иначе пользователь сможет подменять адрес заголовком, а все попытки будут распределяться по выдуманным IP.
Считайте не только запросы, но и результат
Для перебора важна не частота всех обращений к endpoint, а число неудачных проверок секрета. Успешный вход обычно не должен навсегда оставаться в том же счётчике, что и ошибки. Для кода из SMS или приложения нужен отдельный счётчик: повторная отправка кода, проверка кода и запрос нового кода — разные операции.
Счётчик должен иметь срок жизни. Бессрочная блокировка создаёт операционные проблемы: поддержке приходится вручную искать и снимать блоки, а пользователь не понимает, когда сможет войти. Для подозрительных серий попыток лучше предусмотреть нарастающую задержку или временную блокировку, но не делать её единственной защитой от распределённой атаки.
Определите поведение API при превышении
Клиент должен отличать отказ по лимиту от неверного пароля, отсутствия прав и временной ошибки сервера. Для превышения частоты запросов используйте HTTP 429 Too Many Requests. Если время ожидания известно, передавайте Retry-After и документируйте, как клиенту повторять запрос.
- Не возвращайте секреты, внутренние ключи счётчиков и точную причину срабатывания правила.
- Не раскрывайте существование email или телефона в ответах восстановления доступа.
- Для чувствительных операций используйте одинаковые по смыслу ответы при существующем и отсутствующем аккаунте.
- Не заставляйте мобильный клиент повторять запрос без задержки: это превращает 429 в дополнительную нагрузку.
- Логируйте срабатывание правила отдельно от обычных ошибок авторизации.
Уведомление пользователя и технический ответ API — не одно и то же. Человеку можно показать «попробуйте позже», но в ответе для клиента должны быть стабильный статус и предсказуемый формат. Иначе разные версии приложения начнут по-разному обрабатывать один и тот же отказ.
Проведите проверку до релиза
Тестируйте не только одиночный запрос с одного IP. Нужны сценарии, которые имитируют реальное распределение трафика и отказ отдельных компонентов. Для нагрузочного теста используйте тестовую среду или явно выделенный маршрут: случайный запуск на продакшене сам станет инцидентом.
- Проверьте точность. Отправьте запросы чуть ниже, на границе и выше лимита. Зафиксируйте число разрешённых запросов и момент появления 429.
- Проверьте всплеск. Убедитесь, что выбранный алгоритм разрешает или запрещает короткий burst именно так, как задумано. Для token bucket проверьте размер «ведра» и скорость пополнения.
- Проверьте несколько экземпляров. Направьте последовательность запросов через разные узлы. Если лимит считается отдельно на каждом узле, это должно быть осознанным решением, а не случайностью балансировщика.
- Проверьте конкурентность. Запустите параллельные запросы к одному ключу. Счётчик не должен терять обновления из-за гонки.
- Проверьте отказ хранилища. Решите заранее, что произойдёт при недоступности Redis: fail-open пропустит трафик, fail-closed начнёт блокировать запросы. Для входа, платежей и публичного чтения решения могут отличаться.
- Проверьте восстановление. Убедитесь, что ключи счётчиков истекают, временная блокировка снимается по правилам, а ручная разблокировка доступна только сотрудникам с аудитом действий.
Что измерять после включения
До изменения правил снимите базовые показатели, иначе после релиза будет трудно понять, стало ли лучше. Минимальный набор — доля ответов 429 по маршрутам, количество неудачных попыток входа, p95 и p99 задержки, нагрузка на хранилище счётчиков, ошибки соединения с ним и доля обращений к восстановлению пароля.
Разбивайте метрики по маршруту, версии клиента, стране или региону и типу ключа, но не публикуйте в логах пароли, коды, токены и полные email. Для расследования достаточно хеша или внутреннего идентификатора с ограниченным доступом. Отдельно поставьте алерт на резкий рост 429: он может означать атаку, слишком строгий лимит или ошибку клиента, который ушёл в цикл повторов.
Где подход ломается
Один и тот же дизайн не подходит всем системам. Лимит по IP ломается при массовом NAT и при смене адресов. Лимит только по аккаунту уязвим к перебору большого числа учётных записей. Лимит только на вход не защищает отправку кодов и восстановление доступа. Локальные счётчики в памяти процесса расходятся при масштабировании и обнуляются после перезапуска.
Не полагайтесь на CAPTCHA как на единственный барьер: она снижает автоматизацию, но не заменяет лимиты, аудит и защиту аккаунта. Не включайте бесконечную блокировку после нескольких ошибок — это превращает механизм защиты в инструмент отказа в обслуживании для чужих аккаунтов. Наконец, не меняйте лимиты без наблюдаемости: без метрик вы не увидите, что заблокировали реальных клиентов.
Когда что выбирать
Для публичного чтения начните с лимита на границе сети и кэширования там, где оно безопасно. Для входа добавьте составной ключ «IP, аккаунт, операция» и счётчик неудачных попыток в приложении. Для одноразовых кодов разделите отправку и проверку. Для нескольких экземпляров API используйте общее хранилище только после проверки его задержек и поведения при отказе.
Следующий шаг — составить таблицу маршрутов с владельцем, стоимостью запроса, ключом лимита, статусом при превышении и метрикой. После этого прогоните шесть тестов из чек-листа на стенде, включите дашборд 429 и только затем переносите правила в продакшен. Инвалидация сессий и управление украденными токенами — отдельная тема: здесь рассматриваются только скорость запросов и перебор секретов.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: RFC 6585: Additional HTTP Status Codes, NGINX ngx_http_limit_req_module documentation
Частые вопросы
Достаточно ли ограничить запросы по IP-адресу?
Какой HTTP-статус возвращать при превышении лимита?
Что произойдёт, если Redis недоступен?
Можно ли хранить счётчики в памяти приложения?
Не заблокирует ли лимит пользователей за общим NAT?
Нужно ли добавлять CAPTCHA после нескольких ошибок?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.