jwt debugging security authentication web-development

解决 'JWT expired' 及常见的 JSON Web Token 错误

一份详尽的指南,帮助您修复 JWT 错误,如 '签名无效'、'令牌过期' 和 '格式错误'。了解如何调试应用中的身份验证问题。

解决 "JWT expired" 及常见的 JSON Web Token 错误:完整指南

JSON Web Token (JWT) 是在各方之间以 JSON 对象形式安全传输信息的行业标准。它们广泛用于现代 Web 和移动应用中的身份验证(Authentication)和授权(Authorization)。然而,由于它们是经过加密签名的,并且通常具有严格的过期规则,因此它们可能是调试时的一大难题。

在本指南中,我们将分解最常见的 JWT 错误,解释它们发生的原因,并向您展示如何修复它们。


1. 常见的 JWT 错误消息

根据您使用的库(如 Node.js 中的 jsonwebtoken),您会遇到以下常见的错误名称:

  • TokenExpiredError: 令牌有效但已超过其过期时间。
  • JsonWebTokenError: invalid signature: 令牌的签名与提供的密钥/私钥不匹配。
  • JsonWebTokenError: jwt malformed: 提供的字符串不是有效的 JWT 结构。
  • JsonWebTokenError: jwt signature is required: 提供的令牌缺少签名部分。
  • JsonWebTokenError: jwt invalid audience: 令牌中的 aud(受众)声明与预期值不匹配。

2. 核心原因与解决方案

2.1 "TokenExpiredError" (JWT expired)

每个安全的 JWT 都应该包含 exp(过期时间)声明。一旦当前时间超过此值,令牌就不再有效。

症状: 用户突然被登出,或者 API 请求开始返回 401 Unauthorized 错误,并提示 jwt expired

解决方案:

  1. 刷新令牌 (Refresh Tokens): 实现“刷新令牌”策略,这样用户在访问令牌过期时无需手动重新登录。
  2. 时钟同步: 确保服务器时钟使用 NTP 同步。即使是几秒钟的偏差也可能导致问题。
  3. 检查 iatnbf: 确保“签发时间”(iat) 和“生效时间”(nbf) 声明也是正确的。

2.2 "invalid signature" (签名无效)

一个 JWT 由三部分组成:头部 (Header)、负载 (Payload) 和签名 (Signature)。签名是通过使用密钥对头部和负载进行哈希运算创建的。如果负载中哪怕有一个字符发生变化,或者使用了错误的密钥,签名就会失效。

原因:

  • 使用了错误的 secretpublic key 来验证令牌。
  • 签名算法(如 HS256)与验证算法(如 RS256)不匹配。
  • 令牌在传输过程中被篡改或损坏。

解决方案:

  • 仔细检查用于密钥的环境变量。
  • 验证 JWT 头部中的 alg 是否与您用于验证的算法匹配。

2.3 "jwt malformed" 或 "jwt decode failed" (格式错误)

一个有效的 JWT 必须有三个部分,由点 (.) 分隔(即 header.payload.signature)。如果缺少任何部分,或者字符串不是有效的 Base64URL,它就被认为是格式错误的。

原因:

  • 直接将带有 "Bearer " 前缀的字符串传递给了库(例如 atob("Bearer <token>"))。
  • 复制粘贴时不完整。
  • 令牌字符串中包含多余的空格或隐藏字符。

解决方案: 在将令牌传递给解码器之前,确保已经去掉了 Bearer 前缀。

const token = authHeader.split(' ')[1]; // 从 "Bearer <token>" 中提取令牌

2.4 "jwt invalid audience" 或 "jwt invalid issuer" (受众或签发者无效)

当负载中的 aud(受众)或 iss(签发者)声明与服务器预期的值不匹配时,会发生这些错误。

解决方案: 确保身份验证服务器(如 Auth0、Firebase 或您自己的服务器)上的配置与应用代码中的验证选项相匹配。


3. 进阶故障排查

3.1 检查负载

如果您遇到签名错误,第一步是检查负载内容,看看它是否包含您预期的数据。您不需要密钥就可以解码并读取负载(因为它是 Base64 编码的)。

3.2 算法混淆攻击 (Algorithm Confusion Attacks)

确保您的库配置为仅允许您预期的特定算法。一些旧版本的库容易受到攻击,攻击者可以将头部更改为 alg: none 来绕过安全检查。现代库大多已修复此问题,但务必在代码中明确定义允许的算法。

jwt.verify(token, secret, { algorithms: ['HS256'] });

4. 预防措施与最佳实践

  1. 短期访问令牌: 保持访问令牌的生命周期较短(如 15 分钟),并使用刷新令牌处理较长的会话。
  2. 安全存储密钥: 永远不要硬编码您的 JWT 密钥。使用环境变量并定期更换。
  3. 验证每个请求: 永远不要在没有在服务器端验证签名的情况下信任 JWT。
  4. 使用 HTTPS: 始终通过 HTTPS 传输令牌,以防止中间人攻击 (MITM)。

5. 常见问题 FAQ

Q: 我可以在没有密钥的情况下读取 JWT 内部的数据吗?

: 可以。 头部和负载只是 Base64URL 编码的,并未加密。任何拥有令牌的人都可以读取其中的数据。切勿在 JWT 负载中放入密码或信用卡号等敏感信息。

Q: HS256 和 RS256 有什么区别?

: HS256 使用单个密钥进行签名和验证(对称加密)。RS256 使用私钥签名并使用公钥验证(非对称加密),这对于分布式系统更安全。

Q: 如何在前端处理 "jwt expired" 错误?

: 在 API 拦截器中捕获 401 错误。如果错误是 "jwt expired",尝试调用您的“刷新令牌”接口。如果失败,则重定向用户到登录页面。


6. 快速检查工具

处理特定的令牌时遇到困难?使用我们的 JWT 解码与调试工具。它允许您:

  • 瞬间解码任何 JWT,查看其头部和负载。
  • 检查过期状态以及 iatexpnbf 等声明。
  • 识别格式错误的令牌和编码问题。
  • 验证签名(如果您在本地提供密钥)。

相关错误

  • 解决 'Unexpected token in JSON' 错误
  • 如何修复 'invalid base64 string' 错误
  • 解决 'invalid regular expression' 错误