JWT 令牌测试

JWT 测试要点:签名算法校验(拒绝 none 与算法混淆)、exp/nbf 时间窗、aud/iss 校验、密钥轮换后的兼容、错误令牌返回 401;载荷可解码但不可被信任。

软件测试速查开发更新于 2026-10-13

JWT 测试是什么

JWT 测试围绕「服务端是否严格校验」展开:签名算法校验(拒绝 none 与算法混淆)、exp 与 nbf 时间窗、aud 受众与 iss 签发者校验、密钥轮换兼容,以及错误令牌统一返回 401。核心认知是:payload 只是 Base64URL 编码,任何人可解码,不能当作可信数据。

基本信息

结构header.payload.signature 三段 Base64URL,用点连接
关键校验签名算法、exp 过期、nbf 生效时间、aud 受众、iss 签发者
常见攻击面算法替换为 none、RS 与 HS 算法混淆、篡改载荷不验签
边界用例过期一秒、未来时间、跨服务复用、旧密钥签名
错误处理无效令牌统一 401,不泄露校验失败细节

典型使用场景

  • 登录签发链路:核对签发声明与服务端校验配置一致
  • 权限边界:低权限令牌访问高权限接口必须被拒
  • 密钥轮换:重叠期内旧令牌仍可用,伪造密钥的令牌不可用
  • 篡改测试:改动载荷一个字符,签名校验必须失败
  • 过期策略:过期令牌被拒且能正常走刷新流程
  • 跨系统复用检查:A 系统令牌打到 B 系统应被拒绝

令牌边界用例(Python 示意)

令牌边界用例(Python 示意)
import time, jwt
# 过期令牌:exp 设为 60 秒前,服务端必须拒绝
expired = jwt.encode({"sub": "u1", "exp": int(time.time()) - 60}, "k", algorithm="HS256")
r = client.get("/me", headers={"Authorization": "Bearer " + expired})
assert r.status_code == 401
# 同类用例:nbf 设为未来时间、aud 指向其他服务、payload 篡改一个字符
# 算法用例:将 header 中 alg 改为 none 并去掉签名,必须同样返回 401

校验项与对应用例

校验项要求用例断言
签名算法拒绝 none,拒绝 HS 与 RS 混淆篡改或换算法令牌返回 401
exp过期即失效过期一秒的令牌被拒
nbf未生效令牌被拒未来时间令牌被拒
aud 与 iss受众与签发者匹配跨服务令牌被拒
密钥轮换重叠期新旧密钥均可验签新密钥签发、旧密钥验证
只解码 payload 就当可信数据使用是常见缺陷:任何人都能构造合法 Base64 载荷,服务端必须完成签名与声明校验后再进入业务逻辑。
时间校验受服务器时钟影响:允许的时钟偏移(leeway)要显式配置并写进用例,否则偶发的无效令牌告警很难复现与解释。

易错点

  • 不校验算法:攻击者把 alg 改成 none 或替换为对称算法即可伪造令牌,服务端必须白名单允许的算法
  • 把敏感数据放进 payload:JWT 载荷可被任何人读取,身份证号、密钥一类数据不得放入
  • 无过期或有效期过长:泄露的令牌长期有效,应结合刷新令牌与吊销机制管理
  • 各处校验实现不一:网关校验了业务服务没校验,需要统一中间件并加跨服务用例
  • 错误提示过于详细:分别返回「签名错误」「已过期」方便攻击者试探,应统一提示

数据来源与参考

  • RFC 7519(JSON Web Token)
  • OWASP JWT Cheat Sheet
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌