JWT (JSON Web Tokens)
JWT (англ. JSON Web Token, также JSON-веб-токен) — открытый стандарт RFC 7519, задающий компактный и самодостаточный способ безопасной передачи данных между сторонами в формате JSON[1]. Подлинность токена подтверждается за счёт цифровой подписи, что обеспечивает целостность передаваемой информации[2].
Общие сведения
| JWT | |
|---|---|
| англ. JSON Web Token | |
| Область использования | Веб-разработка, Информационная безопасность |
История
Разработка стандарта JWT велась в рамках Инженерного совета Интернета (IETF) при участии рабочей группы JOSE (JSON Object Signing and Encryption), сформированной в 2011 году для создания стандартов подписи и шифрования JSON-объектов. Предпосылкой стало появление формата JSON, разработанного в 2000-х годах Дугласом Крокфордом как более простая альтернатива XML. Первые черновики спецификаций JOSE начали публиковаться к 2013 году. В мае 2015 года был утверждён стандарт RFC 7519 (JSON Web Token), авторами которого стали Майкл Б. Джонс, Джон Брэдли и Нэт Сакимура. Одновременно были приняты связанные спецификации: RFC 7515 (JWS, цифровая подпись), RFC 7516 (JWE, шифрование), RFC 7517 (JWK, представление ключей) и RFC 7518 (JWA, алгоритмы). В настоящее время JWT остаётся промышленным стандартом для безопасной передачи данных между сторонами[3][4][4][5][6].
Определение
Согласно RFC 7519, JSON Web Token — это компактное URL-безопасное средство представления утверждений (claims) для передачи между сторонами. Токен представляет собой строку из трёх частей (заголовок, полезная нагрузка и подпись), разделённых точками и закодированных с использованием Base64URL[1].
- Компактность: использование JSON и Base64URL-кодирования позволяет передавать токен в HTTP-заголовках и URL[7].
- Самодостаточность: все необходимые данные о субъекте содержатся внутри токена, что исключает необходимость хранения состояния сессии на сервере.
- Проверяемость и криптографическая защита: подпись (или MAC), создаваемая с использованием HMAC, RSA или ECDSA, гарантирует целостность данных и подлинность издателя[2].
- Расширяемость: наряду с зарегистрированными клеймами (iss, exp, sub, aud и др.) допускается использование пользовательских данных[8].
- Открытость стандарта: спецификация RFC 7519 свободно реализуется в различных языках и средах[9].
Структурные элементы JWT
JWT состоит из трёх Base64url-кодированных сегментов, разделённых точками («.»):
JSON-объект с метаданными токена. Основные поля:
- typ — тип токена, обычно «JWT»;
- alg — алгоритм подписи (например, HS256, RS256) либо значение «none» для неподписанных токенов. Возможность указания «none» является известной уязвимостью (атака с подменой алгоритма): злоумышленник может изменить это поле на «none» и удалить подпись. Если серверная библиотека сконфигурирована неверно и не проверяет алгоритм, она может посчитать такой токен действительным, что позволяет полностью подделать его содержимое[10].
Содержит совокупность утверждений (claims), которые делятся на зарегистрированные, публичные и частные.
- Зарегистрированные утверждения (Registered Claims): предопределённый набор утверждений, таких как iss (издатель), exp (срок действия), sub (субъект), aud (аудитория), nbf (не раньше), iat (создан) и jti (идентификатор токена).
- Публичные и частные утверждения (Public and Private Claims): пользовательские данные (например, role, userId).
Поскольку полезная нагрузка по умолчанию не шифруется, а лишь кодируется с помощью Base64url, её содержимое может быть легко прочитано любой стороной, перехватившей токен. Это создаёт риск утечки чувствительных данных, если они помещены в полезную нагрузку в открытом виде[11]. Для обеспечения конфиденциальности данных используется стандарт JSON Web Encryption (JWE).
Создаётся путём хэширования строки «Base64url(Header).Base64url(Payload)» с использованием секретного ключа (HMAC) либо закрытого ключа (RSA/ECDSA). Подпись обеспечивает:
- подтверждение издателя;
- защиту от изменения содержимого токена[12].
Одной из известных уязвимостей, связанных с подписью, является атака «Algorithm Confusion» (путаница алгоритмов). Она возникает, когда сервер некорректно валидирует алгоритм, указанный в заголовке, и позволяет переключаться между асимметричными (например, RS256) и симметричными (HS256) алгоритмами. Злоумышленник может взять публичный ключ, предназначенный для асимметричного шифрования, и использовать его как секрет для создания подписи с симметричным алгоритмом (HS256). Если сервер ожидает токен с любым из этих алгоритмов, он может ошибочно проверить подпись HS256, используя публичный ключ как секрет, и счесть поддельный токен действительным.
В итоговом виде токен выглядит как: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJleGFtcGxlIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c.
- Клиент отправляет учётные данные серверу.
- При успешной проверке сервер формирует Header и Payload, подписывает их секретом/ключом и возвращает JWT клиенту[13].
После получения JWT клиент должен безопасно его сохранить. Выбор способа хранения является критически важным аспектом безопасности, поскольку неправильный подход может привести к краже токена.
Хранение токена в веб-хранилищах, таких как `localStorage` или `sessionStorage`, считается небезопасным. Основная причина — уязвимость к атакам типа межсайтового скриптинга (XSS). Если злоумышленнику удаётся внедрить на страницу вредоносный JavaScript-код, он может получить полный доступ к хранилищу и украсть токен[14][15].
Более безопасным подходом является использование cookie с флагом `HttpOnly`. Этот флаг запрещает доступ к cookie из JavaScript, что эффективно защищает от кражи токена через XSS[16]. Однако этот метод уязвим для атак типа межсайтовой подделки запроса (CSRF), если не приняты дополнительные меры защиты[17].
Современной рекомендованной практикой является комбинированная схема с использованием двух токенов — токена доступа (access token) и токена обновления (refresh token)[14]:
- Токен доступа — короткоживущий токен (например, 5–15 минут), который хранится в памяти клиентского приложения (например, в переменной JavaScript). Это наиболее безопасный способ хранения, так как он недоступен для XSS-атак при перезагрузке страницы, но сам токен теряется при обновлении вкладки[18].
- Токен обновления — долгоживущий токен, который сохраняется в cookie с максимальными мерами защиты: `HttpOnly` (защита от XSS), `Secure` (передача только по HTTPS) и `SameSite=Strict` или `SameSite=Lax` (защита от CSRF)[19][20].
Эта архитектура минимизирует риски: даже в случае кражи короткоживущего токена доступа ущерб будет ограниченным, а наиболее ценный токен обновления надёжно защищён в cookie.
При обращении к защищённым ресурсам клиент включает JWT в заголовок Authorization: Bearer <token>[21].
Сервер:
- проверяет подпись токена;
- удостоверяется, что exp не истёк и другие клеймы (iss, aud) валидны;
- извлекает данные пользователя и принимает решение об авторизации[22].
Поскольку JWT по своей природе являются stateless (не хранят состояние), одной из ключевых проблем является невозможность досрочного отзыва скомпрометированного токена — он остаётся действительным до истечения своего срока действия[23]. Для решения этой проблемы и повышения общего уровня безопасности применяется механизм обновления с использованием двух токенов: короткоживущего токена доступа (access token) и долгоживущего токена обновления (refresh token).
Схема работы выглядит следующим образом:
- Клиентское приложение использует токен доступа для авторизации запросов к защищённым ресурсам API.
- Когда срок действия токена доступа истекает, сервер возвращает ошибку авторизации (например, со статусом 401 Unauthorized).
- Получив ошибку, клиентское приложение отправляет запрос на специальный эндпоинт (например,
/api/refresh), не включая в него никаких данных вручную. Браузер автоматически прикрепляет к этому запросу токен обновления, который хранится в защищённой cookie с флагамиHttpOnly,SecureиSameSite. - Сервер получает токен обновления, проверяет его подлинность и валидность (например, сверяясь со списком действующих токенов в базе данных). Это позволяет централизованно отзывать сессии пользователей, просто удаляя их токен обновления[24].
- В случае успеха сервер генерирует новую пару токенов: новый токен доступа и, как правило, новый токен обновления (для реализации ротации токенов). Новый токен доступа возвращается в теле ответа, а новый токен обновления устанавливается в cookie, заменяя старый.
- Клиентское приложение сохраняет новый токен доступа (например, в памяти) и повторяет исходный запрос, который завершился ошибкой.
Этапы работы с JWT
- Создание — сервер формирует Header и Payload, подписывает их выбранным алгоритмом и возвращает клиенту готовый токен[2].
- Подпись — обеспечивает целостность и подтверждает источник токена[25].
- Передача — клиент отправляет значение в заголовке
Authorization: Bearer <token>; коммуникация должна происходить по HTTPS[26]. - Проверка — сервер валидирует подпись и контролирует утверждения (
exp,iat,jti)[27]. - Обновление — по истечении срока действия access-токена клиент обменивает refresh-токен на новую пару токенов, сохраняя непрерывность сессии[28].
Преимущества и недостатки
- Stateless-аутентификация — не требует хранения сессий на сервере, облегчая горизонтальное масштабирование[2].
- Компактность передачи — удобен для мобильных и IoT-устройств[29].
- Криптографическая целостность — подпись выявляет любые изменения содержимого[30].
- Кроссплатформенность — реализуется практически на всех популярных языках[9].
- Снижение риска CSRF — отсутствие cookie-сессий упрощает защиту[31].
- Сложность отзыва — действительность токена прекращается лишь после истечения срока либо при использовании «чёрных списков»[30].
- Повышенный размер — хранит все данные внутри себя, что увеличивает объём трафика.
- Риск при утечке — украденный токен позволяет злоумышленнику действовать от имени жертвы до истечения
exp[32]. - Жёсткое время жизни — внезапное истечение может ухудшать UX.
- Уязвимости при слабой конфигурации — выбор устаревших алгоритмов или коротких секретов приводит к компрометации[32].
Сферы применения
- Аутентификация REST-API — проверка подлинности запросов без повторной передачи учётных данных.
- Авторизация — хранение ролей и прав доступа в Payload позволяет сервисам принимать решения локально[9].
- SSO — единый вход для набора приложений по протоколу OpenID Connect.
- Микросервисные архитектуры — обмен удостоверениями между сервисами без центрального хранилища сессий[30].
- Мобильные приложения — компактное хранение токена в безопасном хранилище устройства[33].
- IoT-устройства — подтверждение подлинности сенсоров и шлюзов при обмене телеметрией.
- Защищённый обмен данными между системами — криптографическая подпись гарантирует целостность и источник сообщения[9].
Инструменты для работы с JWT
Для работы с JSON Web Tokens (JWT) существует множество инструментов: от онлайн-декодеров до специализированных библиотек для разработки и тестирования безопасности.
Для интеграции JWT в код используются готовые реализации стандарта RFC 7519 для разных языков программирования:
- JavaScript/Node.js
- * jsonwebtoken
- * panva/jose
- * nJwt[34]
- Python
- * PyJWT
- * Authlib
- Java
- * java-jwt (Auth0)
- * Nimbus JOSE + JWT
- PHP
- * firebase/php-jwt
- * tymon/jwt-auth
- .NET
- * System.IdentityModel.Tokens.Jwt
- * jwt-dotnet/jwt
- Go
- * golang-jwt/jwt
- Ruby
- * jwt[35]
Эти инструменты позволяют быстро декодировать токен, проверить его структуру и подпись.
- jwt.io — декодирование, подпись и проверка токенов в браузере[1].
- FusionAuth JWT Decoder — интерактивная валидация и просмотр Payload[36].
- JWT.one — генератор и декодер с поддержкой различных алгоритмов.
При использовании веб-инструментов рекомендуется удалять конфиденциальные данные из токена или применять их исключительно в тестовых целях.
Примечания
| Правообладателем данного материала является АНО «Интернет-энциклопедия «РУВИКИ». Использование данного материала на других сайтах возможно только с согласия АНО «Интернет-энциклопедия «РУВИКИ». |