В стандарте JSON Web Signature (JWS), описанном в RFC 7515, полезная
нагрузка (payload) по умолчанию кодируется в формате
Base64URL перед вычислением подписи. Это поведение закреплено как
стандартное и ожидаемое большинством реализаций.
Однако расширение RFC 7797 вводит параметр заголовка
b64, позволяющий отключить это кодирование. Это открывает
возможность работы с неприкреплённым (unencoded) payload, что
особенно важно для сценариев с потоковыми данными, большими файлами или
уже закодированными структурами.
b64Параметр b64 — это булево значение в заголовке JWS:
{
"alg": "HS256",
"b64": false,
"crit": ["b64"]
}
Ключевые особенности:
b64: true (по умолчанию) — payload кодируется в
Base64URLb64: false — payload используется как есть,
без кодированияcrit,
иначе токен считается некорректнымПочему нужен crit: Поле
crit (critical headers) сообщает валидатору, что он обязан
понимать указанные параметры. Если валидатор не знает про
b64, он должен отклонить токен.
b64: falseОбычный JWS:
BASE64URL(header) + "." + BASE64URL(payload)
С b64: false:
BASE64URL(header) + "." + payload (в исходном виде)
Это означает:
.) остаётся разделителемИспользование b64: false накладывает строгие
ограничения:
.Поскольку . используется как разделитель, его наличие в
payload нарушает структуру JWS Compact Serialization.
Некодированные бинарные данные могут привести к некорректной интерпретации. В таких случаях используют Detached Payload.
Если библиотека не поддерживает b64: false, проверка
подписи завершится ошибкой.
Detached Payload — это вариант JWS, при котором payload не включается в сам токен, а передаётся отдельно.
Формат Compact Serialization:
BASE64URL(header) + ".." + BASE64URL(signature)
Обратите внимание на двойную точку .. — это индикатор
отсутствующего payload.
jose в
JavaScriptБиблиотека jose (npm пакет) поддерживает
b64: false и detached payload через низкоуровневые API.
import { CompactSign } from 'jose'
const payload = new TextEncoder().encode('example payload')
const jws = await new CompactSign(payload)
.setProtectedHeader({
alg: 'HS256',
b64: false,
crit: ['b64']
})
.sign(secretKey)
Важно:
Uint8Arrayb64: false требует явного указания
critimport { FlattenedSign } from 'jose'
const payload = new TextEncoder().encode('external data')
const jws = await new FlattenedSign(payload)
.setProtectedHeader({
alg: 'RS256',
b64: false,
crit: ['b64']
})
.sign(privateKey)
Результат:
{
"protected": "...",
"signature": "..."
}
Payload отсутствует — его необходимо передать отдельно при проверке.
import { flattenedVerify } from 'jose'
await flattenedVerify(jws, publicKey, {
payload: externalPayload
})
Особенности:
Большинство JWT/JWS библиотек не поддерживают
b64: false, особенно в high-level API.
Если payload передаётся отдельно, важно гарантировать:
Detached payload должен передаваться по тому же доверенному каналу, что и подпись.
b64: falseПодход оправдан в следующих случаях:
critb64: false| Характеристика | Обычный JWS | b64: false |
|---|---|---|
| Кодирование payload | Base64URL | Нет |
| Совместимость | Высокая | Ограниченная |
| Поддержка библиотек | Повсеместная | Частичная |
| Возможность detached | Нет | Да |
| Размер токена | Больше | Меньше |
crit: ['b64']Uint8Array для payload. в данныхjoseБиблиотека jose:
critb64 на этапе подписи и верификацииЭто делает реализацию безопасной, но строгой.
Поддержка b64: false — это именно расширение, а не часть
базового стандарта.
Использование b64: false — это переход от стандартной
модели JWT к более низкоуровневой криптографической подписи. Это даёт
гибкость, но требует строгого контроля:
В большинстве прикладных задач достаточно стандартного
Base64URL-кодирования, а b64: false остаётся инструментом
для специализированных сценариев, где важна эффективность и контроль над
байтовым представлением данных.