Как устроен JWT
JSON Web Token (RFC 7519) — это три фрагмента текста, соединённые точками. Заголовок говорит, как подписан токен, payload содержит поля (claims), например кто пользователь и когда токен истекает, а подпись доказывает, что и то и другое создал тот, у кого есть ключ. Заголовок и payload — это JSON в Base64url, варианте Base64, безопасном для URL.
header.payload.signature
header = base64url(UTF-8 JSON, e.g. {"alg":"HS256","typ":"JWT"})
payload = base64url(UTF-8 JSON with the claims)
signature = base64url(HMAC-SHA256(secret, header + "." + payload)) Base64url — это кодировка, а не шифрование: любой, у кого есть токен, может прочитать его payload без ключа, как это делает эта страница. Поэтому никогда не кладите в JWT пароли и другие секреты. Ключ защищает подпись: измените в payload один символ — и подпись перестанет совпадать.
При HS256, HS384 и HS512 издатель и сервер используют один общий секрет и подписывают с помощью HMAC; такие подписи эта страница может проверить, если вы введёте секрет. RS256, ES256 и другие алгоритмы с открытым ключом подписываются закрытым ключом, а проверяются открытым ключом издателя, который сервер обычно получает по адресу JWKS. Декодировать токен — не значит доверять ему: сервер обязан проверить подпись, срок действия и аудиторию.
Пример
Возьмём известный пример с jwt.io, eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c. Первая часть декодируется в заголовок {"alg":"HS256","typ":"JWT"}: подпись HMAC-SHA256. Вторая — в payload {"sub":"1234567890","name":"John Doe","iat":1516239022}. Его iat 1516239022 означает, что токен выпущен 18 января 2018 года в 01:30:22 UTC, а раз поля exp нет, он не истекает никогда. Последняя часть — 32-байтовый HMAC-SHA256 от первых двух частей и точки между ними; с секретом your-256-bit-secret он совпадает, поэтому подпись верна.
Стандартные поля (registered claims)
| Поле (claim) | Что это значит |
|---|---|
iss · Издатель | Кто создал и подписал токен, обычно URL сервиса входа. |
sub · Субъект | О ком токен, обычно ID пользователя. |
aud · Аудитория | Для кого предназначен токен. Сервер должен отклонить токен, выпущенный не для него. |
exp · Действует до | После этого момента токен нужно отклонять. Секунды с 1 января 1970 года, UTC. |
nbf · Не раньше | До этого момента токен нужно отклонять. Секунды с 1 января 1970 года, UTC. |
iat · Выпущен | Когда создан токен. Секунды с 1 января 1970 года, UTC. |
jti · ID токена | Уникальный ID этого токена, чтобы сервер мог заблокировать его или заметить повторное использование. |
Вопросы
Безопасно ли вставлять сюда свой JWT?
Да. Токен декодирует JavaScript в вашем браузере, а подпись проверяет встроенный в браузер WebCrypto. Ни токен, ни секрет не отправляются на сервер и не сохраняются. Но действующий токен всё равно храните как пароль: любой, у кого он есть, может им пользоваться, пока он не истечёт.
Можно ли декодировать JWT без секрета?
Да. Заголовок и payload — это просто JSON в кодировке Base64url, поэтому любой может прочитать их без ключа. Секрет или открытый ключ нужны только для проверки, что подпись подлинная. Поэтому в JWT нельзя класть пароли и другие секреты.
Как проверить, истёк ли JWT?
Посмотрите на поле exp: это время истечения в секундах с 1 января 1970 года, UTC. Если текущее время позже, токен истёк. Эта страница сама читает exp и nbf и показывает результат как дату и как «истёк 3 дня назад» или «истекает через 2 часа».
Чем отличается HS256 от RS256?
HS256 подписывает с помощью HMAC и одного общего секрета: тот, кто может проверить токен, может и создать его. RS256 подписывает закрытым ключом RSA, а проверяется открытым, поэтому сервисы могут проверять токены, но не могут их выпускать. Если токены проверяют несколько сервисов, обычно выбирают RS256 или ES256.
Почему подпись моего JWT недействительна?
Секрет неверный, он закодирован в Base64 и нужна опция «Секрет закодирован в Base64», либо токен изменили после подписи. Кроме того, при копировании токена могут добавиться или пропасть символы. Если токен использует RS256, ES256 или другой алгоритм с открытым ключом, секретом его проверить нельзя вовсе: нужен открытый ключ издателя.