目标
每种令牌设计都在隐式回答一个问题:这串字符泄漏了,它能用多久?答案是“寿命算术 + 轮换与吊销行为”。解码真实令牌、在刷新端点重放、再故意吊销一个,三次测量就能把模糊的安全感换成数字,而这个数字要么满足策略、要么直接点名修复项。
步骤要点
- base64 解码访问与刷新令牌的第二段,读出真实 exp/iat/jti/scope(如 15 分钟与 30 天)。
- 用原刷新令牌换新令牌后,立刻再原令牌重放一次:必须 401,200 则意味着可无限重放。
- 对换到的新令牌执行 logout,再重放:应被拒,验证吊销链路真实生效。
- 检查重放检测逻辑:consumed 的 jti 再次出现时整族吊销,窃取的令牌无法借轮换洗白。
- 把实测行为固化为代码默认值(ACCESS_TTL 15m 等),未来变更是对策略的 diff 而非考古。
排错提示
刷新令牌从不轮换就实现“consumed 检查 + 轮换”,顺带获得窃取检测;轮换打断多标签页并发刷新就按用户加短互斥,失败方用新令牌重试;访问令牌无法吊销是無状态的本性,把访问寿命压到分钟级、把吊销权放在刷新侧。若业务要求秒级全局切断,诚实的答案不是 JWT。
适用边界
短访问令牌限定了吊销延迟上限,需要即时切断的场景不该选无状态 JWT;轮换加族吊销能发现“重用”但发现不了“初次盗窃”,高敏感账户应配合设备绑定。
代码示例
# 1. Read the real lifetimes
echo "$REFRESH" | cut -d. -f2 | base64 -d | jq '{exp, jti}'
# 2. Rotation must invalidate the predecessor
curl -X POST .../auth/refresh -d "refresh_token=$R1" > /tmp/r2
sleep 1
curl -X POST .../auth/refresh -d "refresh_token=$R1" # expect 401