Аутентификация и авторизация в API
Безопасность входа - обязательный блок собеса на бэкенде, и здесь много заученных полуправд. Проверяют, различаешь ли ты «кто ты» и «что тебе можно», понимаешь ли, что JWT не зашифрован и плохо отзывается, и не считаешь ли OAuth2 механизмом логина. Каждая путаница - потенциальная дыра.
Типовые формулировки: «чем аутентификация отличается от авторизации?», «безопасно ли класть данные в JWT?», «как отозвать JWT».
Кто ты и что тебе можно
Аутентификация - установление личности, «кто ты»: по токену, паролю, ключу. Авторизация - проверка прав, «что тебе можно»: по ролям или политикам. Порядок жёсткий - сначала первое, потом второе: нельзя проверять права, не зная, кто перед тобой. На кодах это ровно 401 (не аутентифицирован) и 403 (нет прав).
Путаница опасна тем, что легко проверить личность и забыть про права - тогда любой залогиненный пользователь дотянется до чужих данных (нарушение авторизации на уровне объекта).
// OAuth2 это про делегированный доступ, выдать приложению ограниченные права без пароля, а не про логин. «Кто вошёл» добавляет OpenID Connect поверх OAuth2.
- аутентификация
- установление личности (кто ты)
- авторизация
- проверка прав (что тебе можно)
JWT: подписан, но не зашифрован
JWT (JSON Web Token) это header.payload.signature. Подпись защищает от подмены: изменишь payload - подпись не сойдётся. Но payload всего лишь base64url-кодирован, НЕ зашифрован - его прочитает кто угодно, у кого есть токен. Поэтому секреты в payload не кладут.
JWT stateless: сервер его не хранит, а проверяет подпись и exp - валидный токен работает до истечения. Отсюда обратная сторона: мгновенно отозвать его нельзя. Решения - короткий TTL (time to live) плюс refresh-токен и/или денилист по jti для досрочного отзыва. Сессия наоборот хранит состояние на сервере (клиент носит session id) - трейдоф «масштабирование против контроля отзыва».
// Поэтому «JWT легко отозвать» - миф: без денилиста он валиден до exp, что бы ни случилось с пользователем.
header . payload . signature
^base64url, читается любым, кто держит токен- JWT
- подписанный токен header.payload.signature; payload читаем
- OAuth2/OIDC
- делегированный доступ; OIDC (OpenID Connect) добавляет аутентификацию
Как отвечать: «Безопасно ли хранить данные в payload JWT?»
Читаемые - да, чувствительные - нет. Payload JWT только base64url-кодирован, а не зашифрован, поэтому любой, у кого есть токен, прочитает его содержимое открытым текстом. Подпись гарантирует лишь целостность - что данные не подменили, но не конфиденциальность. Значит id пользователя, роль, срок - нормально, а пароли, номера карт, персональные секреты - категорически нет. И отдельно помню, что отозвать JWT мгновенно нельзя: он stateless и валиден до exp, поэтому ставлю короткий TTL с refresh-токеном, а для досрочного отзыва - денилист по jti.
Точно разведены целостность (подпись) и конфиденциальность (шифрования нет), дан критерий что можно/нельзя класть и добавлена связанная проблема отзыва с решением - полное понимание модели JWT.
На чём валят
- −Класть чувствительное в payload JWT: он подписан, но не зашифрован - читается кем угодно.
- −«JWT легко отозвать»: он stateless, валиден до exp; нужен короткий TTL или денилист по jti.
- −Считать OAuth2 механизмом логина: он про делегированный доступ, аутентификацию даёт OIDC.
- −Проверить личность и забыть проверить права на объект - залогиненный дотянется до чужого.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.
- Из чего состоит JWT и что в нём защищено подписью?A)header.payload.signature — подпись защищает от подменыB)Случайный идентификатор сессии, как обычная серверная кукаC)Логин и пароль в открытом виде, склеенные через точку в строкеD)Зашифрованный payload, который без ключа сервера не прочитать
показать ответ и разбор
+A)header.payload.signature — подпись защищает от подмены// разбор: JWT — три части через точку: header (алгоритм), payload (claims) и signature. Подпись подтверждает целостность и подлинность (никто не подменил claims), но payload лишь base64url-кодирован, а не зашифрован — читается кем угодно. Поэтому секреты в payload не кладут.
- Почему «отозвать» выданный JWT сложнее, чем серверную сессию?A)Отзыв JWT требует смены пароля пользователя во всей системеB)JWT отзывают только полной сменой секрета подписиC)JWT самодостаточен и валиден до истечения, сервер его не хранитD)JWT хранится на сервере, но в зашифрованном и недоступном виде
показать ответ и разбор
+C)JWT самодостаточен и валиден до истечения, сервер его не хранит// разбор: Серверную сессию отзывают, удалив запись в хранилище. JWT stateless: сервер его не хранит и проверяет только подпись и exp — значит валидный токен работает до истечения, даже если юзер «разлогинен». Обходят коротким TTL + refresh-токенами и/или денилистом отозванных jti.
- Сессия на сервере против JWT у клиента — где живёт состояние?A)У сессии — на сервере, у JWT — в самом токене у клиентаB)В обоих случаях состояние целиком лежит в базе на сервереC)Состояние в куках браузера в обоих случаяхD)В обоих случаях состояние целиком хранится на стороне клиента
показать ответ и разбор
+A)У сессии — на сервере, у JWT — в самом токене у клиента// разбор: Классическая сессия: сервер хранит состояние (в Redis/БД), клиент носит лишь session id в куке. JWT: состояние (claims) внутри токена у клиента, сервер лишь проверяет подпись — масштабируется без общего хранилища, но платит сложностью отзыва. Выбор — трейдоф масштабирования против контроля.
- Что по своей сути даёт OAuth2?A)Готовый механизм аутентификации пользователя по логину и паролюB)Формат хранения паролей пользователей в базе данных приложенияC)Алгоритм шифрования трафика между клиентом и сервером ресурсовD)Делегированный доступ к ресурсам без передачи пароля
показать ответ и разбор
+D)Делегированный доступ к ресурсам без передачи пароля// разбор: OAuth2 — фреймворк делегированной авторизации: пользователь разрешает приложению ограниченный доступ к своим ресурсам (через access token), не отдавая ему пароль. Сама аутентификация («кто вошёл») — это уже OpenID Connect поверх OAuth2. Путать их — частая ошибка на собесе.
- Система впустила пользователя по паролю, но не даёт удалить чужой пост. Что сделал каждый этап?A)Оба шага — это авторизация, а аутентификация к проверке пароля вообще не относитсяB)Пароль — это аутентификация, запрет действия — авторизацияC)Пароль подтвердил права доступа, а запрет на чужой пост установил личность пользователяD)Это один и тот же процесс: система просто дважды подряд проверила пользователя
показать ответ и разбор
+B)Пароль — это аутентификация, запрет действия — авторизация// разбор: Аутентификация установила личность (пароль верный — кто ты), авторизация проверила права (можно ли тебе удалить именно этот, чужой, пост — что тебе можно). Это разные этапы: сначала authn (провал — 401), затем authz (провал — 403). Верный пароль не даёт права на чужие ресурсы.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.