ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

jose 中 GeneralVerifyResult 接口详解:General JWS 验证结果的结构、语义与实战应用

jose 中 GeneralVerifyResult 接口详解:General JWS 验证结果的结构、语义与实战应用 网络安全认证鉴权后端【免费下载链接】joseJWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes项目地址https://gitcode.com/gh_mirrors/jo/jose点击查看免费下载导读GeneralVerifyResult是 jose 库中generalVerify()函数在成功验证 General JWS JSON 序列化签名后的返回结果类型。它告诉调用方签名验证通过后哪些数据是可信的——即被验证过的 JWS Payload、受保护的头部Protected Header与未受保护的头部Unprotected Header。本文以该接口为骨架结合 generalVerify() 函数文档、底层实现 src/jws/general/verify.ts 与相关测试讲清结果对象的每个字段、它在多签名multi-signature场景下的语义边界以及如何在 Node.js、浏览器、Deno、Bun、Cloudflare Workers 等 Web-interoperable 运行时中正确使用。GeneralVerifyResult 接口定义根据 docs/types/interfaces/GeneralVerifyResult.md接口共定义三个属性其中两个为可选属性类型必选含义payloadUint8Array是JWS Payload已解码的原始字节protectedHeader?JWSHeaderParameters否JWS Protected Header受保护头部unprotectedHeader?JWSHeaderParameters否JWS Unprotected Header未受保护头部它和 FlattenedVerifyResult 拥有完全相同的结果形状——正如底层实现 src/lib/jws_verify.ts 中verifyResult函数的注释所写Flattened and General results have the same shape, so they are assembled in one placeFlattened 与 General 结果形状相同因此在同一处组装。这意味着从两种序列化语法验证同一批数据时消费结果对象的代码可以完全复用。结果中的三个字段payload验证后的可信载荷。类型固定为Uint8Array是 JWS 中 base64url 编码 payload 解码后的原始字节。文档示例中调用方使用new TextDecoder().decode(payload)即可还原为可读字符串。之所以返回Uint8Array而非字符串是为了不丢失二进制载荷的保真度也便于与 RFC 7515 定义的payload 即字节序列语义对齐。protectedHeader?被签名覆盖保护的头部。只有当输入 JWS 的签名条目signature entry中存在protected成员时结果才会包含该字段。它是 JWS 签名输入的组成部分因此任何篡改都会导致签名验证失败——这就是受保护的含义。unprotectedHeader?未被签名覆盖的头部。只有当输入 JWS 的签名条目中存在header成员时才会出现。按照 RFC 7515 的规则未受保护的头部同样由签名者声称但未参与签名输入的计算因此它不能被签名完整性所保证只能作为签名者声明来读取。结果中不会出现的内容GeneralVerifyResult不包含signature原始串、key等信息。唯一的例外是当使用动态密钥解析函数getKey形式调用generalVerify时返回值会与 ResolvedKey 交叉额外携带一个key属性用于暴露本次实际用于验证的密钥。从源码看这是通过verifyResult中resolvedKey分支src/lib/jws_verify.ts实现的仅当密钥由解析函数产出时才将key并入结果。GeneralVerifyResult 的诞生场景generalVerify() 函数结果对象由generalVerify()函数产生。该函数从 jose 主入口jose以及子路径导出jose/jws/general/verify两个位置导出见 src/jws/general/verify.ts其完整调用签名如下// 形式一直接传入密钥 generalVerify(jws: GeneralJWSInput, key: KeyInput, options?: VerifyOptions) : PromiseGeneralVerifyResult // 形式二传入动态密钥解析函数结果额外携带解析出的 key generalVerifyKeyType extends CryptoKey | Uint8Array( jws: GeneralJWSInput, getKey: GeneralVerifyGetKeyKeyType, options?: VerifyOptions, ): PromiseGeneralVerifyResult ResolvedKeyKeyType // 形式三兼容重载key 可能是密钥也可能是解析函数 generalVerify(jws: GeneralJWSInput, key: KeyInput | GeneralVerifyGetKey, options?: VerifyOptions) : PromiseGeneralVerifyResult PartialResolvedKey输入结构GeneralJWSInputjws参数类型为GeneralJWSInput它是 General JSON Serialization 的最小输入视图包含两个必选成员payloadstring | Uint8Array。正常情况下是BASE64URL(JWS Payload)字符串当使用 RFC 7797 的 JWS Unencoded Payload Optionb64: false时可以传入原始Uint8Array。若 payload 为Uint8Array则用于**分离式签名detached signature**校验——测试文件 test/jws/general.test.ts 中有generalVerify({ payload: detached, signatures }, resolve)的用例。signaturesOmitFlattenedJWSInput, payload[]即一个 JSON 对象数组每个对象代表对同一 payload 的一个签名或 MAC。每个条目包含protected可选、header可选、signature必选完整定义见 FlattenedJWSInput。结果对象的核心语义只信任第一个验证成功的条目GeneralVerifyResult的语义有两个关键点来自 generalVerify.md 的 NOTE 以及源码实现返回的是第一个成功验证的签名条目的结果。源码src/jws/general/verify.ts遍历signatures数组中的每个候选条目逐个尝试verifySignature只要有一个验证成功就立即返回该条目的payload、protectedHeader、unprotectedHeader。其他签名条目的头部只用于一致性检查不进入结果。除第一个成功条目的头部外其余条目的头部会被检查是否与 Unencoded Payload OptionRFC 7797b64的使用保持一致——若各签名条目对b64的使用互相矛盾则直接抛出JWSInvalid源码中modes位掩码累加后等于 3 即触发inconsistent use of JWS Unencoded Payload (RFC7797)见 src/jws/general/verify.ts。安全要点General JWS 的接收方只应依赖返回结果中经过验证的数据。结果之外的任何签名条目头部包括未成功的条目、被跳过的条目都不得被当作可信输入处理因为它们没有通过GeneralVerifyResult的已验证边界。典型用法与实战示例用法一直接传入公钥单密钥场景来自 generalVerify.md 的官方示例const jws { payload: SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4, signatures: [ { signature: FVVOXwj6kD3DqdfD9yYqfT2W9jv-Nop4kOehp_DeDGNB5dQNSPRvntBY6xH3uxlCxE8na9d_kyhYOcanpDJ0EA, protected: eyJhbGciOiJFUzI1NiJ9, }, ], } const { payload, protectedHeader } await jose.generalVerify(jws, publicKey) console.log(protectedHeader) // { alg: ES256 } console.log(new TextDecoder().decode(payload)) // 解码后的原始载荷文本由于该 JWS 条目只有protected而没有header此时unprotectedHeader在结果中不存在undefined。protectedHeader来自对eyJhbGciOiJFUzI1NiJ9的 base64url 解码即{ alg: ES256 }。注意验证发生在解码之前——调用方读到的头部信息是在签名验证成功后由 jose 返回的因此可信任。用法二动态密钥解析多密钥 / JWKS 场景当系统中有多个密钥、需要通过kid等头部字段挑选密钥时使用第二个重载import { createRemoteJWKSet, generalVerify } from jose const JWKS createRemoteJWKSet(new URL(https://example.com/.well-known/jwks.json)) const { payload, protectedHeader, key } await generalVerify(jws, JWKS) // ^ 返回 GeneralVerifyResult ResolvedKey // 因为 createRemoteJWKSet 是密钥解析函数结果多出 key 字段这里的结果类型为GeneralVerifyResult ResolvedKeyKeyType。由于 createRemoteJWKSet、createLocalJWKSet 与 EmbeddedJWK 都声明只解析出CryptoKeyResolvedKey.key的类型在调用点会被自动收窄为CryptoKey无需手动标注泛型见 ResolvedKey 文档 的类型参数说明。密钥解析函数GeneralVerifyGetKey的签名是(protectedHeader: JWSHeaderParameters, token: FlattenedJWSInput) JWK | KeyObject | KeyType | Promise...。注意一个安全前提在解析函数被调用的时刻token 的任何组件都尚未被验证源码注释 No token components have been verified at the time of this function call。因此解析函数只能把头部信息当作线索如用kid查表找到合适的密钥后真实性仍由密码学验证来保证。若找不到合适密钥应直接抛错而非返回错误密钥让验证静默失败。options控制验证行为与结果边界generalVerify的第三个参数options类型为 VerifyOptions它不改变返回结果的形状但直接影响什么样的 JWS 能成功返回GeneralVerifyResultalgorithmsalgorithms?: string[]—— 允许的 JWSalg头部取值白名单。默认情况下凡是与所传密钥/密钥类型匹配的alg都被允许传入该数组后只有名单内的算法才会被接受。底层实现中prepareVerify会调用validateAlgorithms生成一个Setstringsrc/lib/jws_verify.ts随后在 src/lib/jws_verify.ts 检查alg是否在集合内不在则抛出JOSEAlgNotAllowed。重要限制未受保护的 JWT{ alg: none }永远不会被此 API 接受即使把它加进algorithms也不会生效。critcrit?: { [propName: string]: boolean }—— 声明哪些critCritical头部参数是已被识别的。true表示该参数必须受完整性保护即出现在受保护头部中false表示其完整性保护与否无关紧要。b64扩展头部参数始终被内置识别并正确处理无需在此声明。使用警告文档中的[!WARNING]crit选项只检查头部参数提供时是否语法正确、且可选地是否受完整性保护它不会替你处理该参数的含义也不会在该参数缺失时拒绝操作。真正的业务校验必须在generalVerify成功后根据你的 profile 规范自行检查该参数是否出现并处理它。错误路径什么情况下不会返回 GeneralVerifyResult依据源码与测试以下情况generalVerify会拒绝返回结果抛出异常调用方应在使用时注意jws不是对象、signatures缺失或类型错误、签名条目中存在非对象成员 →JWSInvalid如General JWS must be an object、JWS Signatures missing or incorrect type见 src/jws/general/verify.ts。所有签名条目都验证失败、或选项解析出错 →JWSSignatureVerificationFailed。值得注意的实现细节源码刻意将畸形 token与签名不是调用方期望的统一报告为JWSSignatureVerificationFailed以保持不可区分性src/jws/general/verify.ts 中注释Reporting the real fault here would distinguish a malformed token from a signature that is simply not the callers. Stay indistinguishable.避免向攻击者泄露额外信息。各签名条目对b64RFC 7797 Unencoded Payload的使用不一致 →JWSInvalid。受保护头部与未受保护头部存在同名参数RFC 7515 要求两者名称必须不相交→JWSInvalidsrc/lib/jws_verify.ts。头部缺少alg、alg不在algorithms白名单内 → 分别抛出JWSInvalid与JOSEAlgNotAllowed。测试文件 test/jws/general.test.ts 覆盖了上述大部分路径例如对null输入、{ signatures: null }、{ signatures: [null] }均断言抛出可作为行为契约的参考。与其他验证结果类型的对比GeneralVerifyResult与 jose 中的其他验证结果接口共享payload 可选头部的结构但适用场景不同CompactVerifyResultCompact 序列化单签名、点分隔三段式字符串的验证结果。Compact 形式不存在unprotectedHeader只有受保护头部。FlattenedVerifyResultFlattened 序列化单个签名、JSON 对象形式的验证结果字段与GeneralVerifyResult完全一致。GeneralVerifyResultGeneral 序列化signatures数组、多签名的验证结果适用于多签名者或多算法并存的场景。选择依据很简单如果 JWS 可能包含多个签名条目例如需要满足两名管理员各自签名的审批流程用generalVerify并消费GeneralVerifyResult单个签名则优先使用 Compact 或 Flattened 验证函数以获得更严格的输入约束。小结GeneralVerifyResult是 jose 多签名 JWS 验证流程的可信数据出口它把验证过的 payload、受保护的头部、未受保护的头部封装成固定结构并严格限定——返回内容只来自第一个验证成功的签名条目其余条目仅用于一致性检查。使用时的三条底线只信任结果对象内的数据在动态密钥解析场景下把解析函数仅当作密钥查找手段真实安全性交给密码学验证crit/algorithms选项负责约束能进入验证的输入而业务语义校验需在验证成功后自行完成。结合 通用验证源码、共享验证逻辑 与 测试用例你可以完整地追踪一个 General JWS 从输入到GeneralVerifyResult的每一步从而在 Node.js、浏览器、Deno、Bun、Cloudflare Workers 等任何支持的运行时中写出安全且可审计的验证代码。赞分享网络安全认证鉴权后端【免费下载链接】joseJWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes项目地址https://gitcode.com/gh_mirrors/jo/jose点击查看免费下载相关推荐jose 中的 GeneralDecryptResult 接口General JWE 解密结果结构与实战解析jose 中的 GeneralDecryptResult 接口General JWE 解密结果结构与实战解析 GeneralDecryptResult 是 j网络安全认证鉴权后端jose 中 FlattenedJWSInput 接口详解Flattened JWS 验证输入的结构、规则与 detached 签名实践jose 中 FlattenedJWSInput 接口详解Flattened JWS 验证输入的结构、规则与 detached 签名实践 导读 Flatten网络安全认证鉴权后端jose 中 FlattenedVerifyResult深入理解 Flattened JWS 验证结果对象的结构与使用jose 中 FlattenedVerifyResult深入理解 Flattened JWS 验证结果对象的结构与使用 导读 FlattenedVerifyR网络安全认证鉴权后端上一篇Zoom Phone 集成 5 分钟预检 Runbook从 OAuth 到事件关联的快速排障清单下一篇Rowboat 沙盒开发实例完全指南基于 dev:sandbox 的多实例并行开发与调试创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表