Что такое JWT

JSON Web Token (, определён в RFC 7519) — это компактный, самодостаточный способ нести набор claims (утверждений), заявлений о сущности (обычно пользователе) плюс некоторые метаданные, в форме, которую получатель может проверить. Это формат токена, лежащий в основе большинства современной веб-аутентификации: ID-токен OpenID Connect — это JWT, и токены доступа 2.0 очень часто тоже.

«Самодостаточный» — ключевая идея. Вместо случайного id сессии, который сервер должен искать в базе данных, JWT несёт claims внутри себя, подписанные так, что получатель может доверять им без пути туда-обратно. Это делает JWT удобными для бесстатусных, распределённых систем, с одним важным компромиссом, разобранным в конце.

Три сегмента

JWT — это три сегмента, закодированных в Base64URL и соединённых точками:

header.payload.signature

У каждого сегмента своя задача:

  • Заголовок (header) — небольшой JSON-объект, называющий алгоритм подписи и тип токена, например {"alg":"HS256","typ":"JWT"}. Значение alg сообщает получателю, как проверить подпись.
  • Полезная нагрузка (payload) — JSON-объект claims. Она хранит зарегистрированные claims со стандартными значениями (iss издатель, sub субъект, aud аудитория, exp истечение, nbf не-ранее, iat выдан-в, jti id токена) рядом с любыми пользовательскими claims, которые добавляет издатель.
  • Подпись (signature) вычисляется над закодированными заголовком и полезной нагрузкой вместе, с использованием алгоритма из заголовка. Именно она делает первые два сегмента заслуживающими доверия.

Поскольку заголовок и полезная нагрузка лишь закодированы в Base64URL, а не зашифрованы, любой, кто владеет токеном, может их декодировать и прочесть. Это единственное самое важное свойство для усвоения: полезная нагрузка JWT читаема, а не секретна. Никогда не помещайте в неё пароль, номер карты или что-либо чувствительное.

Подпись: как устанавливается доверие

Подпись — это то, что отделяет JWT от любой строки, которую клиент мог бы сфабриковать. Как она производится, зависит от семейства алгоритмов:

  • (, HS384, HS512) подписывает одним общим секретом. Подпись — это HMAC-SHA256(base64url(header) + "." + base64url(payload), secret). Она симметрична: один и тот же секрет создаёт и проверяет, так что издатель и проверяющий должны его разделять. Это ровно та конструкция, которую вычисляет инструмент HMAC.
  • и (, и другие) подписывают приватным ключом и проверяют соответствующим открытым ключом. Это асимметрично: подписать может только издатель, но проверить может любой с открытым ключом, что подходит токенам, проверяемым многими независимыми сервисами.

Проверка пересчитывает или сверяет подпись с закодированными заголовком и полезной нагрузкой. Если изменён хотя бы один байт любого сегмента, подпись больше не совпадает и токен отклоняется.

Стоит знать две классические ловушки. Значение alg: none объявляет неподписанный токен; проверяющий, который не отклоняет его явно, может быть обманут и доверится поддельным claims. А в атаке путаницы алгоритмов атакующий берёт токен RS256, переключает заголовок на HS256 и подписывает его, используя открытый ключ как секрет HMAC, что удаётся против проверяющих, берущих алгоритм из токена, а не закрепляющих его. Защита для обоих одна: проверяющий решает, какой алгоритм приемлем, а не токен.

Декодирование — не проверка

Это две разные операции, и их смешение — частый источник ошибок. Декодирование просто декодирует сегменты из Base64URL, чтобы раскрыть заголовок и claims: ни ключа, ни доверия, это может сделать любой. Проверка сверяет подпись правильным ключом и подтверждает временные claims. Действовать следует только по claims проверенного токена.

Время тоже важно. exp (истечение) и nbf (не-ранее) — это метки времени Unix, ограничивающие окно действительности токена, а iat фиксирует, когда он был выдан. Корректный проверяющий отклоняет истёкший или ещё-не-действительный токен, обычно допуская небольшую толерантность к расхождению часов.

Чем JWT не является

JWT подписан, а не зашифрован (шифрование — отдельный стандарт, JWE). Он доказывает, кто выпустил claims и что они не были подделаны; он не скрывает их.

Подписанный JWT также сам по себе нелегко отозвать. Поскольку claims живут внутри токена, а проверке не нужен запрос к серверу, токен остаётся действительным до истечения, даже если вы хотели бы отменить его раньше. Практический ответ — короткие сроки жизни плюс отдельный механизм (токен обновления, список отзыва или интроспекция токена), когда требуется немедленный отзыв.

Инструмент JWT декодирует заголовок и claims токена, читает его истечение и тайминг простым языком и проверяет подпись HS256, HS384 или HS512 против секрета, который вы вставляете, всё в вашем браузере. Токен и секрет никогда никуда не отправляются.