- 网络安全
- 认证鉴权
- 后端
【免费下载链接】jose
JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes
本篇指南聚焦于 jose 开源仓库中 JWE(JSON Web Encryption)的头部类型定义JWEHeaderParameters(docs/types/interfaces/JWEHeaderParameters.md),逐一剖析alg、enc、crit、zip、kid、jwk、x5c等 11 个可识别头部参数的类型约束、安全语义与运行时前提,并结合 src/types.d.ts、src/lib/jwe_encrypt.ts、src/lib/jwe_decrypt.ts 等源码,揭示这些头部参数在CompactEncrypt/FlattenedEncrypt加密与解密验证链中的实际作用。读完本文,你将能正确构造 JWE 受保护头部、理解为何zip只能用"DEF"、为何crit必须被完整性保护,并在自己的签名/加密场景中安全使用这些参数。
一、接口定位:JWE 头部参数的"识别清单"
JWEHeaderParameters是 jose 内部所有 JWE 加密、解密入口共用的头部类型。其 JSDoc 自述为:"Recognized JWE Header Parameters, any other Header members may also be present."——即它只负责识别并显式建模JWE 规范(RFC 7516)定义的头部参数,同时通过索引签名保留任意自定义扩展成员:
/** Recognized JWE Header Parameters, any other Header members may also be present. */ export interface JWEHeaderParameters extends JoseHeaderParameters { alg?: JWEKeyManagementAlgorithm enc?: JWEContentEncryptionAlgorithm crit?: string[] zip?: 'DEF' | (string & {}) [propName: string]: unknown }该定义位于 src/types.d.ts,关键点有三:
- 继承自
JoseHeaderParameters:公共头部成员(kid、x5t、x5c、x5u、jku、jwk、typ、cty)在 JoseHeaderParameters 中统一定义,JWS 与 JWE 共享(JWS 侧对应 JWSHeaderParameters)。 alg与enc使用细粒度联合类型:alg取值为JWEKeyManagementAlgorithm(密钥管理算法),enc取值为JWEContentEncryptionAlgorithm(内容加密算法),两者均以(string & {})收尾,允许未知的扩展标识符通过类型检查,实际支持与否由运行时的算法表决定。- 索引签名
[propName: string]: unknown:与 RFC 保持一致,允许crit声明的自定义扩展参数以及其他私有头部成员存在。
注意:
CompactJWEHeaderParameters(src/types.d.ts)在JWEHeaderParameters基础上将alg、enc提升为必选属性,因为 Compact 序列化不存在共享非受保护头部与每接收方头部,alg/enc必须出现在受保护头部中。
二、继承的公共成员:kid/jwk/x5c等 JOSE 公共头部
JoseHeaderParameters定义了 JWE 与 JWS 共用的 8 个成员(src/types.d.ts),本接口文档逐一给出了 JOSE 规范名称:
| 成员 | 类型 | JOSE 规范名称 | 语义要点 |
|---|---|---|---|
kid? | string | "kid" (Key ID) | 密钥标识,供接收方在密钥集中定位密钥 |
x5t? | string | "x5t" (X.509 Certificate SHA-1 Thumbprint) | 证书 SHA-1 指纹(base64url) |
x5c? | string[] | "x5c" (X.509 Certificate Chain) | 证书链,数组首项为叶子证书 |
x5u? | string | "x5u" (X.509 URL) | 证书链的 URL 引用 |
jku? | string | "jku" (JWK Set URL) | 指向 JWK Set 的 URL |
jwk? | Omit<JWK, 私钥成员> | "jwk" (JSON Web Key) | 只允许公钥 JWK,见下文 |
typ? | string | "typ" (Type) | 媒体类型,如"JWT" |
cty? | string | "cty" (Content Type) | 载荷内容类型,如嵌套签名场景 |
其中jwk的类型约束最为严格。接口文档明确指出:"This must be a public JSON Web Key; private and symmetric key parameters are not permitted.",对应类型为Omit<JWK, "d" | "p" | "q" | "k" | "dp" | "dq" | "qi" | "priv" | "oth">——即内嵌的 JWK 被排除掉 RSA/EC/OKP 私钥指数、oct 对称密钥k、AKP 私钥priv以及多素数 RSA 的oth等全部私密成员(src/types.d.ts)。这是安全设计:头部是明文传输的,任何私钥材料都不允许放入头部。
三、JWE 专属成员之一:alg(密钥管理算法)
alg(Algorithm)是 JWE 的密钥管理算法标识,决定 CEK(Content Encryption Key)如何被保护与分发。类型JWEKeyManagementAlgorithm(src/types.d.ts)枚举了 jose 支持的 18 个标识符,按家族划分:
- 直接模式:
dir(直接用 CEK 加密,无密钥包装) - AES 密钥包装:
A128KW、A192KW、A256KW - AES-GCM 密钥包装:
A128GCMKW、A192GCMKW、A256GCMKW - ECDH 密钥协商:
ECDH-ES、ECDH-ES+A128KW、ECDH-ES+A192KW、ECDH-ES+A256KW - RSA 密钥封装:
RSA-OAEP、RSA-OAEP-256、RSA-OAEP-384、RSA-OAEP-512 - PBES2 口令派生:
PBES2-HS256+A128KW、PBES2-HS384+A192KW、PBES2-HS512+A256KW
文档与类型定义均注明:某一标识符是否可用取决于运行时(Web Crypto 支持面)。类型末尾的
(string & {})允许扩展算法标识符通过编译。
在源码层面,算法能力集中登记在 src/lib/jwe_algorithms.ts 的JWE表中:每条目描述密钥类型(kty)、Web Crypto 底层算法名(如RSA-OAEP、ECDH、AES-KW、PBKDF2)、所需密钥用法与哈希(如RSA-OAEP-256对应SHA-256)。加密时checkEncryptHeaders首先从合并后的头部取出alg,缺少或非字符串即抛出JWEInvalid(src/lib/jwe_encrypt.ts),随后由jweAlgorithm(alg)查表,未知值抛出JOSENotSupported。
四、JWE 专属成员之二:enc(内容加密算法)
enc(Encryption Algorithm)定义 CEK 与明文的实际加密算法,类型JWEContentEncryptionAlgorithm(src/types.d.ts)枚举 6 个值:
A128GCM、A192GCM、A256GCM(AES-GCM,96 位 IV)A128CBC-HS256、A192CBC-HS384、A256CBC-HS512(AES-CBC + HMAC 复合模式,128 位 IV)
enc的底层参数(CEK 位长、IV 位长、是否为 CBC 复合模式)登记在 src/lib/jwe_algorithms.ts 的ENC表中,例如A128CBC-HS256的cekBits为 256(128 位密钥 + 128 位 HMAC 密钥)、ivBits为 128、cbc为true。加密流程中 CEK 长度、IV 长度均由此表推导:
- 未显式设置 CEK 时,按
encEntry.cekBits生成随机 CEK(generateCek); - 解密时若
encrypted_key解出的 CEK 长度与cekBits不符,会静默替换为随机 CEK再继续解密——这是 RFC 7516 §11.5 的时序攻击缓解要求,见 src/lib/jwe_decrypt.ts。
五、JWE 专属成员之三:crit(关键头部参数)
crit(Critical)的类型为string[],是"必须被接收方理解"的扩展头部参数名列表。jose 在生产侧与消费侧对crit有不同的强制约束,源码 src/lib/options.ts 中的validateCrit完整呈现了规则:
- 必须被完整性保护:
crit一旦出现就必须位于受保护头部(protectedHeader),否则抛JWEInvalid("MUST be integrity protected")。 - 必须是合法数组:非空字符串数组,不得包含重复值(validateCritDuplicates,RFC 7515 §4.1.11 禁止生产者列出重复名)。
- 扩展参数必须可识别:
crit中列出的每个名字都必须被消费方识别——通过内置的JWE_RECOGNIZED(JWE 默认无内置扩展,见 src/lib/options.ts)或解密选项crit显式声明;未被识别的名字抛JOSENotSupported。 - 扩展参数必须存在:
crit列出的每个参数都必须实际出现在头部中;若该参数要求完整性保护(选项值为true),还必须位于受保护头部。
对应地,加密侧通过 EncryptOptions.crit 传入"识别清单",解密侧通过 DecryptOptions.crit 传入,其中CritOption的文档特别警告:该机制只做语法与完整性校验,不会替你处理扩展参数语义,操作成功后仍需自行按 profile 验证参数是否存在并处理。
六、JWE 专属成员之四:zip(压缩算法,唯一支持"DEF")
zip(Compression Algorithm)是本接口中运行时约束最明显的成员。接口文档与类型定义(src/types.d.ts)一致声明:唯一支持的值是"DEF"(DEFLATE),且要求运行时提供CompressionStream/DecompressionStreamAPI。
加密侧 src/lib/deflate.ts 的validateZip施加三重约束:
zip取值非"DEF"→JOSENotSupported;zip必须位于受保护头部(否则明文压缩信息可被篡改而不被发现)→JWEInvalid;- 运行时不提供
CompressionStream(如某些受限运行时)→JOSENotSupported。
实际压缩通过new CompressionStream('deflate-raw')完成(src/lib/deflate.ts)。解密侧使用DecompressionStream并受maxDecompressedLength上限约束(默认 250 KB,见 src/lib/jwe_decrypt.ts),防止压缩炸弹;设为0直接拒绝一切压缩 JWE,设为Infinity关闭限制。完整的zip实战示例可见 cookbook/jwe.mjs,其中zip: 'DEF'与alg: 'A128KW'、enc: 'A128GCM'组合使用并保留在受保护头部。
七、在加密 API 中的落地:受保护头部与三区头部模型
JWEHeaderParameters在 jose 的加密 API 中并非只有一个去处。RFC 7516 定义了三类头部,jose 分别提供设置方法:
| 头部位置 | 是否受完整性保护 | Flattened 设置方法 | 序列化字段 |
|---|---|---|---|
| Protected Header | 是(base64url 编码进protected) | setProtectedHeader() | protected |
| Shared Unprotected Header | 否 | setSharedUnprotectedHeader() | unprotected |
| Per-Recipient Unprotected Header | 否 | setUnprotectedHeader() | header |
三类头部的类型均为JWEHeaderParameters。加密流程 src/lib/jwe_encrypt.ts 会将三者浅合并成joseHeader用于算法校验,同时 checkDisjoint 强制三者的参数名两两不相交(重复参数名抛JWEInvalid)。受保护头部最终被b64u(JSON.stringify(...))序列化进 JWE 令牌(src/lib/jwe_encrypt.ts),因此只要涉及完整性保护或安全敏感的参数(alg、enc、crit、zip),都必须通过setProtectedHeader放置。
以 Compact 序列化为例(src/jwe/compact/encrypt.ts):
const jwe = await new jose.CompactEncrypt( new TextEncoder().encode('It’s a dangerous business, Frodo, going out your door.'), ) .setProtectedHeader({ alg: 'RSA-OAEP-256', enc: 'A256GCM' }) .encrypt(publicKey) console.log(jwe) // five dot-separated base64url segments注意CompactEncrypt.setProtectedHeader的参数类型是CompactJWEHeaderParameters(alg、enc必选),这正是第一节提到的必选约束的落地。而 FlattenedEncrypt 则允许同时使用setProtectedHeader、setSharedUnprotectedHeader、setUnprotectedHeader三个入口,并可搭配setAdditionalAuthenticatedData()(AAD 同样参与完整性保护,但不加密)。
八、密钥管理相关头部:apu/apv/p2c的补充
与JWEHeaderParameters紧邻的还有JWEKeyManagementHeaderParameters(src/types.d.ts),它建模 ECDH-ES 与 PBES2 特有的算法输入:
apu(Agreement PartyUInfo)/apv(Agreement PartyVInfo):参与 ECDH 的 ConcatKDF 派生;p2c(PBES2 Count):PBKDF2 迭代次数,解密时受maxPBES2Count(默认 10000)上限约束;p2s、iv、epk:已标记@deprecated,仅用于测试向量验证,不应在生产代码中使用。
这些参数通过各加密类的setKeyManagementParameters()设置(如 src/jwe/compact/encrypt.ts),由 src/lib/jwe_encrypt.ts 在头部校验完成后并入合适的 JOSE 头部,再重新执行checkDisjoint,避免生成参数与既有头部参数名冲突。
九、解密侧的对应校验:头部参数如何被消费
解密是加密的镜像流程,同样以JWEHeaderParameters为类型锚点。以 compactVerify 的姊妹函数 compactDecrypt 与 Flattened/General 解密为例,src/lib/jwe_decrypt.ts 的解密核心decryptRecipientCore按序执行:
- 头部合并:
joseHeader = { ...parsedProt, ...header, ...unprotected },并再次校验三者参数名不相交(src/lib/jwe_decrypt.ts); crit校验:validateCrit,与加密侧同一套规则;zip校验:validateZip,非法值或未受保护即拒绝;alg/enc白名单:DecryptOptions.keyManagementAlgorithms与contentEncryptionAlgorithms过滤;特别地,所有 PBES2 算法默认禁止,必须显式列入keyManagementAlgorithms才允许解密(src/types.d.ts、src/lib/jwe_decrypt.ts);- 密钥解析:
alg === 'dir'时用enc描述密钥,否则用alg描述密钥(prepareKey); - 解密与解压:按
encEntry参数解密,zip: 'DEF'时在maxDecompressedLength限制内解压。
解密结果protectedHeader字段的类型即为JWEHeaderParameters(见 FlattenedDecryptResult),CompactDecryptResult则使用必含alg/enc的CompactJWEHeaderParameters。
十、实践要点小结
alg与enc是必配组合:加密时必须同时提供(Compact 序列化中类型层面强制),二者缺一即抛JWEInvalid;alg决定密钥管理方式,enc决定 CEK 与内容加密方式。- 安全敏感参数一律放入受保护头部:
alg、enc、crit、zip均要求或被要求位于setProtectedHeader设置的头部中,zip与crit在源码层面有强制校验。 jwk只能内嵌公钥:Omit类型在编译期排除全部私钥/对称密钥成员,杜绝明文泄露。- PBES2 默认被拒:解密时需要显式
keyManagementAlgorithms白名单,且受maxPBES2Count(默认 10000)约束。 zip: 'DEF'有运行时门槛:需要CompressionStream/DecompressionStream,解密端默认 250 KB 解压上限。
通过本接口文档与 src/types.d.ts、src/lib/jwe_encrypt.ts、src/lib/jwe_decrypt.ts、src/lib/options.ts、src/lib/deflate.ts 等源码的对照阅读,你可以精确掌握 jose 中 JWE 头部的每一个可识别成员——从类型约束到运行时校验,再到加密/解密调用链中的实际落点,为构造安全、合规的 JWE 令牌提供完整依据。
- 网络安全
- 认证鉴权
- 后端
【免费下载链接】jose
JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes
相关推荐
jose 的 JWE 加密选项接口 EncryptOptions 与 crit 关键头参数处理机制
jose 的 JWE 加密选项接口 EncryptOptions 与 crit 关键头参数处理机制 本篇技术指南聚焦 jose 库中 JWE 加密操作所用的 E
网络安全认证鉴权后端jose 中 decodeProtectedHeader 与 ProtectedHeaderParameters 完全指南:解码 JWS/JWE/JWT 受保护头
jose 中 decodeProtectedHeader 与 ProtectedHeaderParameters 完全指南:解码 JWS/JWE/JWT 受保护
网络安全认证鉴权后端jose 中的 JoseHeaderParameters 接口:JWE 与 JWS 公共 JOSE Header 参数全解析
jose 中的 JoseHeaderParameters 接口:JWE 与 JWS 公共 JOSE Header 参数全解析 导读 在 jose 这个面向 No
网络安全认证鉴权后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考