Открыть главное меню

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

Содержание

ИсторияПравить

В 2011 году была сформирована группа JOSE (JSON Object Signing and Encryption group), целью которой была стандартизация механизма защиты целостности, шифрования, а также формата ключей и алгоритмов идентификации для обеспечения совместимости служб безопасности, использующих формат JSON. К 2013 году в открытом доступе появились неофициальные наброски и примеры использования идей данной группы, которые позже стали стандартами RFC: JWT, JWS, JWE, JWK и JWA.

Официально JWT был стандартизован группой IETF в мае 2015 года.[1]

СтруктураПравить

Токен JWT состоит из трех частей: заголовок (header), полезная нагрузка (payload) и подпись или данные шифрования. Первые два элемента — это JSON объекты определенной структуры. Третий элемент вычисляется на основании первых и зависит от выбранного алгоритма (в случае использования не подписанного JWT может быть опущен). Токены могут быть перекодированы в компактное представление (JWS/JWE Compact Serialization): к заголовку и полезной нагрузке применяется алгоритм кодирования Base64-URL, после чего добавляется подпись и все три элемента разделяются точками («.»).

К примеру, для заголовка и полезной нагрузки, которые выглядят таким образом:

{
  "alg": "HS512",
  "typ": "JWT"
}
{
  "sub": "12345",
  "name": "John Gold",
  "admin": true
}

Получим следующее компактное представление (переводы строки добавлены для наглядности):

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NSIsIm5hbWUiOiJKb2huIEdvbGQiLCJhZG1pbiI6dHJ1ZX0.
LIHjWCBORSWMEibq-tnT8ue_deUqZx1K0XxCOXZRrBI

ЗаголовокПравить

В заголовке указывается необходимая информация для описания самого токена.

Обязательный ключ здесь только один:

  • alg: алгоритм, используемый для подписи/шифрования (в случае не подписанного JWT используется значение «none»).

Необязательные ключи:

  • typ: тип токена (type). Используется в случае, когда токены смешиваются с другими объектами, имеющими JOSE заголовки. Должно иметь значение «JWT».
  • cty: тип содержимого (content type). Если в токене помимо зарегистрированных служебных ключей есть пользовательские, то данный ключ не должен присутствовать. В противном случае должно иметь значение «JWT»[2]

Полезная нагрузкаПравить

В данной секции указывается пользовательская информация (например, имя пользователя и уровень его доступа), а также могут быть использованы некоторые служебные ключи. Все они являются необязательными:

  • iss: чувствительная к регистру строка или URI, которая является уникальным идентификатором стороны, генерирующей токен (issuer).
  • sub: чувствительная к регистру строка или URI, которая является уникальным идентификатором стороны, о которой содержится информация в данном токене (subject). Значения с этим ключом должны быть уникальны в контексте стороны, генерирующей JWT.
  • aud: массив чувствительных к регистру строк или URI, являющийся списком получателей данного токена. Когда принимающая сторона получает JWT с данным ключом, она должна проверить наличие себя в получателях — иначе проигнорировать токен (audience).
  • exp: время в формате Unix Time, определяющее момент, когда токен станет не валидным (expiration).
  • nbf: в противоположность ключу exp, это время в формате Unix Time, определяющее момент, когда токен станет валидным (not before).
  • jti: строка, определяющая уникальный идентификатор данного токена (JWT ID).[3]

Использование в клиент-серверных приложенияхПравить

Access и refresh токеныПравить

  • Access-токен — это токен, который предоставляет доступ его владельцу к защищенным ресурсам сервера. Обычно он имеет короткий срок жизни и может нести в себе дополнительную информацию, такую как IP-адрес стороны, запрашивающей данный токен.
  • Refresh-токен — это токен, позволяющий клиентам запрашивать новые access-токены по истечении их времени жизни. Данные токены обычно выдаются на длительный срок.

Схема работыПравить

Как правило, при использовании JSON токенов в клиент-серверных приложениях реализована следующая схема:

  1. Клиент проходит аутентификацию в приложении (к примеру, с использованием логина и пароля)
  2. В случае успешной аутентификации, сервер отправляет клиенту access- и refresh-токены.
  3. При дальнейшем обращении к серверу, клиент использует access-токен. Сервер проверяет токен на валидность и предоставляет клиенту доступ к ресурсам
  4. В случае, если access-токен становится не валидным, клиент отправляет refresh-токен, в ответ на который сервер предоставляет два обновленных токена.
  5. В случае, если refresh-токен становится не валидным, клиент опять должен пройти процесс аутентификации (п. 1).[4]

ПреимуществаПравить

JWT имеет ряд преимуществ над куки:

  • При использовании куки сервер должен хранить информацию о выданных сессиях, в то время как использование JWT не требует хранения дополнительных данных о выданных токенах: все, что должен сделать сервер — это проверить подпись.
  • Сервер может не заниматься созданием токенов, а предоставить это внешним сервисам.
  • В JSON токенах можно хранить дополнительную полезную информацию о пользователях. Как следствие — более высокая производительность. В случае c куки иногда необходимо осуществлять запросы для получения дополнительной информации. При использовании JWT эта информация может быть передана в самом токене.[5]
  • JWT делает возможным предоставление одновременного доступа к различным доменам и сервисам.[6][7]

Возможные атакиПравить

Удаление подписиПравить

JSON токен состоит из трех частей, которые кодируются независимо друг от друга. Таким образом, становится возможным удалить подпись из токена и изменить заголовок, сделав JWT не подписанным. Если на сервере не стоит проверка на наличие подписи у токена, то злоумышленник может указывать собственные значения в полезной нагрузке. Проблема решается простым отбрасыванием неподписанных объектов.[8]

CSRFПравить

Одним из методов борьбы с CSRF является добавление специальных заголовков с зашифрованной информацией, подтверждающей отправку запроса с доверенного сервера. Таким образом, если JWT используется не в качестве куки, CSRF атака становится невозможной.[9]

XSSПравить

JSON токены могут храниться в браузере двумя способами: в DOM-хранилище или в куки. В первом случае система может быть подвержена XSS атаке, так как JavaScript имеет доступ к DOM-хранилищу и злоумышленник может извлечь оттуда токен для дальнейшего использования от имени пользователя. При использовании куки можно выставить HttpOnly флаг, который предотвращает доступ JavaScript к хранилищу. Таким образом, злоумышленник не сможет извлечь токен и приложение становится защищенным от XSS.[10]

JWSПравить

Подписанные JSON токены описываются JWS спецификацией (RFC 7515).

Поддерживаемые алгоритмы подписиПравить

Подпись заголовка и полезной нагрузки производится следующими алгоритмами:

Обязательный для поддержки всеми реализациями алгоритм:

Рекомендованные алгоритмы:

Также поддерживаются вариации рекомендованных алгоритмов с использованием SHA-384 и SHA-512 соответственно:

  • HS384, HS512
  • RS384, RS512
  • ES384, ES512

Аббревиатуры курсивом — названия, использующиеся в JSON токенах, описанные спецификацией JWA (RFC 7518)[11]

Структура заголовкаПравить

В случае подписанного JWT в заголовок могут быть добавлены дополнительные ключи:

  • jku: URI на набор открытых ключей в JSON-формате, используемых для подписи данного токена (JSON Web Key Set URL).
  • jwk: Ключ, используемый для подписи данного токена (JSON Web Key).
  • kid: Уникальный идентификатор используемого ключа для случая, когда указывается набор ключей (Key ID).
  • x5u: URI на набор сертификатов X.509. Первый сертификат в наборе должен являться тем, который использовался для подписи данного токена (X.509 URL).
  • x5c: Массив сертификатов X.509 в формате JSON, использованных для подписи данного токена (X.509 certifcate chain).
  • x5t: Цифровой отпечаток SHA1 сертификата X.509 (X.509 certificate SHA-1 fingerprint).
  • crit: Массив строк с названиями ключей данного заголовка, которые должны обрабатываться парсером JWT. Если должны быть обработаны все ключи, то не используется (critical).[12]

РеализацииПравить

Реализации JWT существуют в следующих языках программирования и фреймворках: Clojure, .NET, Go, Haskell, Python, Java, JavaScript, Lua, Perl, PHP, Ruby, Rust, Scala, Erlang, Common Lisp и Elixir.[13]

ПримечанияПравить

  1. JWT Handbook v0.13.0, с.6-7 (англ.). auth0.com. Дата обращения 11 декабря 2017.
  2. Bradley, John, Sakimura, Nat, Jones, Michael. JSON Web Token (JWT), с. 11 (англ.). tools.ietf.org. Дата обращения 20 декабря 2017.
  3. Bradley, John, Sakimura, Nat, Jones, Michael. JSON Web Token (JWT), c. 9-10 (англ.). tools.ietf.org. Дата обращения 20 декабря 2017.
  4. JWT Handbook v0.13.0, c. 18 (англ.). auth0.com. Дата обращения 20 декабря 2017.
  5. Ryan Boyd. Getting Started with OAuth 2.0. — O'Reilly media, 2012. — С. 56.
  6. JWT Handbook v0.13.0, с. 9-11 (англ.). auth0.com. Дата обращения 21 декабря 2017.
  7. Justin Richer and Antonio Sanso. OAuth 2 in Action. — Manning Publications, 2017. — С. 252—253. — 360 с. — ISBN 9781617293276.
  8. JWT Handbook v0.13.0, с. 9 (англ.). auth0.com. Дата обращения 21 декабря 2017.
  9. JWT Handbook v0.13.0, с. 10 (англ.). auth0.com. Дата обращения 21 декабря 2017.
  10. JWT Handbook v0.13.0, с. 11-12 (англ.). auth0.com. Дата обращения 20 декабря 2017.
  11. Bradley, John, Sakimura, Nat, Jones, Michael. JSON Web Token (JWT), с. 16 (англ.). tools.ietf.org. Дата обращения 20 декабря 2017.
  12. Bradley, John, Sakimura, Nat, Jones, Michael. JSON Web Signature (JWS), c. 9-14 (англ.). tools.ietf.org. Дата обращения 20 декабря 2017.
  13. auth0.com. JWT.IO (англ.). jwt.io. Дата обращения 20 декабря 2017.

СсылкиПравить