JWT

JSON Web Token (рус. веб-токен в формате JSON, далее — JWT) — открытый стандарт IETF (RFC 7519, май 2015 года), определяющий компактный, самодостаточный и URL-безопасный способ представления утверждений (claims) между двумя сторонами. Информация внутри JWT цифрово подписывается (HMAC, RSA, ECDSA) либо шифруется, что позволяет проверить подлинность отправителя и целостность данных.

Что важно знать
JSON Web Token
англ. JSON Web Token
Область использования Веб-разработка, Информационная безопасность
Дата появления май 2015[1]
Место появления Инженерный совет Интернета (IETF)[2]
Автор понятия Майкл Б. Джонс, Джон Брэдли, Нэт Сакимура[2]

История

Разработка стандарта JWT велась в рамках Инженерного совета Интернета (IETF). Ключевую роль в этом процессе сыграла рабочая группа JOSE (англ. JSON Object Signing and Encryption), сформированная в 2011 году с целью разработки стандартов для защиты (подписи и шифрования) объектов в формате JSON. Первые неофициальные проекты группы начали появляться в открытом доступе к 2013 году, а в мае 2015 года был официально опубликован итоговый стандарт — RFC 7519. Его авторами выступили Майкл Б. Джонс (Microsoft), Джон Брэдли (англ. Ping Identity) и Нэт Сакимура (англ. Nomura Research Institute).

Определение

Согласно RFC 7519 JWT — это «compact, URL-safe means of representing claims to be transferred between two parties»[3]. Ключевые свойства стандарта:

  • Компактность: данные кодируются в формате Base64url, поэтому токен подходит для передачи в HTTP-заголовках или URL-параметрах[4].
  • Самодостаточность: токен содержит всю необходимую информацию о субъекте, что исключает необходимость хранения состояния сессии на сервере[5].
  • Проверяемость: цифровая подпись (или MAC) гарантирует неизменность полезной нагрузки и подлинность издателя[6].
  • Расширяемость: кроме зарегистрированных клеймов (iss, exp, sub, aud и др.) стандарт допускает публичные и приватные клеймы, что упрощает добавление пользовательских данных[7].

Структурные элементы JWT

JWT состоит из трёх Base64url-кодированных сегментов, разделённых точками («.»):

Заголовок (Header)

JSON-объект с метаданными токена. Основные поля:

  • typ — тип токена, обычно «JWT»;
  • alg — алгоритм подписи (например, HS256, RS256) либо значение «none» для неподписанных токенов. Возможность указания «none» является известной уязвимостью (атака с подменой алгоритма): злоумышленник может изменить это поле на «none» и удалить подпись. Если серверная библиотека сконфигурирована неверно и не проверяет алгоритм, она может посчитать такой токен действительным, что позволяет полностью подделать его содержимое[8].

Полезная нагрузка (Payload)

Содержит совокупность утверждений (claims), которые делятся на зарегистрированные, публичные и частные.

  • Зарегистрированные утверждения (Registered Claims): предопределённый набор утверждений, таких как iss (издатель), exp (срок действия), sub (субъект), aud (аудитория), nbf (не раньше), iat (создан) и jti (идентификатор токена).
  • Публичные и частные утверждения (Public and Private Claims): пользовательские данные (например, role, userId).

Поскольку полезная нагрузка по умолчанию не шифруется, а лишь кодируется с помощью Base64url, её содержимое может быть легко прочитано любой стороной, перехватившей токен. Это создаёт риск утечки чувствительных данных, если они помещены в полезную нагрузку в открытом виде[9]. Для обеспечения конфиденциальности данных используется стандарт JSON Web Encryption (JWE).

Подпись (Signature)

Создаётся путём хэширования строки «Base64url(Header).Base64url(Payload)» с использованием секретного ключа (HMAC) либо закрытого ключа (RSA/ECDSA). Подпись обеспечивает:

  • подтверждение издателя;
  • защиту от изменения содержимого токена[10].

Одной из известных уязвимостей, связанных с подписью, является атака «Algorithm Confusion» (путаница алгоритмов). Она возникает, когда сервер некорректно валидирует алгоритм, указанный в заголовке, и позволяет переключаться между асимметричными (например, RS256) и симметричными (HS256) алгоритмами. Злоумышленник может взять публичный ключ, предназначенный для асимметричного шифрования, и использовать его как секрет для создания подписи с симметричным алгоритмом (HS256). Если сервер ожидает токен с любым из этих алгоритмов, он может ошибочно проверить подпись HS256, используя публичный ключ как секрет, и счесть поддельный токен действительным.

В итоговом виде токен выглядит как: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJleGFtcGxlIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c.

1. Аутентификация и генерация токена

  1. Клиент отправляет учётные данные серверу.
  2. При успешной проверке сервер формирует Header и Payload, подписывает их секретом/ключом и возвращает JWT клиенту[11].

2. Хранение на клиенте

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

Хранение токена в веб-хранилищах, таких как `localStorage` или `sessionStorage`, считается небезопасным. Основная причина — уязвимость к атакам типа межсайтового скриптинга (XSS). Если злоумышленнику удаётся внедрить на страницу вредоносный JavaScript-код, он может получить полный доступ к хранилищу и украсть токен[12][13].

Более безопасным подходом является использование cookie с флагом `HttpOnly`. Этот флаг запрещает доступ к cookie из JavaScript, что эффективно защищает от кражи токена через XSS[14]. Однако этот метод уязвим для атак типа межсайтовой подделки запроса (CSRF), если не приняты дополнительные меры защиты[15].

Современной рекомендованной практикой является комбинированная схема с использованием двух токенов — токена доступа (access token) и токена обновления (refresh token)[12]:

  • Токен доступа — короткоживущий токен (например, 5–15 минут), который хранится в памяти клиентского приложения (например, в переменной JavaScript). Это наиболее безопасный способ хранения, так как он недоступен для XSS-атак при перезагрузке страницы, но сам токен теряется при обновлении вкладки[16].
  • Токен обновления — долгоживущий токен, который сохраняется в cookie с максимальными мерами защиты: `HttpOnly` (защита от XSS), `Secure` (передача только по HTTPS) и `SameSite=Strict` или `SameSite=Lax` (защита от CSRF)[17][18].

Эта архитектура минимизирует риски: даже в случае кражи короткоживущего токена доступа ущерб будет ограниченным, а наиболее ценный токен обновления надёжно защищён в cookie.

3. Передача с запросами

При обращении к защищённым ресурсам клиент включает JWT в заголовок Authorization: Bearer <token>[19].

4. Валидация на сервере

Сервер:

  • проверяет подпись токена;
  • удостоверяется, что exp не истёк и другие клеймы (iss, aud) валидны;
  • извлекает данные пользователя и принимает решение об авторизации[20].

5. Обновление (refresh)

Поскольку JWT по своей природе являются stateless (не хранят состояние), одной из ключевых проблем является невозможность досрочного отзыва скомпрометированного токена — он остаётся действительным до истечения своего срока действия[21]. Для решения этой проблемы и повышения общего уровня безопасности применяется механизм обновления с использованием двух токенов: короткоживущего токена доступа (access token) и долгоживущего токена обновления (refresh token).

Схема работы выглядит следующим образом:

  1. Клиентское приложение использует токен доступа для авторизации запросов к защищённым ресурсам API.
  2. Когда срок действия токена доступа истекает, сервер возвращает ошибку авторизации (например, со статусом 401 Unauthorized).
  3. Получив ошибку, клиентское приложение отправляет запрос на специальный эндпоинт (например, /api/refresh), не включая в него никаких данных вручную. Браузер автоматически прикрепляет к этому запросу токен обновления, который хранится в защищённой cookie с флагами HttpOnly, Secure и SameSite.
  4. Сервер получает токен обновления, проверяет его подлинность и валидность (например, сверяясь со списком действующих токенов в базе данных). Это позволяет централизованно отзывать сессии пользователей, просто удаляя их токен обновления[22].
  5. В случае успеха сервер генерирует новую пару токенов: новый токен доступа и, как правило, новый токен обновления (для реализации ротации токенов). Новый токен доступа возвращается в теле ответа, а новый токен обновления устанавливается в cookie, заменяя старый.
  6. Клиентское приложение сохраняет новый токен доступа (например, в памяти) и повторяет исходный запрос, который завершился ошибкой.

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

  • Безгосударственная архитектура, упрощающее горизонтальное масштабирование[23].
  • Компактный формат — меньше сетевой трафик по сравнению с SAML[4].
  • Кросс-платформенность и поддержка SSO-сценариев[5].
  • Проверяемость и целостность данных благодаря цифровой подписи[6].

Недостатки

  • Невозможность досрочного отзыва токена. Поскольку JWT являются stateless, скомпрометированный токен остаётся действительным до истечения своего срока действия. Решения, такие как «чёрные списки» отозванных токенов, превращают систему в stateful, нивелируя одно из ключевых преимуществ JWT.
  • Утечка данных из полезной нагрузки. По умолчанию данные в payload не шифруются, а лишь кодируются в Base64, что позволяет любой стороне, перехватившей токен, прочитать его содержимое, если в нём содержатся чувствительные данные.
  • Подверженность атакам при некорректной реализации. К наиболее известным уязвимостям относятся атака с подменой алгоритма на `none` и атака «Algorithm Confusion» (путаница между асимметричными и симметричными алгоритмами).
  • Риски, связанные с управлением ключами. Использование жёстко закодированных секретов в коде приложения или прошивке устройств неоднократно приводило к критическим уязвимостям (например, в оборудовании Cisco), позволяя злоумышленникам получать полный контроль над системой путём подписи собственных токенов[24].
  • Увеличенный размер токена. Включение большого количества утверждений (claims) увеличивает размер токена, что повышает сетевой трафик и может создавать проблемы при хранении в cookie или localStorage.

Сферы применения

  • Аутентификация и авторизация в REST-API и микросервисах[25].
  • Веб- и мобильные приложения (SPA, PWA) — обмен токенами между фронтендом и бэкендом[26].
  • Протоколы OAuth 2.0 и OpenID Connect (ID-, Access- и Refresh-токены).
  • Безопасный обмен информацией между независимыми системами и сторонними сервисами.

Онлайн-отладка

Для отладки и анализа JWT используются как онлайн-сервисы, так и офлайн-приложения, которые обеспечивают безопасность при работе с конфиденциальными данными.

  • JWT.io — один из самых известных онлайн-инструментов, позволяющий в браузере декодировать, верифицировать и создавать токены.
  • Authgear JWT & JWE Debugger — онлайн-инструмент, который, помимо стандартных подписанных токенов (JWS), поддерживает работу с зашифрованными токенами (JWE)[27].
  • DevUtils — десктопное приложение для macOS с офлайн-дебаггером JWT. Позволяет работать с токенами без отправки данных в интернет, что необходимо при работе с чувствительной информацией[28].
  • Функции для работы с JWT также встроены в комплексные инструменты для тестирования API, такие как Postman, где они используются для управления токенами при отправке запросов к защищённым эндпоинтам[29].

Библиотеки по языкам программирования

  • Node.js:
    • jose — рекомендованная библиотека, строго соответствующая стандартам IETF JOSE (JWS, JWE, JWK). Отличается активной поддержкой и полным набором функций, включая шифрование токенов (JWE), что делает её предпочтительным выбором для систем с высокими требованиями к безопасности[30].
    • fast-jwt — высокопроизводительная альтернатива `jsonwebtoken` с совместимым API, предназначенная для приложений, где скорость обработки токенов является критически важной[31].
    • jsonwebtoken — исторически одна из самых популярных библиотек, простая в использовании. Однако по состоянию на 2025 год её разработка менее активна, и она не поддерживает шифрование (JWE), в отличие от `jose`[32].
  • Python:
    • PyJWT — наиболее популярная и рекомендуемая библиотека, активно поддерживается и реализует стандарт RFC 7519. Является стандартом де-факто для большинства задач[33].
    • Authlib — комплексная библиотека, реализующая полный стек стандартов JOSE. Подходит для построения сложных систем аутентификации, включающих OAuth и OpenID Connect[34].
    • python-jose — ранее популярная библиотека, однако на 2025 год считается слабо поддерживаемой, и её использование не рекомендуется из-за потенциальных рисков безопасности[35].
  • Java:
    • java-jwt (Auth0) — одна из самых популярных библиотек с удобным API, активно поддерживается компанией Auth0. Хороший выбор для большинства стандартных задач[36].
    • Nimbus JOSE + JWT — мощный и гибкий фреймворк, полностью поддерживающий JWS (подпись) и JWE (шифрование). Рекомендуется для сложных сценариев, требующих максимального контроля и безопасности[37].
    • JJWT — библиотека, ориентированная на простоту использования. Часто применяется в связке с фреймворком Spring Security[38].
  • C# / .NET:
    • System.IdentityModel.Tokens.Jwt — встроенная в .NET библиотека для создания и валидации токенов. Является стандартным решением для приложений на ASP.NET Core[39].
    • Microsoft.AspNetCore.Authentication.JwtBearer — пакет для интеграции JWT-аутентификации в конвейер обработки запросов ASP.NET Core[40].
  • Go:
    • golang-jwt/jwt — стандарт де-факто в экосистеме Go. Эта библиотека является активно поддерживаемым сообществом преемником устаревшего пакета `dgrijalva/jwt-go`. Для новых проектов рекомендуется использовать последнюю версию (v5)[41][42].
  • PHP:
    • firebase/php-jwt — простая и легковесная библиотека, популярная для стандартных задач[43].
    • lcobucci/jwt — более мощное и гибкое решение, подходящее для проектов со сложными требованиями к настройке токенов[43].

Примечани