JWT 令牌结构解析:Header、Payload、Signature 与签名算法

JSON Web Token(JWT)是 OAuth 2.0 授权流程中最常用的令牌格式。一个完整的 JWT 由三个 Base64URL 编码的部分组成,以点号(.)分隔:Header.Payload.Signature。理解这三部分的结构与签名机制,是保障支付订单安全接入的基础。

JWT 三段式结构全景图 JWT 令牌三段式结构 Header(头部) 算法类型 令牌类型 {"alg":"RS256", "typ":"JWT"} Base64URL 编码 Payload(载荷) 声明(Claims) sub, iss, exp, iat order_id, amount {"sub":"user123", "order":"ORD001"} Base64URL 编码 Signature(签名) 防篡改验证 HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) Base64URL 编码 最终令牌格式:eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIn0.abcdefg123456

2.1 Header(头部)

Header 是 JWT 的第一段,通常包含两个字段:令牌类型(typ)和签名算法(alg)。它使用 Base64URL 编码,不加密,任何人都可以解码读取。

字段含义示例值
alg签名算法,标识使用哪种算法生成签名"RS256" 或 "HS256"
typ令牌类型,固定为 "JWT""JWT"
kid(可选)密钥标识,用于多密钥场景选择对应密钥"key-rsa-2024"
支付安全提示: 在支付订单令牌中,Header 的 alg 字段必须显式指定,且服务端应校验该字段是否与预期算法一致,防止算法混淆攻击(Algorithm Confusion Attack)。

2.2 Payload(载荷)

Payload 是 JWT 的第二段,包含实际传递的声明(Claims)。声明分为三类:注册声明、公共声明、私有声明。在支付订单场景中,Payload 承载订单核心数据。

声明类型常见字段说明支付订单示例
注册声明sub, iss, exp, iat, jti标准预定义字段,建议使用"sub":"user_1001", "exp":1735689600
公共声明自定义字段,需在 IANA 注册或使用 URI 避免冲突可扩展性高"https://pay.example.com/role":"merchant"
私有声明双方约定的自定义字段灵活但需注意命名冲突"order_id":"ORD20241201", "amount":2999
安全红线: Payload 仅 Base64URL 编码,不是加密。绝不能在 Payload 中存放密码、信用卡号、CVV 等敏感信息。如需保护敏感数据,应使用 JWE(JSON Web Encryption)或额外加密层。

2.3 Signature(签名)

Signature 是 JWT 的第三段,用于验证令牌的完整性和真实性。签名由 Header 中指定的算法,对 base64UrlEncode(header) + "." + base64UrlEncode(payload) 进行签名计算生成。

// 签名生成伪代码
signature = sign(
    base64UrlEncode(header) + "." + base64UrlEncode(payload),
    secretOrPrivateKey,
    { algorithm: header.alg }
);

服务端收到 JWT 后,使用相同的密钥和算法重新计算签名,并与令牌携带的签名比对。若不一致,则拒绝请求。

2.4 RS256 与 HS256 签名算法对比

RS256(RSA Signature with SHA-256)和 HS256(HMAC with SHA-256)是 JWT 最常用的两种签名算法。它们在密钥管理、安全模型和适用场景上有本质区别。

RS256 与 HS256 签名算法对比 RS256 vs HS256 签名算法对比 RS256(非对称) 私钥签名 · 公钥验签 🔑 私钥:仅授权服务持有 🔓 公钥:可分发至任意客户端 ✅ 适合微服务间令牌验证 ✅ 支持第三方安全验签 ⚠️ 性能略低于对称算法 🔒 密钥泄露风险低 推荐用于支付订单令牌 HS256(对称) 同一密钥签名与验签 🔑 单一密钥:双方共享 ✅ 计算速度快,延迟低 ✅ 实现简单,无需证书管理 ⚠️ 密钥分发困难 ⚠️ 任何持有密钥者均可签发 🔒 密钥泄露风险高 适用于内部信任环境
对比维度RS256(非对称)HS256(对称)
密钥类型私钥 + 公钥(密钥对)单一共享密钥
签名方仅持有私钥的授权服务器任何持有共享密钥的实体
验签方任何持有公钥的客户端或服务同样持有共享密钥的实体
密钥分发公钥可公开,私钥严格保护密钥需安全通道传输给所有验签方
性能签名较慢,验签较快签名和验签均快
安全风险私钥泄露则整个系统受影响;公钥泄露无影响共享密钥泄露,攻击者可伪造任意令牌
适用场景微服务间令牌验证、第三方接入、支付订单令牌单一服务内部、高吞吐低延迟场景
算法混淆防护天然抗算法混淆(公钥无法用于 HMAC 验签)需额外校验 alg 字段,防止攻击者将 RS256 改为 HS256
支付订单接入建议: 在支付网关与订单服务之间,推荐使用 RS256。原因:支付场景涉及多方(商户、网关、银行),公钥可安全分发给所有验签方,私钥仅由授权服务器持有,即使某个下游服务被攻破,攻击者也无法伪造令牌。HS256 更适合内部高并发、完全信任的闭环系统。

2.5 算法混淆攻击与防护

算法混淆攻击(Algorithm Confusion Attack)是 JWT 安全中必须防范的经典攻击。攻击者将 JWT Header 中的 alg 从 RS256 改为 HS256,然后使用公钥(通常是公开的)作为 HMAC 的密钥重新签名。如果服务端未校验 alg 字段,就会使用公钥作为 HS256 的密钥进行验签,导致攻击成功。

// 攻击示例:将 RS256 令牌改为 HS256
// 原始令牌(RS256 签名)
// header: {"alg":"RS256","typ":"JWT"}
// payload: {"sub":"user","role":"admin"}
// 攻击者修改为:
// header: {"alg":"HS256","typ":"JWT"}
// 使用公钥(公开)作为 HMAC 密钥重新签名
// 服务端若未校验 alg,使用公钥验签 → 通过
防护措施:
  • 服务端必须显式校验 alg 字段,拒绝非预期的算法值。
  • 使用 RS256 时,验签逻辑应只接受 RS256,拒绝 HS256。
  • JWT 库应配置白名单算法列表,例如:jwt.verify(token, publicKey, { algorithms: ['RS256'] })。
  • 避免使用 none 算法,生产环境应禁用无签名令牌。

2.6 支付订单 JWT 最佳实践

  • 使用 RS256:支付订单令牌涉及资金安全,非对称算法提供更强的密钥隔离。
  • 设置短过期时间:exp 建议设置为 15-30 分钟,支付流程完成后立即失效。
  • 包含 jti 声明:jti(JWT ID)用于防重放攻击,每次支付请求生成唯一 ID,服务端记录已使用的 jti。
  • 最小化 Payload:只存放订单 ID、用户标识、金额等必要字段,避免冗余数据。
  • 签名算法白名单:服务端验签时强制指定算法,拒绝动态从 Header 读取算法。
// 支付订单 JWT 示例(Payload 部分)
{
  "sub": "user_1001",
  "jti": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "order_id": "ORD20241201001",
  "amount": 2999,
  "currency": "CNY",
  "iss": "https://pay.example.com",
  "iat": 1735689600,
  "exp": 1735691400
}
核心要点回顾: JWT 的三段结构(Header、Payload、Signature)各自承担不同职责。Header 声明算法,Payload 承载数据,Signature 保证完整性。RS256 与 HS256 的选择直接影响支付系统的安全边界——在多方参与的支付场景中,RS256 的非对称特性是更安全的选择。算法混淆攻击是必须防范的常见威胁,通过算法白名单校验即可有效防御。