Skip to content

feat(security): rate-limit на /api/auth/login и /api/auth/register#19

Merged
Br1Im merged 2 commits into
mainfrom
devin/1778715097-rate-limit-login
May 14, 2026
Merged

feat(security): rate-limit на /api/auth/login и /api/auth/register#19
Br1Im merged 2 commits into
mainfrom
devin/1778715097-rate-limit-login

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

Защита от брутфорса. Раньше любой мог долбить /api/auth/login сколько угодно — bcrypt rounds=10 даёт всего ~5-10 попыток/сек/тред, но при ботнете это вполне реальная атака. Теперь:

  • /api/auth/login10 неуспешных попыток на 15 минут с одного IP. Успешные логины не считаются (skipSuccessfulRequests: true), так что легитимные пользователи не страдают.
  • /api/auth/register5 регистраций в час с одного IP (антиспам — мешает массово регистрировать фейковые аккаунты, что было бы DoS на email-таблицу и БД).

После исчерпания лимита — 429 Too Many Requests с понятным русским сообщением + стандартные заголовки RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset (RFC 6585 / IETF draft).

В NODE_ENV=test оба лимита подняты до 10000, чтобы не мешать integration-тестам.

Изменения

  • server/package.json + package-lock.json — добавлена зависимость express-rate-limit@^8.5.1.
  • server/routes/api.js:
    • Импортирован rateLimit.
    • Объявлены loginRateLimiter и registerRateLimiter (top of file).
    • Привешены к POST /auth/login и POST /auth/register соответственно.
  • server/__tests__/rate-limit.test.js — новый файл, +3 теста:
    • 429 после исчерпания лимита.
    • RateLimit-* заголовки на каждом ответе.
    • skipSuccessfulRequests: true не считает 2xx ответы.

Тесты

  • jest rate-limit.test.js: 3/3 PASS.
  • Полный backend Jest suite: 95/95 PASS (92 baseline + 3 новых).
  • Существующие auth-тесты (10 кейсов) проходят без изменений, потому что под NODE_ENV=test лимит = 10000 и фактически выключен.

Review & Testing Checklist for Human

  • Залить на сервер, попробовать сделать 11+ неуспешных логинов подряд из одного браузера — на 11-м должен прийти 429 с сообщением «Слишком много попыток входа».
  • Убедиться, что 10 успешных логинов подряд НЕ блокируются (skipSuccessfulRequests).
  • Проверить, что после 15 минут счётчик сбрасывается.

Notes

— Лимиты сейчас in-memory (per-process). Если в будущем будет несколько инстансов backend'а за load balancer'ом — нужно подключить Redis/Memcached store (rate-limit-redis), чтобы счётчики были общие. Сейчас один контейнер lawtech-backend, так что in-memory достаточно.
— Если фронт через прокси/CDN — нужно убедиться, что app.set('trust proxy', 1) в Express установлен, иначе IP клиента будет = IP прокси и все попадут в один счётчик. Сейчас этого нет, но и фронт обращается напрямую к backend через nginx на том же хосте, так что req.ip корректный.

Link to Devin session: https://app.devin.ai/sessions/514f368ad0194bf18d0327e62a88aeda
Requested by: @Br1Im

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@Br1Im Br1Im merged commit 114aa39 into main May 14, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant