4、令牌过期机制:exp字段校验逻辑、服务端时钟偏差容忍度、过期后令牌失效行为

JWT 的 exp(Expiration Time)声明是令牌生命周期的核心防线。后端在验证令牌时,必须严格校验该字段,同时处理分布式系统中不可避免的时钟偏差问题。本章深入剖析 exp 的校验逻辑、时钟偏差容忍度的配置策略,以及令牌过期后的失效行为。

4.1 exp 字段校验逻辑

exp 是一个 NumericDate 类型的声明,表示令牌的过期时间戳(自 Unix 纪元以来的秒数)。后端验证流程如下:

  1. 提取 exp 值:从 JWT Payload 中解析 exp 字段,若缺失则视为无效令牌(根据安全策略可拒绝或放行,但生产环境建议拒绝)。
  2. 获取当前时间:使用服务端系统时间(通常为 UTC),避免依赖客户端时间。
  3. 比较时间戳:若当前时间 ≥ exp,则令牌过期,拒绝请求并返回 401 Unauthorized。
  4. 考虑时钟偏差:在比较时引入一个可配置的容忍窗口(见 4.2 节)。
关键校验规则: 即使令牌签名正确、其他声明有效,只要 exp 过期,后端必须立即拒绝。这是 JWT 安全性的基石。

4.2 服务端时钟偏差容忍度

在分布式系统中,不同服务器的系统时钟可能存在秒级甚至毫秒级差异。直接使用严格的 当前时间 ≥ exp 比较,可能导致合法令牌因时钟不同步而被误判为过期。因此,主流 JWT 库引入了 时钟偏差容忍度(Clock Skew Tolerance)。

参数 说明 推荐值 风险
clockSkew 允许的时钟偏差时间窗口(秒) 30 ~ 60 秒 过大增加令牌重用窗口
leeway 与 clockSkew 同义,部分库使用此名称 30 秒 同上
maxClockSkew 某些库支持的最大偏差限制 300 秒(5 分钟) 仅用于极端场景,需配合 NTP 同步

校验公式(含时钟偏差):

// 伪代码示例
const currentTime = Date.now() / 1000; // 当前 UTC 时间戳(秒)
const exp = decodedToken.payload.exp;
const clockSkew = 30; // 容忍 30 秒偏差

if (currentTime + clockSkew >= exp) {
    // 令牌过期,拒绝
    throw new Error('Token expired');
}
// 令牌有效
最佳实践: 时钟偏差容忍度应设置为 30~60 秒。过大的容忍度会延长令牌的有效窗口,增加被重放攻击的风险。同时,确保所有服务器使用 NTP 服务同步时钟,从根本上减少偏差。

4.3 过期后令牌失效行为

令牌过期后,后端的行为直接影响用户体验和系统安全。以下是标准失效行为及处理策略:

  • 立即拒绝:后端在验证时发现 exp 过期,直接返回 401 Unauthorized,错误码通常为 TOKEN_EXPIRED 或 JWT_EXPIRED。
  • 不提供降级访问:即使令牌过期,后端也不应返回部分数据或允许受限操作。过期令牌视为完全无效。
  • 客户端刷新流程:客户端收到 401 后,应使用 Refresh Token 获取新的 Access Token(不在本章范围,但需知晓)。
  • 黑名单机制(可选):对于主动注销或提前失效的令牌,即使 exp 未过期,后端也应通过黑名单拒绝。但过期令牌本身无需加入黑名单,因为其已自然失效。
安全警告: 不要为了用户体验而允许过期令牌继续访问。任何绕过 exp 校验的行为都会破坏 JWT 的安全模型,可能导致未授权访问。

4.4 令牌过期校验流程图

下图展示了后端对 exp 字段的完整校验流程,包括时钟偏差容忍度的处理:

JWT exp 字段校验与时钟偏差容忍度流程图 JWT exp 字段校验与时钟偏差容忍度流程图 收到 JWT 请求 解析 Payload,提取 exp exp 是否存在? 拒绝(无效令牌) 获取当前时间 加入时钟偏差容忍度 当前时间+偏差 ≥ exp? 返回 401 TOKEN_EXPIRED 令牌有效,放行 说明:时钟偏差容忍度通常为 30~60 秒,用于补偿分布式系统时钟不同步问题。

4.5 常见错误码与断言

在故障排查中,后端返回的错误码是定位问题的关键。以下是 exp 相关常见错误码及断言建议:

错误码 含义 断言检查点
TOKEN_EXPIRED 令牌已过期 检查 exp 时间戳与当前服务器时间;确认时钟偏差配置
JWT_EXPIRED JWT 过期(同义) 同上;检查 JWT 库版本是否支持时钟偏差
INVALID_TOKEN 令牌无效(可能包含过期) 需进一步解析错误详情;确认是否因 exp 缺失导致
TOKEN_MALFORMED 令牌格式错误 检查 exp 是否为 NumericDate 类型;确认 Payload 结构
故障排查断言: 当收到 TOKEN_EXPIRED 时,首先对比令牌中的 exp 值与服务器当前 UTC 时间。若差值在 30 秒以内,则可能是时钟偏差问题;若差值较大,则令牌确实已过期,需客户端刷新。

4.6 过期后令牌失效行为示意图

下图展示了令牌过期后,后端与客户端之间的交互行为:

令牌过期后失效行为交互图 令牌过期后失效行为交互图 客户端 后端服务 携带过期 JWT 请求 校验 exp 过期 返回 401 TOKEN_EXPIRED 401 错误响应 客户端收到 401 使用 Refresh Token 获取新令牌 说明:过期令牌不会被后端缓存或加入黑名单,直接拒绝即可。

4.7 总结与最佳实践

  • 严格校验 exp:即使令牌签名正确,exp 过期也必须拒绝。
  • 合理配置时钟偏差:30~60 秒是安全且实用的范围。
  • 统一时间源:所有服务端使用 NTP 同步时钟,减少偏差。
  • 错误码标准化:使用 TOKEN_EXPIRED 等明确错误码,便于客户端和日志排查。
  • 不信任客户端时间:始终以服务端时间为准。