Что такое 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выдан-в,jtiid токена) рядом с любыми пользовательскими 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 против секрета, который вы вставляете, всё в вашем браузере. Токен и секрет никогда никуда не отправляются.