3. JWT 安全风险:无签名攻击、密钥泄露、算法混淆攻击(alg=none)、重放攻击

JSON Web Token(JWT)作为无状态认证的主流方案,其安全性高度依赖于实现过程的严谨性。在实际生产环境中,由于开发人员对 JWT 规范理解不深、库使用不当或配置疏忽,常导致严重的安全漏洞。本章将深入剖析四种最具破坏力的 JWT 攻击向量,并给出对应的防御策略。

3.1 攻击向量全景图

下表总结了四种核心攻击类型的攻击原理、利用条件与危害等级,帮助安全工程师建立全局风险视图。

攻击类型 攻击原理 利用条件 危害等级
无签名攻击 将 JWT 头部 alg 字段设为 none,绕过签名验证 服务端未强制校验签名算法,或允许 none 算法 严重
密钥泄露 攻击者获取签名密钥后,可伪造任意合法 Token 密钥硬编码、泄露到版本控制、日志或配置中心 灾难性
算法混淆攻击 利用服务端对非对称/对称算法验证逻辑的缺陷,使用公钥作为 HMAC 密钥签名 服务端未校验算法类型与密钥的匹配关系 严重
重放攻击 截获合法 Token 后重复使用,绕过身份验证 Token 缺乏一次性校验或时间窗口约束 中-高

3.2 无签名攻击(alg=none)

JWT 规范(RFC 7519)定义了一种特殊算法 none,用于在已通过其他通道(如 TLS)保证完整性的场景下跳过签名。然而,许多服务端实现错误地接受了 alg: none 的 Token,导致攻击者可以构造任意载荷而无需任何密钥。

攻击示例:攻击者将原始 JWT 头部从 {"alg":"HS256"} 修改为 {"alg":"none"},并将载荷中的 "role":"user" 改为 "role":"admin",然后移除签名部分。若服务端未做严格校验,将直接信任该 Token。
// 攻击者构造的恶意 JWT
// Header: {"alg":"none"}
// Payload: {"sub":"1234567890","name":"John Doe","role":"admin","iat":1516239022}
// Signature: (空)

// 最终 Token 字符串:
eyJhbGciOiJub25lIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDIyfQ.

3.3 密钥泄露

密钥是 JWT 安全体系的基石。一旦密钥泄露,攻击者便获得了与合法服务端同等的签名能力,可以伪造任意身份、权限的 Token。常见的泄露途径包括:

  • 硬编码到源代码:密钥直接写在代码中,随版本控制库(如 Git)泄露。
  • 配置文件泄露:密钥存储在未加密的配置文件中,被错误地推送到公共仓库。
  • 日志输出:调试日志或错误堆栈中打印了密钥信息。
  • 第三方依赖:密钥通过不安全的渠道传递给 CI/CD 或微服务。
防御要点:密钥必须使用专门的密钥管理服务(如 AWS KMS、HashiCorp Vault)存储,并定期轮换。生产环境与开发环境使用不同的密钥,且密钥长度应满足算法最低要求(如 HMAC-SHA256 至少 256 位)。

3.4 算法混淆攻击

算法混淆攻击(Algorithm Confusion Attack)是 JWT 实现中最隐蔽的漏洞之一。当服务端使用 RSA 等非对称算法验证 Token 时,攻击者可以获取公钥,然后将头部算法改为 HMAC(如 HS256),并使用公钥作为 HMAC 密钥对 Token 进行签名。若服务端未校验算法类型与密钥的匹配关系,将使用公钥作为 HMAC 密钥进行验证,从而通过校验。

// 攻击步骤:
// 1. 获取服务端公钥(通常通过 /.well-known/jwks.json 端点)
// 2. 构造 JWT 头部:{"alg":"HS256"}
// 3. 使用公钥字符串作为 HMAC 密钥对载荷进行签名
// 4. 服务端使用公钥作为 HMAC 密钥验证签名,通过校验

// 防御:服务端必须明确指定期望的算法,并拒绝算法类型与密钥类型不匹配的 Token
核心防御原则:在验证 JWT 时,必须显式指定允许的算法列表,并强制校验 Token 头部中的 alg 字段是否在允许列表中。切勿依赖 JWT 库的自动算法检测功能。

3.5 重放攻击

即使 JWT 签名完整且算法正确,攻击者仍可通过网络嗅探或中间人攻击截获合法 Token,并在有效期内重复使用。重放攻击的典型场景包括:用户登录后 Token 被截获,攻击者利用该 Token 执行敏感操作(如转账、修改密码)。

防御重放攻击的常用策略包括:

  • 短有效期(exp):将 Token 的过期时间设置为较短窗口(如 15 分钟),降低重放窗口。
  • 一次性 Token(jti):在 JWT 载荷中包含唯一标识符 jti,服务端维护已使用 jti 的黑名单。
  • 时间戳校验(iat/nbf):结合 iat(签发时间)和 nbf(生效时间)进行时间窗口校验。
  • 请求绑定:将 Token 与特定请求参数(如 IP、User-Agent、nonce)绑定,增加重放难度。

3.6 攻击流程与防御闭环

下图展示了四种攻击向量的攻击路径以及对应的防御闭环节点,帮助理解从攻击到防御的完整链路。

JWT 攻击向量与防御闭环 无签名攻击 密钥泄露 算法混淆攻击 重放攻击 JWT 验证服务 密钥管理 算法验证逻辑 Token 状态管理 强制签名校验 密钥管理服务 算法白名单 jti + 短过期 防御闭环要点: 1. 验证时显式指定允许算法,拒绝 alg=none 和算法类型不匹配的 Token。 2. 密钥使用专用管理服务存储,定期轮换,禁止硬编码。 3. 结合 jti 黑名单与短过期时间,防止重放攻击。

3.7 综合防御清单

针对上述四种攻击,以下清单总结了每个环节必须落实的防御措施:

攻击类型 防御措施 实现优先级
无签名攻击 验证时强制要求签名存在,拒绝 alg: none;使用白名单算法列表 P0(立即修复)
密钥泄露 使用密钥管理服务(KMS/Vault);禁止硬编码;定期轮换;最小权限原则 P0(立即修复)
算法混淆攻击 验证时校验算法类型与密钥类型匹配;显式指定算法而非自动检测 P0(立即修复)
重放攻击 短过期时间(exp);jti 唯一标识 + 已使用列表;请求绑定(IP/User-Agent) P1(高优先级)
安全架构师提示:JWT 安全不仅仅是签名算法的问题。在微服务架构中,每个服务都应独立验证 Token 的签名和算法,而不是信任上游服务传递的“已验证”标记。同时,建议在网关层统一完成 JWT 验证,并将验证结果(如用户 ID、角色)以内部请求头形式传递给下游服务,减少重复验签开销。