security(auth): anti-enumeration, returnTo-валидация, лимит попыток логина
Шаг 2.1 плана production-готовности: - единый 401 при любом отказе логина + constant-time bcrypt - forgot-password: идентичный ответ независимо от существования email - sanitizeReturnTo (open redirect fix в /api/documents/generate-link) - 10 неудачных попыток → блок 15 мин (in-memory, аудит) - DATABASE_SSL_REJECT_UNAUTHORIZED env (дефолт true) - доделка 0.7: статичные тексты в llm-providers/rag/finance-di2 - 8 новых тестов (104/104)
This commit is contained in:
@@ -309,3 +309,19 @@
|
||||
- Как проверялось: `npm run check` чисто; vitest зелёные; lint 0 errors; `npm run build` собирается.
|
||||
- Влияние на поиск/UX: нет.
|
||||
- Подводные камни: dompurify используется в client/src/lib/htmlUtils.ts для rich-text — обновление патчевое, API совместим.
|
||||
|
||||
---
|
||||
|
||||
## [2.1] Средние security-фиксы
|
||||
|
||||
- Статус: ✅ done
|
||||
- Зачем: anti-enumeration, open redirect, брутфорс, явный SSL, доделка 0.7 (Фаза 2).
|
||||
- Что изменено:
|
||||
- Anti-enumeration: `server/services/auth.service.ts` — bcrypt-сравнение всегда (dummy-хэш), единый 401 «Неверный email или пароль» для всех причин отказа; forgot-password — идентичный 200 «Если аккаунт существует…» независимо от email.
|
||||
- returnTo: `server/utils/return-to.ts` + `client/src/lib/return-to.ts` — только относительные пути с одиночным `/` (отброс //host, /\host, ctrl-символов); применено в auth и /api/documents/generate-link (был open redirect через res.redirect).
|
||||
- Лимит логина: `server/utils/login-attempts.ts` — 10 неудачных → блок 15 мин (in-memory, сброс при успехе), аудит auth.login.locked; поверх authLimiter по IP.
|
||||
- SSL: `server/db.ts` — rejectUnauthorized через env DATABASE_SSL_REJECT_UNAUTHORIZED (дефолт true).
|
||||
- Доделка 0.7: 200+success:false с err.message зачищены в llm-providers/rag/finance-di2.
|
||||
- Как проверялось: 8 новых тестов (tests/auth-security.test.ts) — vitest 104/104; check/lint чисто.
|
||||
- Влияние на поиск/UX: нет; UX логина: деактивированный аккаунт видит «Неверный email или пароль» (цель anti-enumeration), после 10 попыток — сообщение о 15-минутной блокировке.
|
||||
- Подводные камни: блокировки in-memory (рестарт обнуляет; multi-instance делит лимит — как остальные кэши).
|
||||
|
||||
Reference in New Issue
Block a user