JSON Web Tokens

JSON Web Tokens

t.me/qa_chillout

Что такое JWT

JSON Web Token (JWT) — это открытый стандарт (RFC 7519) для создания токенов доступа, основанный на формате JSON. Как правило, используется для передачи данных для аутентификации в клиент-серверных приложениях. Токены создаются сервером, подписываются секретным ключом и передаются клиенту, который в дальнейшем использует данный токен для подтверждения подлинности аккаунта.

Предыстория

Сегодня широко распространены клиент-серверные приложения с многочисленными сервисами. Однако, если посмотреть на небольшие проекты, либо оглянуться на несколько лет назад, то проект может иметь один сервис. Рассмотрим авторизацию клиента в таком сервисе. Тут все довольно просто:

  • клиент отправляет пару логин и пароль,
  • сервис генерирует буквенно-числовую строку (cookie) по своему алгоритму и отдает клиенту,
  • затем клиент отправляет данную cookie сервису при каждом запросе.

А что делать с микросервисной архитектурой? Предположим, наш сервис располагается на домене first.example.com, а также имеется несколько других сервисов second.example.com и third.example.com. Наш клиент авторизуется в сервисе first.example.com и для него создается кука. Однако, сервис second.example.com не будет видеть эту куку. Разумеется, можно сохранить куку в локальном хранилище браузера. Такой вариант прост, но сервису second.example.com не проверить подлинность куки. Можно конечно делать запрос на сервис, получать подтверждение, что кука валидна, но это все увеличивает нагрузку на сервис.


Так и появился JWT токен, на который возложили решение вышеописанных проблем с авторизацией.

Формат JWT

JWT состоит из трех основных частей:

  • заголовка (header),
  • нагрузки (payload),
  • подписи (signature). 

Заголовок и нагрузка формируются отдельно в формате JSON, кодируются в base64, а затем на их основе вычисляется подпись. Закодированные части соединяются друг с другом, и на их основе вычисляется подпись, которая также становится частью токена.

Обычно JWT токен выглядит следующим образом: xxxxx.yyyyy.zzzzz

Заголовок обычно состоит из двух частей: типа токена (JWT) и алгоритма хэширования подписи, например HMAC SHA256 или RSA.

{
  "typ": "JWT",
  "alg": "HS256"
}

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

Payload

Payload (или полезная нагрузка) — это любые данные, которые передаются в токене. Существуют следующие зарезервированные поля:

  • iss — (issuer) хост, который выдал этот токен
  • sub — (subject) “тема”, назначение токена
  • aud — (audience) аудитория, получатели токена
  • exp — (expire time) срок действия токена
  • nbf — (not before) срок, до которого токен не действителен
  • iat — Unixtime выдачи JWT
  • jti — (JWT id) уникальный идентификатор токена

Ниже приведен Payload:

{
  "sub": "authorization",
  "name": "Ivan Ivanov",
  "admin": true,
  "iss": "Admin"
}

Signature

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

закодированные заголовок и полезная нагрузка объединяются точкой (".") в качестве разделителя. Затем эта строка хэшируется указанным в header алгоритмом. Результат работы алгоритма хеширования и есть подпись.

Например, если мы будем использовать алгоритм HMAC SHA256, подпись будет создана следующим образом:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)


В качестве примера давайте воспользуемся jwt.io Debugger для декодирования, проверки и создания JWT.

Вот такой токен получился у нас:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRob3JpemF0aW9uIiwibmFtZSI6Ikl2YW4gSXZhbm92IiwiYWRtaW4iOnRydWUsImlzcyI6IkFkbWluIn0.1JWLekR8SauGe9t5FkqHrgPX-i36ZXAQKwvY1ENI4gQ

А в качестве примера, попробуйте расшифровать что же зашифровано в токене и какого числа он протухает:

token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2lkIjoyLCJjaWQiOjE2OSwiYXVkIjoicWFfY2hpbGxvdXQiLCJleHAiOjE3NDkxMTUyNzAsImlzcyI6Imh0dHBzOi8vdC5tZS9xYV9jaGlsbG91dCJ9.r6ZDZ6FqvGrfffCiAyziX0mIbIp6ABVWg30QzWSNb5s

Своими ответами делитесь в комментариях: https://t.me/qa_chillout/223

Для тестирования

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

  • во время передачи токена используется защищенное соединение,
  • в токене не передаются чувствительные пользовательские данные,
  • время жизни JWT токена ограничено и на проекте используется механизм refresh tokens.

Report Page