Шифрование в формате JWE Compact Serialization в библиотеке jose
строится вокруг класса CompactEncrypt, который реализует
создание зашифрованного JSON Web Encryption токена в компактной
строковой форме. Этот формат используется, когда требуется не подпись, а
именно конфиденциальность данных: полезная нагрузка полностью шифруется
и становится недоступной без ключа расшифровки.
Compact JWE состоит из пяти частей, разделённых точками:
header.encryptedKey.iv.ciphertext.tag
Каждая часть кодируется в Base64URL. В отличие от JWS, здесь содержимое не читается, а полностью зашифровано.
В библиотеке jose процесс формирования этого токена инкапсулирован в
CompactEncrypt, который последовательно:
Ключевым элементом является симметричный или асимметричный ключ в формате JWK или CryptoKey.
Пример использования симметричного ключа:
import { CompactEncrypt, generateSecret } from 'jose'
// создание ключа шифрования
const secretKey = await generateSecret('A256GCM')
// полезная нагрузка
const payload = new TextEncoder().encode(
JSON.stringify({ userId: 123, role: 'admin' })
)
// создание JWE
const jwe = await new CompactEncrypt(payload)
.setProtectedHeader({
alg: 'dir',
enc: 'A256GCM'
})
.encrypt(secretKey)
console.log(jwe)
Protected header — это JSON-объект, который защищён шифрованием и участвует в расчёте целостности токена.
Основные параметры:
alg — алгоритм управления ключомenc — алгоритм шифрования содержимогоПример:
{
"alg": "dir",
"enc": "A256GCM"
}
Алгоритм dir означает прямое использование симметричного
ключа без его обёртки (Key Wrapping). Это самый простой сценарий,
подходящий для shared secret.
Используется, когда один и тот же ключ применяется для шифрования и расшифровки.
.setProtectedHeader({
alg: 'dir',
enc: 'A256GCM'
})
При асимметричном подходе используется публичный ключ для защиты симметричного CEK (Content Encryption Key).
.setProtectedHeader({
alg: 'RSA-OAEP-256',
enc: 'A256GCM'
})
В этом случае библиотека автоматически:
При вызове .encrypt(key) происходит несколько
этапов:
encimport { CompactEncrypt, importJWK } from 'jose'
const publicKeyJwk = {
kty: 'RSA',
e: 'AQAB',
n: '...'
}
const publicKey = await importJWK(publicKeyJwk, 'RSA-OAEP-256')
const payload = new TextEncoder().encode('sensitive data')
const jwe = await new CompactEncrypt(payload)
.setProtectedHeader({
alg: 'RSA-OAEP-256',
enc: 'A256GCM'
})
.encrypt(publicKey)
Compact формат имеет ограничения:
Это делает его компактным и удобным для HTTP заголовков, cookies или URL-safe передачи.
Payload в jose всегда передаётся как Uint8Array. Это
означает, что строковые данные должны быть предварительно
закодированы:
const encoder = new TextEncoder()
const payload = encoder.encode(
JSON.stringify({
session: 'abc123',
expires: 1710000000
})
)
При расшифровке используется TextDecoder.
Поддерживаемые enc алгоритмы:
A128GCMA192GCMA256GCMНа практике чаще всего используется A256GCM как наиболее
устойчивый вариант.
При использовании dir критически важно:
При RSA сценарии:
Если ключ не соответствует алгоритму, библиотека выбросит ошибку во
время .encrypt().
Например, использование RSA-OAEP-256 с симметричным
ключом невозможно.
CompactEncrypt этого не поддерживает, в таком случае требуется General JWE JSON Serialization.
Полученная строка выглядит примерно так:
eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..vZ3...8kQ..m9P...Q8
Разделы:
dirCompactEncrypt чаще всего применяется для:
Особенно полезен в архитектурах, где требуется:
Хотя основная операция — шифрование, важный аспект заключается в том, что GCM режим обеспечивает:
Любое изменение строки приводит к ошибке расшифровки.
Факторы влияния:
Для high-load систем предпочтительно:
dir с заранее распределёнными ключами