JWT(JSON Web Token)鉴权是一种无状态、自包含的认证机制,其核心在于“信任签名,而非存储”。
一、JWT 结构:三段式 Base64Url 编码
xxxxx.yyyyy.zzzzz ↑ ↑ ↑ Header.Payload.Signature1.Header(头部)
- 内容:
{"alg":"HS256","typ":"JWT"} - 作用:声明签名算法(
alg)和令牌类型(typ)。 - 编码:Base64Url →
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
2.Payload(载荷)
- 内容:业务数据 + 标准声明(Claims)
{"sub":"1234567890",// 主题(用户ID)"name":"John Doe","admin":true,"iat":1516239022,// 签发时间"exp":1516242622// 过期时间(关键!)} - 标准 Claims:
iss(签发者)、sub(主题)、aud(受众)exp(过期时间)、nbf(生效时间)、iat(签发时间)
- 编码:Base64Url →
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
⚠️Payload 未加密!任何人可解码查看内容(仅防篡改,不防窥探)。
3.Signature(签名)
- 生成方式:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret_key ) - 作用:验证令牌未被篡改,且由可信方签发。
- 编码:二进制签名 → Base64Url
✅关键:只有服务端持有
secret_key,能生成/验证签名。
二、鉴权流程:无状态交互
关键步骤(服务端验证):
- 解析 Token:按
.分割三段。 - 验证签名:用本地
secret_key重新计算签名,比对是否一致。 - 校验 Claims:
exp是否过期iss是否可信aud是否匹配当前服务
- 提取用户身份:从
sub或自定义字段获取用户 ID。
✅无状态:服务端无需存储 JWT,所有信息自包含。
三、签名算法:对称 vs 非对称
| 算法类型 | 示例 | 密钥管理 | 适用场景 |
|---|---|---|---|
| 对称加密 | HS256, HS512 | 单一secret_key(服务端保管) | 单体应用、内部服务 |
| 非对称加密 | RS256, ES256 | 私钥(签发)+ 公钥(验证) | 多服务、OAuth 2.0 |
为什么推荐 RS256?
- 安全隔离:验证方只需公钥,即使泄露也无法伪造 Token。
- 避免密钥分发:微服务架构中,各服务用同一公钥验证,无需共享
secret_key。
⚠️绝对禁止:
- 使用
none算法(无签名)- 客户端可控制
alg字段(导致算法混淆攻击)
四、核心安全陷阱与对策
1.Token 泄露 = 账号被盗
- 原因:JWT 一旦签发,在
exp前始终有效。 - 对策:
- 短有效期:Access Token 设为 15~30 分钟。
- Refresh Token 机制:
- Access Token 过期后,用 Refresh Token(存储在 HttpOnly Cookie)换取新 Token。
- Refresh Token 可撤销(需服务端存储黑名单或状态)。
2.无法主动失效
- 问题:用户登出后,旧 Token 仍有效(因无状态)。
- 对策:
- 短期 Token:降低风险窗口。
- Token 黑名单:登出时将 Token 加入 Redis(
jti+exp),验证时检查。 - 版本号机制:用户表存
token_version,Payload 中带版本,不匹配则拒绝。
3.敏感信息泄露
- 问题:Payload 可被 Base64 解码。
- 对策:绝不存放密码、身份证号等敏感数据。
4.重放攻击(Replay Attack)
- 问题:截获 Token 后重复使用。
- 对策:
- 加入
jti(JWT ID) + 服务端记录已用 ID(短期存储)。 - 绑定客户端指纹(IP、User-Agent),但影响体验。
- 加入
五、与 Session 对比
| 特性 | JWT | Session |
|---|---|---|
| 状态 | 无状态(服务端不存) | 有状态(服务端存 Session) |
| 扩展性 | 天然适合分布式 | 需共享 Session 存储(Redis) |
| 安全性 | 依赖签名 + 短期有效 | 依赖 Cookie 安全(HttpOnly, Secure) |
| 撤销 | 困难(需额外机制) | 简单(删除 Session) |
| 体积 | 较大(含 Payload) | 小(仅 Session ID) |
✅选型建议:
- API 服务、移动端→ JWT
- 传统 Web 应用→ Session(更易管理登出、CSRF)
六、工程最佳实践
- Always use HTTPS:防止 Token 被中间人截获。
- Never store secrets in payload:Payload 是公开的。
- Validate all claims:
exp,iss,aud必须校验。 - Use strong keys:
- HS256:
secret_key≥ 32 字节随机字符串 - RS256:RSA 2048 位以上
- HS256:
- Implement refresh token rotation:每次刷新返回新 Refresh Token,旧的立即失效。
总结
- JWT 不是银弹:它解决的是无状态认证问题,而非所有安全问题。
- 核心价值:去中心化验证、跨域支持、减少 DB 查询。
- 致命缺陷:无法主动失效、信息泄露风险。
- 正确姿势:短期 Access Token + 可撤销 Refresh Token + 严格 Claim 校验。
💡一句话本质:
JWT 是“一次性密码本”,签名保证真实性,有效期控制风险窗口。