сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · FastAPI, Django и API

Аутентификация и авторизация в API

Аутентификация, авторизация, JWT

Безопасность входа - обязательный блок собеса на бэкенде, и здесь много заученных полуправд. Проверяют, различаешь ли ты «кто ты» и «что тебе можно», понимаешь ли, что 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, остальные разбираются в тренажёре.

  1. #auth_authz1 / 5
    Из чего состоит JWT и что в нём защищено подписью?
    A)header.payload.signature — подпись защищает от подмены
    B)Случайный идентификатор сессии, как обычная серверная кука
    C)Логин и пароль в открытом виде, склеенные через точку в строке
    D)Зашифрованный payload, который без ключа сервера не прочитать
    показать ответ и разбор
    +A)header.payload.signature — подпись защищает от подмены

    // разбор: JWT — три части через точку: header (алгоритм), payload (claims) и signature. Подпись подтверждает целостность и подлинность (никто не подменил claims), но payload лишь base64url-кодирован, а не зашифрован — читается кем угодно. Поэтому секреты в payload не кладут.

  2. #auth_authz2 / 5
    Почему «отозвать» выданный JWT сложнее, чем серверную сессию?
    A)Отзыв JWT требует смены пароля пользователя во всей системе
    B)JWT отзывают только полной сменой секрета подписи
    C)JWT самодостаточен и валиден до истечения, сервер его не хранит
    D)JWT хранится на сервере, но в зашифрованном и недоступном виде
    показать ответ и разбор
    +C)JWT самодостаточен и валиден до истечения, сервер его не хранит

    // разбор: Серверную сессию отзывают, удалив запись в хранилище. JWT stateless: сервер его не хранит и проверяет только подпись и exp — значит валидный токен работает до истечения, даже если юзер «разлогинен». Обходят коротким TTL + refresh-токенами и/или денилистом отозванных jti.

  3. #auth_authz3 / 5
    Сессия на сервере против JWT у клиента — где живёт состояние?
    A)У сессии — на сервере, у JWT — в самом токене у клиента
    B)В обоих случаях состояние целиком лежит в базе на сервере
    C)Состояние в куках браузера в обоих случаях
    D)В обоих случаях состояние целиком хранится на стороне клиента
    показать ответ и разбор
    +A)У сессии — на сервере, у JWT — в самом токене у клиента

    // разбор: Классическая сессия: сервер хранит состояние (в Redis/БД), клиент носит лишь session id в куке. JWT: состояние (claims) внутри токена у клиента, сервер лишь проверяет подпись — масштабируется без общего хранилища, но платит сложностью отзыва. Выбор — трейдоф масштабирования против контроля.

  4. #auth_authz4 / 5
    Что по своей сути даёт OAuth2?
    A)Готовый механизм аутентификации пользователя по логину и паролю
    B)Формат хранения паролей пользователей в базе данных приложения
    C)Алгоритм шифрования трафика между клиентом и сервером ресурсов
    D)Делегированный доступ к ресурсам без передачи пароля
    показать ответ и разбор
    +D)Делегированный доступ к ресурсам без передачи пароля

    // разбор: OAuth2 — фреймворк делегированной авторизации: пользователь разрешает приложению ограниченный доступ к своим ресурсам (через access token), не отдавая ему пароль. Сама аутентификация («кто вошёл») — это уже OpenID Connect поверх OAuth2. Путать их — частая ошибка на собесе.

  5. #auth_authz5 / 5
    Система впустила пользователя по паролю, но не даёт удалить чужой пост. Что сделал каждый этап?
    A)Оба шага — это авторизация, а аутентификация к проверке пароля вообще не относится
    B)Пароль — это аутентификация, запрет действия — авторизация
    C)Пароль подтвердил права доступа, а запрет на чужой пост установил личность пользователя
    D)Это один и тот же процесс: система просто дважды подряд проверила пользователя
    показать ответ и разбор
    +B)Пароль — это аутентификация, запрет действия — авторизация

    // разбор: Аутентификация установила личность (пароль верный — кто ты), авторизация проверила права (можно ли тебе удалить именно этот, чужой, пост — что тебе можно). Это разные этапы: сначала authn (провал — 401), затем authz (провал — 403). Верный пароль не даёт права на чужие ресурсы.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.