Декодер JWT

Прочитайте заголовок и полезную нагрузку токена и увидьте, что он о себе заявляет. Декодирование, не проверка подписи.

Разбор — это не проверка. Два читаемых сегмента JWT — это просто base64: прочитать их может кто угодно, и написать тоже. Доверять токену позволяет только подпись, а чтобы её проверить, нужен ключ. У этой страницы ключа нет, она его не просит и ничего не утверждает о подлинности токена.

Префикс «Bearer» убирается автоматически. Ничто из вставленного не покидает эту страницу.

Три сегмента, из которых важен один

JWT — это три строки в base64url, соединённые точками. Первые две — читаемый JSON; третья — подпись над первыми двумя.

eyJhbGciOiJIUzI1NiJ9  .  eyJzdWIiOiIxMjM0In0  .  4fXK...
      header                    payload            signature

Заголовок сообщает, каким алгоритмом он подписан. Полезная нагрузка несёт утверждения. Ни то, ни другое не зашифровано: base64 — это транспортное кодирование, а не сокрытие, и любой, у кого есть токен, прочтёт обе части примерно за секунду.

Единственная часть, делающая работу по безопасности, — подпись. Она доказывает, что первые два сегмента созданы обладателем ключа подписи и с тех пор не менялись. Без её проверки JWT — это самоописывающийся текстовый файл, обладающий не большим авторитетом, чем любая другая строка, присланная клиентом.

Поэтому эта страница не скажет вам, что токен действителен

Для проверки нужен ключ, а совета «вставьте свой секрет подписи в веб-страницу» не существует ни в одной хорошей редакции. Вместо этого инструмент сообщает, что токен говорит о себе сам: истёк ли он, наступило ли его время начала действия, симметричный алгоритм или асимметричный и не заявляет ли он, что подпись ему вовсе не нужна.

alg:none, и чем этот случай поучителен

Спецификация допускает "alg": "none" — токен без подписи. Атака пишется сама: возьмите законный токен, отредактируйте нагрузку как вздумается, поставьте алгоритм none, удалите подпись и отправьте.

Библиотека, которая читает алгоритм из заголовка и делает, как там сказано, это примет. Политику проверки выбрал атакующий, потому что политика лежала в подконтрольной ему части сообщения.

Родственный случай — путаница алгоритмов. У сервера, проверяющего RS256, есть открытый ключ, а он не секретен. Смените заголовок на HS256 — симметричный алгоритм — и подпишите этим открытым ключом как общим секретом. Наивная библиотека возьмёт один и тот же ключевой материал для обоих случаев, и поддельный токен пройдёт проверку.

Лечится и то и другое одинаково, и этот принцип стоит унести с собой и в другие места: проверяющая сторона обязана сама заявить, какие алгоритмы принимает, а не спрашивать об этом токен.

Что на самом деле ломается в бою

СимптомОбычная причина
Отклоняется сразу после выпускаРасхождение часов. iat или nbf на несколько секунд опережают часы проверяющего. Заложите небольшой допуск.
Работает локально, падает после развёртыванияРазные ключи подписи в разных средах — токен из тестового контура отправлен в боевой.
Подпись верна, но токен всё равно отклонёнУтверждение aud или iss не совпадает с тем, чего ждёт эта служба.
Работает, а потом перестаёт посреди сессииИстечение срока. Короткоживущим токенам нужен поток обновления, и обычно именно его и не хватает.
Запросы падают из-за слишком больших заголовковТокен перерос лимит. Большинство серверов ограничивают заголовки примерно 8 КБ, а браузеры — куки в 4 КБ.

Проблема отзыва

Причина использовать JWT в том, что проверка не требует обращения к базе: токен несёт собственное доказательство. Ровно поэтому его и нельзя отозвать. При проверке ничего не запрашивается, значит, некуда и записать, что токен должен перестать работать.

Варианты, и ни один не бесплатен:

  • Короткий срок жизни плюс токены обновления. Стандартный ответ. Токены доступа живут минуты, токены обновления сверяются с базой и могут быть отозваны.
  • Список отзыва. Сверять jti каждого токена с хранилищем отозванных — что возвращает тот самый поход в базу, ради избавления от которого формат и появился.
  • Смена ключа подписи. Обесценивает разом все токены, включая чужие.

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

Смежное

Все три сегмента — это URL-безопасный Base64 без дополнения, отчего сегмент часто и не читается строгим декодером. После раскодирования две читаемые части — это JSON. А для тех учётных данных, вместо которых стоит токен, проверщик надёжности закрывает другой конец входа в систему.

Вопросы про JWT

Означает ли декодирование JWT его проверку?

Нет, и на этом различии держится вся модель безопасности. Заголовок и полезная нагрузка закодированы в base64url — чтобы их прочитать, не нужно ничего. Проверка же означает пересчёт подписи с ключом и сравнение, и она доказывает, что токен выпущен владельцем этого ключа и с тех пор не менялся. Декодер без ключа расскажет, что токен утверждает; поверить ему или нет, показывает только проверка.

Безопасно ли вставлять настоящий токен на сайт?

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

Можно ли класть секреты в полезную нагрузку JWT?

Нет. Нагрузка подписана, а не зашифрована — её прочтёт любой, у кого есть токен, включая того пользователя, которому он выдан. Подпись гарантирует, что содержимое не изменяли, но ничего не скрывает. Если вам действительно нужна конфиденциальная нагрузка, это JWE — другая и заметно более громоздкая спецификация. На практике лучший ответ обычно иной: оставить чувствительную часть на сервере, а в токен положить идентификатор.

Что такое уязвимость alg:none?

Спецификация JWT допускает значение «alg», равное «none», то есть неподписанный токен. Атака состоит в том, чтобы взять корректный токен, поменять нагрузку на «я администратор», выставить alg в none и убрать подпись. Библиотека, доверяющая полю алгоритма в заголовке, признает такой токен действительным — он ведь сам заявил, что проверять ничего не надо. Все крупные библиотеки давно исправлены, но урок шире: какие алгоритмы принимать, должен решать сервер, а не токен.

Как отозвать JWT до истечения срока?

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

Почему токен отклоняют, хотя он выглядит корректным?

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

Последняя проверка . Заметили, что что-то устарело? Напишите нам.