JWT 标准本身不支持主动吊销已发令牌,紧急情况下必须通过轮换签名密钥(Key Rotation)使旧令牌失效,或引入服务端黑名单机制拦截请求。
先说结论:JWT 无状态特性导致无法直接撤销,需立即更换私钥并配置服务端只信任新密钥。
- 先判断:确认泄露范围是签名密钥(Secret/Private Key)还是仅访问令牌(Token)。
- 优先做:生成新密钥对并更新所有验证服务配置,强制旧密钥签发的令牌验签失败。
- 再验证:使用旧令牌发起请求,确认服务端返回 401 Unauthorized 。
快速处理思路
JWT 密钥轮换涉及配置更新,无单一命令可完成,需按以下逻辑执行:
- 生成新的签名密钥或非对称密钥对(RS256)。
- 更新认证服务配置,禁用旧密钥 ID(kid)。
- 若使用微服务架构,确保所有网关和下游服务同步新公钥。
- 前端或客户端重新登录获取新令牌。
为什么会这样
JWT 设计初衷是无状态验证,令牌包含签名后即可离线校验,服务端不保存令牌状态。
RFC 7519 标准未定义吊销机制,令牌有效期(exp)内只要签名正确即被视为合法。私钥泄露意味着攻击者可伪造任意身份令牌,仅靠删除服务端会话无法阻止已签发的合法令牌通过验签。
分步处理
步骤 1:生成新密钥
立即生成新的 HMAC Secret 或 RSA 密钥对。若使用 JWK 集合,添加新密钥并标记旧密钥为失效。
# 示例:生成新的 RSA 私钥(OpenSSL)
openssl genrsa -out new_private.key 2048
openssl rsa -in new_private.key -pubout -out new_public.key步骤 2:更新服务端配置
修改认证服务配置,将验证密钥指向新公钥。若支持多密钥轮换(Key Rotation),移除旧密钥的 kid 信任列表。
步骤 3:强制客户端重认证
旧令牌虽无法立即物理删除,但可通过服务端拒绝验签使其失效。通知前端清除本地存储的旧 Token,引导用户重新登录。
步骤 4:引入黑名单(可选加固)
若需精确吊销特定令牌,需在令牌中加入 jti claim,并将泄露的 jti 存入 Redis 黑名单,验签时查询黑名单。
怎么验证是否生效
使用泄露的旧令牌调用受保护接口,观察响应状态码和日志。
- 预期结果:服务端返回 401 Unauthorized 或 403 Forbidden。
- 日志检查:查看认证服务日志,确认错误原因为 Signature Verification Failed 或 Key Not Found。
- 新令牌测试:使用新密钥签发的令牌请求接口,确认返回 200 OK。
常见坑
- 密钥缓存:部分网关或 SDK 会缓存公钥,需重启服务或清除缓存才能生效。
- 时间同步:多节点部署时,确保所有服务器时间同步,避免因时钟偏移导致新令牌验签失败。
- 密钥分发:微服务架构下,确保所有下游服务及时获取新公钥,避免服务间调用中断。
- 硬编码密钥:检查代码仓库,确保旧密钥未硬编码在源码中,防止二次泄露。
常见问题
能否只吊销单个泄露的 JWT 令牌?
原生 JWT 不支持,需额外实现黑名单机制。
标准 JWT 无状态,服务端无法感知单个令牌状态。需在令牌 payload 中加入唯一标识 jti,并将该 jti 存入服务端黑名单数据库,每次请求时查询拦截。
轮换密钥会影响在线用户吗?
会影响,旧密钥签发的令牌会立即失效。
切换密钥后,所有持旧令牌的用户请求将被拒绝。建议在低峰期操作,或采用双密钥过渡期策略,但泄露场景下应优先安全,立即废除旧密钥。
如何防止私钥再次泄露?
使用密钥管理服务(KMS)或硬件安全模块(HSM)存储私钥。
避免将私钥放在代码库或环境变量中。使用云厂商 KMS 或专用密钥管理系统,限制访问权限并开启审计日志。
参考来源
- RFC 7519: JSON Web Token (JWT), Section 5.1 (alg), https://www.rfc-editor.org/rfc/rfc7519.html
- OWASP: JSON Web Token Cheat Sheet for Java, https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html
- Auth0: JWT Revocation strategies documentation (General Industry Practice)