Rate limit в Nginx: ошибки защиты от перебора паролей
Nginx может отсекать частые запросы к форме входа ещё до приложения, но неверный ключ лимитера способен наказать всех пользователей за одним NAT. Разбираем типичные ошибки настройки, сравниваем уровни защиты и показываем, что проверять.

Лимит на запросы к странице входа кажется простой защитой: задать максимум попыток и заблокировать лишнее. На практике ошибка в ключе Nginx может ограничить целый офис за одним NAT, а лимит только по IP не остановит распределённый перебор. Разбираем практический вариант для Nginx 1.24 и новее: что ставить на прокси, что оставить приложению и как не закрыть доступ обычным пользователям.
Сначала определите, где Nginx видит клиента
До настройки проверьте сетевой путь запроса. Если перед Nginx стоит балансировщик или CDN, переменная $remote_addr обычно содержит адрес ближайшего прокси, а не пользователя. Тогда лимитер считает всех посетителей одним клиентом. Обратная ошибка — бездумно доверять заголовку X-Forwarded-For: клиент может прислать его сам и менять значение между запросами.
Настройте получение исходного адреса только от известных прокси и проверьте результат в access log. Не добавляйте доверенные сети «на глаз»: диапазоны должны соответствовать вашей инфраструктуре. Если прямой доступ к Nginx возможен в обход CDN, отдельно закройте его на сетевом уровне.
- Зафиксируйте, какие прокси действительно могут подключаться к Nginx.
- Сделайте несколько запросов через обычный пользовательский путь и проверьте, что в журнале указан адрес клиента.
- Повторите проверку при прямом обращении к серверу, если оно технически возможно.
Если исходный IP ещё не восстановлен корректно, сначала исправьте эту часть, а уже потом задавайте лимиты. Иначе даже аккуратно подобранные числа будут работать не на того пользователя.
Три уровня защиты и цена каждого
| Уровень | Что ограничивает | Чем платите |
|---|---|---|
| Nginx по IP | Частоту запросов с одного адреса до приложения | Пользователи за общим IP делят лимит; несколько адресов обходят ограничение |
| Приложение по аккаунту | Попытки входа в конкретную учётную запись | Нужны хранение счётчиков, политика сброса и защита от блокировки чужих аккаунтов |
| Распределённый лимитер | Счётчики, общие для нескольких экземпляров приложения | Дополнительная зависимость и необходимость продумать отказ хранилища |
Для одиночного веб-сервера начните с лимита Nginx на конкретном маршруте входа. Приложение всё равно должно ограничивать попытки с учётом аккаунта: IP-лимит не видит, что перебор распределён по адресам. Если приложение запущено в нескольких экземплярах, его счётчик должен быть общим или согласованным между ними. Локальный счётчик каждого процесса легко обойти, отправляя запросы на разные экземпляры.
Как задать лимит в Nginx
В примере используется модуль ngx_http_limit_req_module, доступный в стандартной поставке Nginx. Конфигурация рассчитана на ситуацию, где $remote_addr уже содержит реальный адрес клиента. Значение rate=5r/m здесь — стартовый пример, а не универсальная рекомендация: подберите его по поведению пользователей и нагрузочным тестам.
http {
limit_req_zone $binary_remote_addr zone=login_by_ip:10m rate=5r/m;
server {
location = /login {
limit_req zone=login_by_ip burst=3 nodelay;
limit_req_status 429;
proxy_pass http://application;
}
}
}
Проверьте, что ваш блок server действительно направляет запросы к приложению как задумано: строка proxy_pass в примере предполагает настроенный upstream с именем application. Замените её на существующую схему проксирования проекта. Перед применением проверьте конфигурацию штатной командой nginx -t, затем перечитайте конфигурацию способом, который принят в вашей системе.
Зона login_by_ip хранит ключи лимитера в общей памяти Nginx. burst=3 разрешает небольшой всплеск сверх обычной скорости, а nodelay не заставляет эти запросы ждать в очереди. В результате лишний запрос может получить ответ 429 сразу. Если убрать nodelay, часть запросов будет задерживаться; это меняет поведение и задержки, а не отменяет ограничение.
Сопоставление location = /login точное: оно не охватывает, например, /login/ или отдельный API-маршрут авторизации. Добавьте лимит на все реально используемые точки входа. Не ставьте его на весь сайт без причины: так можно ограничить загрузку статики, поиск или другие безопасные действия.
Ошибки, из-за которых защита не помогает
Ограничивают только IP
Один человек может менять адреса, а злоумышленник — распределять попытки между ними. На уровне приложения полезен отдельный счётчик по нормализованному идентификатору аккаунта. Не отвечайте злоумышленнику, существует ли такой аккаунт: одинаковая реакция на неверный пароль и неизвестный логин снижает риск перечисления пользователей.
Навсегда блокируют аккаунт после нескольких ошибок
Так можно устроить отказ в обслуживании чужой учётной записи: достаточно отправить неверные пароли за её владельца. Вместо вечной блокировки используйте ограничение по времени, постепенное увеличение задержки или дополнительную проверку. Числа и срок выбирайте с учётом риска, а разблокировку проектируйте так, чтобы она не превращалась в обход защиты.
Забывают про несколько экземпляров приложения
Если каждый сервер ведёт собственный счётчик, запросы распределяются между ними. Лимит на одном узле не равен лимиту на весь сервис. Проверьте поведение при балансировке и перезапуске: сохраняется ли счётчик, и не сбрасывается ли он слишком легко.
Не проверяют ответ и журнал
Не ограничивайтесь проверкой синтаксиса. В тестовой среде отправьте серию запросов с одного адреса и убедитесь, что после заданного всплеска появляются ответы 429, а обычная навигация не затронута. Сверьте журналы Nginx и приложения: видно ли, какие запросы были ограничены, и не пишется ли туда пароль или токен.
Лимит по IP — это фильтр на входе, а не полноценная защита учётной записи. Если забыть об этом, аккуратная настройка Nginx создаст видимость безопасности.
Как выбирать значения, не гадая
Соберите базовую картину до включения строгого ограничения: частоту запросов к авторизации, долю неуспешных входов и число пользователей за общими адресами. В тестовой среде проверьте вход обычного пользователя, повторную отправку формы, мобильную сеть и работу за корпоративным NAT. Затем включайте лимит и наблюдайте за ответами 429 и жалобами на невозможность войти.
Счётчик обращений к маршруту — не то же самое, что счётчик неверных паролей. На Nginx можно ограничить запросы к точке входа, но он не знает, успешна ли проверка пароля внутри приложения. Поэтому метрики приложения должны отдельно показывать ошибки аутентификации и частоту по аккаунтам. Не логируйте секреты ради диагностики.
Подводный камень: если приложение доступно напрямую из интернета, атакующий может обойти Nginx. Разрешите вход к приложению только через доверенный прокси или продублируйте защиту на доступном извне уровне.
Состояние зоны — записи лимитера, которые Nginx держит в общей памяти. Это не постоянное хранилище: перезапуск или изменение конфигурации может повлиять на счётчики. Если защита должна работать согласованно на нескольких узлах и переживать их смену, одного локального состояния недостаточно.
Что делать дальше
Начните с маршрутов входа и фактического адреса клиента в журналах. Затем проверьте ответ 429, поведение за NAT и обход Nginx напрямую. После этого настройте в приложении отдельные ограничения по аккаунту и измеряйте не только количество запросов, но и долю отказов при входе. Инвалидация сессий и многофакторная аутентификация решают другие задачи — здесь речь только о частоте запросов и переборе паролей.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: Документация Nginx: модуль ngx_http_limit_req_module, OWASP Authentication Cheat Sheet
Частые вопросы
Достаточно ли ограничить вход только в Nginx?
Какой лимит запросов поставить на форму входа?
Почему Nginx ограничивает всех пользователей офиса?
Можно ли блокировать аккаунт после нескольких неправильных паролей?
Поможет ли лимитер Nginx, если приложение работает на нескольких серверах?
Как понять, что настройка работает?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.