Как JWT помогает решить проблему нагрузки на сервис авторизации
Что проверяют
Понимаете ли вы разницу между токеном, который нужно проверять у сервиса авторизации, и токеном, который проверяется локально по подписи. Следом почти всегда спрашивают про обратную сторону: как отозвать такой токен до истечения срока.
Как отвечать
Начните с проблемы. С непрозрачным токеном или серверной сессией каждый сервис на каждый запрос идёт в сервис авторизации или в общее хранилище сессий, и тот становится узким местом и единой точкой отказа. JWT снимает эту зависимость:
- самодостаточность: токен содержит заголовок, полезную нагрузку с клеймами (
sub,exp,iss,aud, роли) и подпись. Сервису не нужно никуда ходить, чтобы узнать, кто пользователь; - локальная проверка: сервис сам проверяет подпись и срок. С асимметричными алгоритмами (
RS256,ES256) приватный ключ есть только у сервиса авторизации, а остальные берут публичные ключи с JWKS-эндпоинта и кешируют их. В Python этоPyJWTсPyJWKClientилиauthlib; - сервис авторизации нужен только при входе и обновлении: он выдаёт короткий access token и refresh token. Нагрузка на него падает с «каждый запрос» до «раз в несколько минут на пользователя».
Затем честно назовите цену. Отозвать выданный JWT нельзя, он валиден до exp. Поэтому access token живёт минуты (обычно 5-15), refresh token хранится на сервере и отзывается, а для мгновенного отзыва заводят чёрный список по jti в Redis. Это частично возвращает состояние, но проверка в Redis всё равно дешевле похода в сервис авторизации.
Где спотыкаются
Говорят, что JWT зашифрован. Обычный JWS только подписан, полезная нагрузка читается кем угодно после base64url-декодирования, класть туда персональные данные нельзя. Шифрование это отдельный формат JWE.
Не фиксируют алгоритм при проверке. В jwt.decode() нужно явно передавать список algorithms, иначе открывается путь к атакам с подменой алгоритма.
Используют HS256 с общим секретом во всех сервисах. Тогда любой сервис может выпустить токен от имени системы, и утечка секрета из одного места компрометирует все.