Компактная сериализация JWE — это самый распространённый формат представления зашифрованного JSON Web Encryption, в котором все компоненты токена упакованы в одну строку, разделённую точками. Именно этот формат используется в большинстве веб-приложений, API и OAuth/OIDC сценариях благодаря своей компактности и удобству передачи через HTTP-заголовки и URL-параметры.
В библиотеке jose работа с JWE компактной сериализацией строится
вокруг высокоуровневых функций compactEncrypt и
compactDecrypt, которые инкапсулируют всю криптографическую
сложность.
Формат JWE Compact Serialization всегда состоит из пяти частей:
BASE64URL(Protected Header) .
BASE64URL(Encrypted Key) .
BASE64URL(Initialization Vector) .
BASE64URL(Ciphertext) .
BASE64URL(Authentication Tag)
Каждая часть имеет строго определённое назначение:
Эта структура фиксирована и не может быть изменена без нарушения спецификации.
JWE использует двухуровневую схему:
Пример распространённых комбинаций:
RSA-OAEP-256 + A256GCMECDH-ES + A256GCMdir + A256GCM (прямое использование
ключа)В библиотеке jose процесс шифрования выглядит следующим образом:
import { compactEncrypt } from 'jose'
const encoder = new TextEncoder()
const jwe = await new compactEncrypt(
encoder.encode('Секретное сообщение')
)
.setProtectedHeader({
alg: 'RSA-OAEP-256',
enc: 'A256GCM'
})
.encrypt(publicKey)
В этом примере:
alg определяет алгоритм шифрования ключаenc задаёт алгоритм шифрования содержимогоpublicKey используется для шифрования CEKРезультатом будет строка вида:
eyJhbGciOiJS... .
OKOawDo13gRp2... .
48V1_ALb6US04U3e... .
5eym8Tw6gH7s... .
XFBoMYUZodetZdvTiFvSkQ
Расшифровка выполняется симметричной операцией:
import { compactDecrypt } from 'jose'
const { plaintext } = await compactDecrypt(jwe, privateKey)
console.log(new TextDecoder().decode(plaintext))
На этом этапе:
Protected Header всегда включается в процесс аутентификации. Он кодируется в base64url и участвует в вычислении authentication tag.
Пример header:
{
"alg": "RSA-OAEP-256",
"enc": "A256GCM",
"typ": "JWE"
}
Изменение любого поля header после шифрования приводит к невозможности верификации тегов.
IV (Initialization Vector) в JWE:
Повтор IV с тем же ключом приводит к критическим уязвимостям в режиме GCM.
CEK — это симметричный ключ, который используется для фактического шифрования payload.
Процесс:
Таким образом достигается гибридная криптография:
Compact Serialization имеет ряд ограничений:
В отличие от него JSON Serialization поддерживает:
В реальных системах часто встречаются следующие проблемы:
alg и типа ключа (например, RSA-OAEP-256
с симметричным ключом)enc алгоритма между encrypt/decrypt
сторонамиПри использовании alg: "dir" CEK не шифруется, а
используется напрямую:
const jwe = await new compactEncrypt(
encoder.encode('data')
)
.setProtectedHeader({
alg: 'dir',
enc: 'A256GCM'
})
.encrypt(sharedSecretKey)
Это упрощает структуру, но требует безопасного обмена ключом заранее.
При вызове encrypt() выполняется последовательность:
Каждый этап строго детерминирован спецификацией JWE (RFC 7516), что обеспечивает совместимость между различными реализациями.
Compact Serialization оптимизирована под:
Поэтому именно этот формат используется в большинстве реализаций OAuth2/OIDC и систем авторизации на базе JWT + JWE.