Отличие зашифрованного JWT от подписанного

Подписанный JWT (JWS) и зашифрованный JWT (JWE) решают разные задачи и часто путаются, хотя на уровне использования в JavaScript через библиотеку Jose они выглядят схожими по форме — компактная строка из нескольких частей.

Подписанный JWT (JSON Web Signature) предназначен для обеспечения целостности данных и аутентичности источника. Он не скрывает содержимое токена.

JWT в формате JWS состоит из трёх частей:

  • Header (заголовок)
  • Payload (данные)
  • Signature (подпись)

Формат:

xxxxx.yyyyy.zzzzz

Что даёт подпись

Подпись решает две задачи:

  • Проверка, что данные не были изменены после выпуска токена
  • Подтверждение, что токен был подписан владельцем секретного ключа или приватного ключа

При этом содержимое payload остаётся открытым. Любой может декодировать base64url и увидеть данные:

  • userId
  • role
  • exp
  • любые кастомные поля

Алгоритмы подписи в Jose

Библиотека Jose реализует JWS через модуль jose/jwt/sign.

Типичные алгоритмы:

  • HS256 — симметричный HMAC
  • RS256 — RSA с SHA-256
  • ES256 — ECDSA

Пример логики:

import { SignJWT } from 'jose'

const jwt = await new SignJWT({ userId: 123 })
  .setProtectedHeader({ alg: 'HS256' })
  .setExpirationTime('2h')
  .sign(secretKey)

Важно: секрет или приватный ключ участвует только в создании подписи, но не скрывает данные.


Зашифрованный JWT (JWE)

Зашифрованный JWT (JSON Web Encryption) решает другую задачу — конфиденциальность данных.

В отличие от JWS, здесь payload недоступен без ключа.

Структура JWE включает 5 частей:

header.encryptedKey.iv.ciphertext.tag

Что даёт шифрование

JWE обеспечивает:

  • Полную скрытность payload
  • Защиту от чтения третьими лицами
  • Возможность безопасно передавать чувствительные данные

Даже если токен перехвачен, его содержимое невозможно восстановить без ключа.


Алгоритмы шифрования в Jose

Jose реализует JWE через jose/jwt/encrypt.

Типичные алгоритмы:

  • RSA-OAEP — шифрование ключа
  • A256GCM — симметричное шифрование контента
  • ECDH-ES — обмен ключами на основе эллиптических кривых

Пример:

import { EncryptJWT } from 'jose'

const jwt = await new EncryptJWT({ userId: 123 })
  .setProtectedHeader({ alg: 'RSA-OAEP', enc: 'A256GCM' })
  .setExpirationTime('2h')
  .encrypt(publicKey)

Здесь используется публичный ключ для шифрования, а приватный — для расшифровки.


Ключевое различие между JWS и JWE

Подписанный JWT (JWS)

  • Данные не скрыты
  • Защищена целостность
  • Проверяется подлинность
  • Payload читаем без ключа

Зашифрованный JWT (JWE)

  • Данные скрыты
  • Защищена конфиденциальность
  • Требуется ключ для чтения
  • Payload недоступен без расшифровки

Важный практический момент

Подпись и шифрование решают разные задачи и не заменяют друг друга.

  • JWS отвечает за: «можно ли доверять данным»
  • JWE отвечает за: «можно ли видеть данные»

Использование в реальных системах

Когда используют JWS

  • Авторизация пользователей
  • Передача роли и идентификаторов
  • Stateless API authentication
  • OAuth 2.0 access tokens

Типичный кейс: фронтенд может видеть payload, но не может его подделать.


Когда используют JWE

  • Передача персональных данных
  • Медицинская или финансовая информация
  • Секретные бизнес-данные
  • Сценарии, где даже клиент не должен видеть payload

Ошибки при использовании Jose и JWT

1. Использование JWS вместо JWE для секретных данных

Распространённая ошибка — хранить чувствительные данные (например, паспортные данные) в подписанном токене. Подпись не защищает от чтения.

2. Попытка «спрятать» данные base64

Base64 не является шифрованием. В JWS payload читается мгновенно.

3. Неверное понимание роли ключей

  • В JWS секрет или приватный ключ используется для подписи
  • В JWE публичный ключ используется для шифрования, приватный — для расшифровки

Комбинированные сценарии

Иногда применяют оба подхода:

  1. Сначала данные шифруются (JWE)
  2. Затем весь токен подписывается (JWS поверх JWE)

Это даёт:

  • Конфиденциальность (шифрование)
  • Проверку целостности (подпись)

Но увеличивает сложность и размер токена.


Архитектурное различие на уровне Jose

В библиотеке Jose эти два мира строго разделены:

  • jose/jwt/sign → JWS
  • jose/jwt/encrypt → JWE

Они используют разные криптографические примитивы и разные форматы сериализации.

JWS ориентирован на компактность и скорость. JWE — на безопасность данных даже в недоверенной среде.


Практическое правило выбора

  • Если данные можно безопасно читать клиенту → JWS
  • Если данные должны быть скрыты полностью → JWE
  • Если требуется максимальная защита → JWE + JWS

Разделение этих подходов — ключевой момент при проектировании безопасных систем аутентификации и обмена данными в JavaScript-экосистеме с использованием Jose.