Условие
Друг хочет написать веб-сервис с регистрацией и входом. Какие рекомендации вы дадите ему по безопасной реализации аутентификации? Перечислите несколько предложений.
Решение
1. Хранение паролей
- Никогда не хранить в открытом виде. И не «MD5», и не «SHA-256». Только современные slow KDF:
bcrypt,scrypt,argon2id. - Пароли + соль (salt), уникальная для каждого пользователя, длиной ≥ 16 байт. Соль хранится рядом с хешем.
- Cost-параметры подбираются так, чтобы один хеш считался ~100 мс на текущем железе. Для
argon2id—m=64MiB, t=3, p=1как стартовая точка (OWASP).
2. Политика паролей
- Минимум 8–12 символов (NIST 800-63B), без обязательных «спец-символов и Big/small» — это снижает энтропию.
- Проверять по базе утечек (HaveIBeenPwned k-anonymity API: посылаем первые 5 символов SHA1, получаем список суффиксов).
- Запрет «топ-100 распространённых паролей».
- Не требовать смену пароля периодически без причины (NIST ушёл от этого).
3. Защита от перебора
- Rate-limiting на эндпоинт логина: например, не более 5 попыток / 5 минут / IP, плюс на аккаунт независимо от IP.
- Captcha после нескольких неудач.
- Account lockout с экспоненциальной задержкой (или вместо лока — задержка ответа). Полный лок открывает DoS-вектор.
- Login-функции отвечают одинаково при «нет такого пользователя» и «неверный пароль» — иначе утечка существующих логинов.
4. Многофакторная аутентификация (MFA)
- TOTP (Google Authenticator, RFC 6238) — обязателен как опция.
- WebAuthn / FIDO2 — gold standard, защищает от фишинга.
- SMS-OTP — допустим, но не основной: SIM-swap.
- При установке MFA — печатать «recovery codes», 8–10 одноразовых.
5. Сессии
- Сессионный токен — криптографически случайный (≥ 128 бит энтропии), на сервере мапится на user_id.
- В HttpOnly + Secure + SameSite=Lax/Strict cookie. JS не должен иметь доступ к токену.
- Идemпотентный logout — обязательно инвалидирует токен на сервере.
- Регенерация ID после логина (защита от Session Fixation).
- Истечение по неактивности (idle timeout, ~30 мин) и абсолютное (~12-24 часа).
6. JWT — аккуратно
Если используется JWT:
- Только подписанные
RS256/EdDSA, неHS256с шаренным секретом на клиенте. - Не хранить в localStorage (XSS-риск). Только HttpOnly cookie.
- Короткий TTL (15 мин) + refresh-token rotation.
- Запретить алгоритм
none(CVE-2015-2951).
7. Защита от CSRF
- Если используете cookie-based сессии — CSRF-токены для всех state-changing запросов.
- Либо
SameSite=Strict+ double-submit cookie + проверкаOrigin/Referer.
8. Восстановление пароля
- Ссылка с одноразовым криптослучайным токеном, TTL ≤ 1 час, single-use.
- Не отправлять текущий пароль на почту (это значит — он был восстановим из БД, что плохо).
- После сброса — инвалидировать все активные сессии пользователя.
- Generic-ответ: «Если такая почта зарегистрирована — мы отправили ссылку».
9. Регистрация и валидация email
- Подтверждение email через одноразовую ссылку (TTL).
- Не отдавать «такая почта уже зарегистрирована» — это user enumeration. Лучше: «инструкция отправлена на почту».
10. HTTPS, HSTS, secure-headers
- Только TLS 1.2+, обязательный
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload. Content-Security-Policyдля защиты от XSS (особенно если токен в localStorage / любой рендеринг user-input).X-Frame-Options: DENYили CSPframe-ancestors 'none'против clickjacking.
11. Логирование и алертинг
- Логи логинов (успех/провал) — без паролей, с IP/User-Agent.
- Алерт на «новое устройство» / «новая страна».
- SIEM-правила на массовый brute-force.
Подводные камни
- MD5/SHA — это хеши, не KDF. Они рассчитываются миллионами в секунду на GPU. Только bcrypt/argon2/scrypt.
- Сложные требования к паролю, как
1 заглавная + 1 цифра + 1 спецсимвол, дают пользователям предсказуемые паттерны (Password1!). Лучше длина + проверка по утечкам. - JWT в localStorage = XSS-крах. Все думают, что localStorage «удобнее», но любой XSS = слив токена.
PUT /reset-password?token=...без проверки одноразовости даёт атаку повторного использования при перехвате ссылки.- Email-validation без подтверждения: regex проверяет формат, но не реальность. Без
confirm-emailвозможны фейковые регистрации. - Брутфорс не только пароля. Атакуют username (enumeration), сессионные токены (если короткие), reset-token (если предсказуем).
- «Запомнить меня» на год = огромное окно компрометации. Делать «remember me» через долгоживущий refresh-token с возможностью отозвать.
Эталонный ответ
Argon2id для паролей; rate-limiting + одинаковые ответы на login; обязательный TOTP/WebAuthn; HttpOnly+Secure+SameSite сессии; CSRF-токены; HSTS+TLS 1.2+; secure-headers; одноразовые reset-токены с TTL и инвалидацией всех сессий.