Аутентификация отвечает на вопрос «кто это», авторизация на вопрос «что ему можно». Путать их на собесе нельзя, как и хранить пароли в MD5. Ниже то, что спрашивают от junior до senior.
Хранение паролей
Пароль никогда не хранят в открытом виде и не шифруют обратимо. Хранят медленный хеш с солью:
- Django по умолчанию использует PBKDF2 с SHA256 и сотнями тысяч итераций, поддерживает Argon2 и bcrypt через
PASSWORD_HASHERS. - В FastAPI-проектах берут
argon2-cffi,bcryptилиpwdlib. - MD5 и SHA-256 без растяжения не подходят: они быстрые, и видеокарта перебирает миллиарды вариантов в секунду.
Соль уникальна для каждого пароля и хранится рядом с хешем, она убивает радужные таблицы и одинаковые хеши у одинаковых паролей.
Сессии
После логина сервер создаёт запись сессии (в БД, Redis или подписанной cookie) и отдаёт браузеру cookie с id сессии. На каждый запрос сервер находит сессию и пользователя.
- Плюсы: мгновенный выход и отзыв (удалили сессию), сервер всё контролирует.
- Cookie ставят с флагами
HttpOnly(недоступна JS),Secure(только HTTPS),SameSite=Lax(защита от CSRF). - Для запросов, меняющих данные, нужна защита от CSRF (в Django
CsrfViewMiddleware).
Токены и JWT
JWT это подписанный токен из трёх частей header.payload.signature в base64url. Payload не зашифрован, его может прочитать кто угодно; подпись гарантирует, что содержимое не меняли.
payload = {'sub': '42', 'exp': now + 15 * 60, 'iat': now, 'type': 'access'}
token = jwt.encode(payload, SECRET, algorithm='HS256')
data = jwt.decode(token, SECRET, algorithms=['HS256']) # проверит подпись и exp
- Короткий access (5-15 минут) в заголовке
Authorization: Bearer ...и долгий refresh для получения новых access. Refresh хранят безопаснее (httpOnly cookie) и ротируют: каждый обмен выдаёт новый refresh, а старый становится недействительным. - Отозвать JWT до истечения нельзя без серверного состояния: нужен denylist или версия токенов у пользователя.
- При проверке явно задают допустимые алгоритмы, иначе возможны атаки с
alg: noneили подменой алгоритма. - В payload не кладут секреты и персональные данные.
OAuth 2.0 и OpenID Connect
OAuth 2.0 это протокол делегирования доступа: приложение получает токен на действия от имени пользователя у сервера авторизации (Яндекс ID, VK ID, Google). Для входа «через Яндекс» используется OpenID Connect поверх OAuth 2.0 с ID-токеном. Для браузерных и мобильных клиентов стандартом стал Authorization Code flow с PKCE.
Авторизация
- RBAC: роли с наборами разрешений (
admin,manager,viewer). - Проверка на уровне объекта: «редактировать можно только свой заказ» или «только в своей организации». Её отсутствие называется IDOR (небезопасная прямая ссылка на объект) и стабильно в топе уязвимостей.
- Проверять права нужно на сервере для каждого запроса, а не прятать кнопки во фронтенде.
Частые ошибки
- MD5, SHA1 или «свой» хеш для паролей, отсутствие соли.
- Сравнение токенов и подписей через
==вместоhmac.compare_digest(утечка по времени). - JWT без
exp, долгоживущий access, хранение токена вlocalStorageбез понимания рисков XSS. - Проверка только «пользователь вошёл» без проверки владельца объекта.
- Разные сообщения «нет такого email» и «неверный пароль», которые позволяют перебрать пользователей.
- Нет ограничения попыток входа.
Что спросят на собесе
- Чем аутентификация отличается от авторизации.
- Как правильно хранить пароли и почему не MD5.
- Сессии или JWT: плюсы и минусы, как отозвать JWT, зачем refresh.
- Что такое OAuth 2.0 и чем он отличается от OpenID Connect.
- Что такое IDOR и как построить проверку прав на уровне объектов.