Структура JWT: Заголовок, Полезная нагрузка и Подпись
В современную эпоху веб-разработки обеспечение безопасности взаимодействия между клиентами и серверами имеет первостепенное значение. JSON Web Tokens (JWT) стали отраслевым стандартом для безопасного представления утверждений (claims) между двумя сторонами. Независимо от того, создаете ли вы одностраничное приложение (SPA), мобильное приложение или микросервисную архитектуру, понимание того, как работают JWT, необходимо для реализации надежной аутентификации и авторизации.
Хотя многие разработчики используют готовые библиотеки для работы с JWT, глубокое понимание их внутренней структуры позволяет эффективнее проводить отладку, аудит безопасности и принимать правильные архитектурные решения. В этом подробном руководстве мы разберем три части JWT, объясним процесс аутентификации и обсудим лучшие практики безопасности.
Что такое JSON Web Token (JWT)?
JSON Web Token (JWT) — это открытый стандарт (RFC 7519), который определяет компактный и автономный способ безопасной передачи информации между сторонами в виде объекта JSON. Эта информация может быть проверена и ей можно доверять, поскольку она имеет цифровую подпись. JWT могут быть подписаны с использованием секретного ключа (с помощью алгоритма HMAC) или пары открытого/закрытого ключей с использованием RSA или ECDSA.
«Автономность» JWT является их самым большим преимуществом. Они несут в себе всю необходимую информацию о пользователе, а это значит, что серверу не нужно запрашивать базу данных для проверки личности пользователя при каждом запросе. Это делает JWT идеальными для распределенных систем и горизонтального масштабирования.
Общие случаи использования включают:
- Авторизация: Самый распространенный сценарий использования JWT. Как только пользователь входит в систему, каждый последующий запрос будет включать JWT, позволяя пользователю получать доступ к маршрутам, сервисам и ресурсам, которые разрешены с этим токеном.
- Обмен информацией: JWT — это хороший способ безопасной передачи информации между сторонами. Поскольку JWT могут быть подписаны — например, с использованием пар открытого/закрытого ключей — вы можете быть уверены, что отправители являются теми, за кого себя выдают. Кроме того, поскольку подпись рассчитывается с использованием заголовка и полезной нагрузки, вы также можете убедиться, что содержимое не было изменено.
Три части JWT
В своей компактной форме JSON Web Token состоит из трех частей, разделенных точками (.):
- Заголовок (Header)
- Полезная нагрузка (Payload)
- Подпись (Signature)
Таким образом, JWT обычно выглядит следующим образом:
xxxxx.yyyyy.zzzzz
Давайте разберем каждую часть, чтобы увидеть, что они содержат и как они кодируются. Если вам когда-нибудь понадобится проверить реальный токен, вы можете использовать наш JWT Decoder, чтобы увидеть, что именно находится внутри.
Часть 1: Заголовок (Header)
Заголовок обычно состоит из двух частей: типа токена (JWT) и используемого алгоритма подписи, такого как HMAC SHA256 или RSA.
{
"alg": "HS256",
"typ": "JWT"
}
Затем этот JSON кодируется в формат Base64Url, образуя первую часть JWT. Важно отметить, что кодирование Base64Url — это не шифрование; это просто способ представления двоичных данных в виде строки, безопасной для использования в URL.
Поле alg (алгоритм) имеет решающее значение. Оно сообщает получателю, как проверять подпись. Однако это поле было источником многих уязвимостей в прошлом (например, атака с алгоритмом «none»), поэтому современные библиотеки требуют явного определения ожидаемых алгоритмов при проверке.
Часть 2: Полезная нагрузка (Payload)
Вторая часть токена — это полезная нагрузка, содержащая утверждения (claims). Утверждения — это заявления об объекте (обычно о пользователе) и дополнительные данные. Существует три типа утверждений: зарегистрированные, публичные и приватные.
- Зарегистрированные утверждения: Это набор предопределенных утверждений, которые не являются обязательными, но рекомендуются для обеспечения совместимости. Некоторые из них:
iss(издатель),exp(время истечения),sub(субъект),aud(аудитория) и другие. - Публичные утверждения: Они могут определяться разработчиками по желанию. Но чтобы избежать коллизий, они должны быть определены в реестре IANA JSON Web Token или определены как URI, содержащий пространство имен, устойчивое к коллизиям.
- Приватные утверждения: Это пользовательские утверждения, созданные для обмена информацией между сторонами, которые договорились об их использовании, и не являются ни зарегистрированными, ни публичными.
Пример полезной нагрузки может выглядеть так:
{
"sub": "1234567890",
"name": "Ivan Ivanov",
"admin": true,
"iat": 1516239022,
"exp": 1516242622
}
Полезная нагрузка затем кодируется в Base64Url для формирования второй части токена. Вы можете использовать наш JWT Decoder, чтобы быстро извлечь эти утверждения из любого токена, с которым вы столкнетесь во время разработки.
Часть 3: Подпись (Signature)
Чтобы создать часть подписи, вы должны взять закодированный заголовок, закодированную полезную нагрузку, секретный ключ, алгоритм, указанный в заголовке, и подписать это.
Например, если вы хотите использовать алгоритм HMAC SHA256, подпись будет создана следующим образом:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
Подпись используется для проверки того, что сообщение не было изменено по пути, а в случае токенов, подписанных закрытым ключом, она также может подтвердить, что отправитель JWT является тем, за кого себя выдает. Это самая критическая часть JWT, так как она обеспечивает гарантию целостности.
Как работает аутентификация JWT (процесс)
Типичный процесс аутентификации на основе JWT включает следующие шаги:
- Запрос на вход: Клиент отправляет свои учетные данные (например, имя пользователя и пароль) на сервер.
- Генерация токена: Сервер проверяет учетные данные и, если они верны, создает JWT. Сервер подписывает JWT с использованием секретного или закрытого ключа.
- Ответ с токеном: Сервер отправляет JWT обратно клиенту.
- Хранение: Клиент сохраняет токен, обычно в
localStorageили вHttpOnlycookie. - Последующие запросы: Для каждого запроса к защищенному ресурсу клиент отправляет JWT в заголовке
Authorization, используя схемуBearer:Authorization: Bearer <token>. - Верификация: Сервер получает запрос, извлекает токен и проверяет его подпись с помощью секретного или открытого ключа. Если подпись действительна и срок действия токена не истек, сервер предоставляет доступ к запрошенному ресурсу.
Этот процесс устраняет необходимость для сервера поддерживать состояние сеанса в памяти (или базе данных/Redis) для каждого пользователя, что значительно снижает накладные расходы на стороне сервера и обеспечивает лучшую масштабируемость.
Лучшие практики безопасности: почему не стоит хранить секреты в JWT
Распространенным заблуждением среди разработчиков является то, что JWT — это безопасный способ скрыть конфиденциальные данные. Это неверно. Если вы не используете JSON Web Encryption (JWE), полезная нагрузка JWT только кодируется Base64Url, а не шифруется.
Любой, кто перехватит токен, может легко декодировать полезную нагрузку и прочитать информацию внутри. Поэтому никогда не следует хранить пароли, номера социального страхования или другие конфиденциальные секреты в полезной нагрузке. Чтобы убедиться, что вы используете надежные секреты для процесса подписания, вы можете использовать наш Password Generator для создания ключей с высокой энтропией.
Ключевые советы по безопасности:
- Всегда используйте HTTPS: Чтобы предотвратить атаки типа «человек посередине» (MITM), направленные на кражу ваших токенов.
- Короткий срок действия: Устанавливайте короткое время истечения (утверждение
exp), чтобы минимизировать окно возможностей для злоумышленника в случае кражи токена. - Используйте HttpOnly Cookies: Если вы храните JWT в браузере, использование флагов
HttpOnlyиSecureдля файлов cookie помогает защититься от атак типа межсайтового скриптинга (XSS). - Проверяйте алгоритм: Не доверяйте слепо заголовку
alg. Жестко закодируйте ожидаемый алгоритм в логике верификации.
JWT против сессионных кук: ключевые различия
Выбор между JWT и традиционными сессионными куками зависит от требований вашего приложения. Вот сравнение:
| Особенность | Сессионные куки | JSON Web Tokens |
|---|---|---|
| Состояние | С сохранением состояния (на сервере) | Без сохранения состояния (на клиенте) |
| Масштабируемость | Сложнее (требуются липкие сессии или общее хранилище) | Проще (полностью независимы) |
| Отзыв | Легко (удаление с сервера) | Сложно (требуется черный список или короткий срок действия) |
| Размер | Маленький (только ID сессии) | Большой (содержит все утверждения) |
Общие алгоритмы JWT (HS256 против RS256)
Существует два основных типа алгоритмов подписи, используемых с JWT: симметричные и асимметричные.
HS256 (HMAC с SHA-256) — это симметричный алгоритм, что означает, что один и тот же секретный ключ используется как для подписи, так и для проверки токена. Его просто реализовать, но он требует, чтобы и издатель, и потребитель безопасно обменивались секретом.
RS256 (подпись RSA с SHA-256) — это асимметричный алгоритм, то есть он использует закрытый ключ для подписи токена и открытый ключ для его проверки. Это более безопасно для сценариев, где сервис, выпускающий токен, отличается от сервиса, потребляющего его (например, провайдеры OAuth2, такие как Google или Auth0).
| Алгоритм | Тип | Требования к ключам | Лучше всего для |
|---|---|---|---|
| HS256 | Симметричный | Один общий секретный ключ | Внутренние приложения, небольшие команды |
| RS256 | Асимметричный | Закрытый ключ (подпись), Открытый ключ (проверка) | Микросервисы, публичные API, провайдеры личности |
Заключение
JSON Web Tokens предлагают мощный и гибкий способ обработки аутентификации в современных веб-приложениях. Понимая трехчастную структуру — заголовок, полезную нагрузку и подпись — разработчики могут создавать системы, которые являются одновременно масштабируемыми и безопасными. Однако жизненно важно помнить, что JWT — это инструменты для целостности и аутентификации, а не для секретности.
При внедрении JWT всегда уделяйте приоритетное внимание безопасности, используя надежные ключи подписи, принудительное использование HTTPS и сохраняя полезную нагрузку компактной. Независимо от того, отлаживаете ли вы токен с помощью нашего JWT Decoder или генерируете новый секрет с помощью нашего Password Generator, наличие правильных инструментов и знаний — это первый шаг к созданию отличного программного обеспечения.