一、引言:为什么“无状态”如此迷人
HTTP 协议天生无记忆,每一次请求都是一次“陌生人对话”。Cookie、Session、Token 轮番登场,只为解决一句灵魂拷问:“这个请求者到底是谁?”
JWT(JSON Web Token)用三段 Base64 字符串,把身份信息、权限范围、过期时间封装成自包含的“数字契约”,让服务器摆脱 Session 存储枷锁,也让微服务间传递信任变得像快递包裹一样简单。
本文尝试用近四千字,把 JWT 的生成、验证、攻防、演进、落地故事串成一本可随身携带的“令牌手册”。
二、历史脉络:从 Session Cookie 到 Stateless Token
- 1994:Netscape 推出 Cookie,服务端用 Set-Cookie 种下 SessionID,浏览器每次自动回传。
- 2000 年代:Session 存储在内存、Redis、数据库,横向扩展时带来“粘性会话”噩梦。
- 2010:OAuth 2.0 普及,Token 成为授权主流,JWT 作为其轻量级表示被纳入 RFC 7519。
- 2020:微服务、Serverless、边缘计算兴起,无状态成为架构刚需,JWT 成为“最小信任单元”。
三、令牌解剖:三段字符串的密码学契约
JWT 由 Header、Payload、Signature 三段组成,用两个点号连接,形如 `aaaa.bbbb.cccc`。
1. Header
声明类型(JWT)与签名算法(HS256、RS256、ES256…)。
2. Payload
承载业务数据(sub、iat、exp、scope…),官方定义 7 个标准字段,也可自定义私有字段。
3. Signature
用 Header 指定的算法对 “Base64(Header) + . + Base64(Payload)” 进行签名,确保篡改即失效。
三段字符串既可放在 HTTP Header、URL 查询参数,也能塞进 Cookie,甚至 QR 码。
四、生成流程:从用户登录到颁发令牌
1. 认证
用户提交凭证,服务端验证账号密码、短信验证码或生物特征。
2. 授权
查询角色权限,组装 Payload:用户 ID、角色列表、过期时间、发行者。
3. 签名
根据安全级别选择对称(HMAC)或非对称(RSA/ECDSA)算法生成签名。
4. 颁发
通过 HTTP 200 响应返回 JWT,客户端存于内存、Cookie、LocalStorage 或移动端 Keychain。
5. 刷新
搭配 Refresh Token 机制,让长周期权限无需重输密码。
五、验证流程:从令牌到身份确认的“三步曲”
1. 格式校验
检查三段结构、Base64 完整性、JSON 可解析性。
2. 签名验证
用 Header 中声明的算法与密钥重新计算签名,比对一致性。
3. 业务校验
检查 exp(过期)、nbf(生效)、iss(发行者)、scope(权限范围)是否满足当前请求。
任何一步失败即返回 401 Unauthorized,并附带 WWW-Authenticate 头部提示原因。
六、签名算法:对称与非对称的权衡
- HMAC(HS256/HS512)
计算快、密钥短,适合内部微服务;缺点是共享密钥泄露即全线失守。
- RSA(RS256)
私钥签名、公钥验证,密钥分离,适合跨域、开放平台;计算量略大。
- ECDSA(ES256)
同等安全强度下密钥更短、签名更小,移动端友好,但实现复杂。
选择原则:性能敏感选 HMAC,开放平台选 RSA/ECDSA,必要时混合使用(JWT + JWE 加密 Payload)。
七、攻防实录:六类常见攻击与防御
1. 签名伪造
攻击者把 alg 改为 none,删除签名。防御:强制验证 alg 白名单。
2. 密钥泄露
对称密钥被拖库。防御:密钥轮换、环境变量注入、使用非对称方案。
3. 重放攻击
被盗令牌再次使用。防御:exp 短周期 + Refresh Token,或绑定 IP、UA、指纹。
4. 算法混淆
把 RS256 公钥当成 HMAC 密钥。防御:解析 Header 后拒绝非预期算法。
5. 敏感信息泄露
Payload 明文暴露用户邮箱、手机号。防御:使用 JWE 加密或最小字段原则。
6. 令牌劫持
XSS 窃取 LocalStorage 中的 JWT。防御:HttpOnly Cookie + SameSite + CSP。
八、生命周期管理:短令牌与长会话
- 有效期策略
访问令牌 15 min、刷新令牌 7 天,既降低泄露窗口,又避免频繁登录。
- 撤销机制
由于 JWT 无状态,服务端需维护“黑名单”或使用版本号(jti)+ 分布式缓存。
- 滑动窗口
每次请求后刷新 exp,实现“活跃续命”。注意并发场景下的竞态条件。
九、进阶场景:微服务、网关、边缘计算
1. 网关统一鉴权
边缘网关验证签名后,把解析后的用户 ID 注入请求头,下游服务无需二次解析。
2. 微服务间调用
内部服务使用 HMAC 短令牌,跨域服务使用 RSA 长令牌,实现“内外有别”。
3. 边缘函数
在 CDN Worker 中验证 JWT,拒绝非法请求,减少回源流量。
4. 多租户
iss 字段区分租户,scope 字段区分权限,实现“一张令牌,多域通行”。
十、工具与生态:调试、可视化、测试
- 在线解码器:粘贴令牌即可查看 Header、Payload、签名验证结果。
- 单元测试:用固定密钥与已知负载生成“金样本”,断言解析结果。
- 安全扫描:集成 OWASP JWT Cheat Sheet,自动检测弱算法、缺失字段。
- 监控告警:令牌过期前 5 min 触发通知,防止用户体验断崖。
十一、未来展望:JWT 2.0 与去中心化身份
- JOSE 扩展:支持 EdDSA、BLS12-381 后量子算法。
- Verifiable Credentials:把 JWT 作为可验证凭证的一部分,实现去中心化身份(DID)。
- 零知识证明:在不暴露隐私字段的情况下证明“我已成年”。
当 Web3 来临时,JWT 或许不再是“服务端颁发”,而是“用户自证”。
十二、每日一练:亲手签发与验证
1. 准备:选择一种签名算法,生成密钥对。
2. 构造:编写 Header 与 Payload,填入标准字段与自定义声明。
3. 签名:使用工具或库生成 Signature。
4. 验证:把令牌放到解码器中,观察篡改后的错误提示。
5. 思考:如果把 exp 改成 1970,会发生什么?
十三、结语:令牌即契约
JWT 的简洁让它易于传播,也容易被误用。
真正的安全不在于算法多高级,而在于:
- 最小披露:只把必要信息放进 Payload;
- 最小信任:密钥、算法、有效期随时可轮换;
- 最大验证:每一次请求都重新校验签名与业务规则。
当下一次你拿到一串三段点号分隔的字符,请记得:
它不仅是一张通行证,更是一份数字时代的信任契约。