JWT 知识小课堂:从入门到精通,一文吃透 JSON Web Token

JWT 看似简单,实则暗藏玄机。从 JWS/JWE 标准族到密钥管理陷阱,从 Token 生命周期设计到 JWT 伪造攻击,这篇小课堂带你深入 JWT 的每一个角落。


一、JWT 到底是什么?

JWT(JSON Web Token)是一种紧凑、自包含的方式,用于在各方之间安全地传输信息。它由 IETF 在 2015 年通过 RFC 7519 标准化,但核心思想可追溯到更早的 Token 认证机制。它并非为替代 Session 而生,而是为了解决无状态分布式系统中的身份传递问题。

核心定位
维度 说明
设计哲学 自包含原则:Token 自身携带全部必要信息,服务端无需额外查询
数据模型 三段式结构:Header.Payload.Signature,Base64Url 编码
类型系统 Payload 为 JSON 对象,支持字符串、数字、布尔、数组、对象
编码规范 必须使用 Base64Url 编码(非标准 Base64,去除了 = 填充和 +/ 字符)
标准族 RFC 7515(JWS)、7516(JWE)、7517(JWK)、7518(JWA)、7519(JWT)
元数据 Header 声明算法与类型,Payload 声明声明(claims),Signature 保证完整性
核心特点深度解读
特点 表面理解 深层陷阱
自包含 Token 携带全部信息,服务端无状态 Payload 明文可见,敏感信息直接暴露
跨域友好 天然适合分布式、微服务、前后端分离 Token 一旦签发,在过期前无法主动撤销
标准化 IETF 标准,多语言库支持完善 算法声明在 Header 中,存在算法混淆攻击面
易于传输 字符串格式,可放 Header/URL/Cookie 体积通常比 Session ID 大 5-10 倍,高频请求带宽压力大
人类可读 Base64 解码即可查看内容 可读≠可信任,客户端可随意篡改 Payload 内容
广泛支持 几乎所有编程语言都有成熟库 库的实现质量参差不齐,默认配置常存在安全隐患

二、JWT 格式规范:三段式结构深度解析

2.1 完整结构
复制代码
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.     ← Header(蓝色)
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.  ← Payload(绿色)
SflKxwRJSMeKKF2QT4fwpMe                   ← Signature(红色)
2.2 各段详解
内容 编码方式 核心作用 安全警示
Header JSON 对象,声明 alg(算法) 和 typ(类型) Base64Url 告诉验证方用什么算法验证签名 ⚠️ alg 可被篡改,必须白名单校验
Payload JSON 对象,携带声明(claims) Base64Url 携带用户身份、权限、过期时间等业务数据 ⚠️ 仅 Base64 编码,任何人可解码查看
Signature 签名值 Base64Url 防止 Header 和 Payload 被篡改 ✅ 唯一不可伪造的部分,依赖密钥安全

签名公式:

复制代码
HMACSHA256(
  base64url(header) + "." + base64url(payload),
  secret
)
2.3 标准声明(Registered Claims)
声明 全称 说明
iss Issuer 签发者,标识 Token 来源
sub Subject 主题,通常为用户唯一标识
aud Audience 受众,标识 Token 的目标接收方
exp Expiration Time 过期时间戳(秒级 Unix 时间)⭐ 必须设置
nbf Not Before 生效时间,在此之前 Token 无效
iat Issued At 签发时间
jti JWT ID 唯一标识,用于防止 Token 重放
2.4 关键规则
规则编号 规则内容 违反后果
R1 必须使用 Base64Url 编码,禁止标准 Base64 的 = 填充 URL 中 = 会被转义,破坏 Token 格式
R2 Header 中的 alg 不可为 none(生产环境) 算法置空后签名验证被跳过,攻击者可任意伪造 Token
R3 exp 必须设置且为未来的时间戳 永不过期的 Token 一旦泄露,风险永久存在
R4 敏感数据不得放入 Payload(仅 JWE 可加密) Payload 仅 Base64 编码,任何人可解码查看
R5 密钥长度必须符合算法要求(如 HS256 需 ≥256 位) 短密钥可被暴力破解或彩虹表攻击
R6 验证时必须同时校验签名、过期时间、受众 漏检任一环节都可能被绕过

三、签名算法:六种核心方案

3.1 算法对照表
算法 类型 密钥要求 特点 适用场景
HS256 对称 (HMAC-SHA256) 单一共享密钥 速度快,密钥分发困难 内部服务、微服务间通信
HS384/512 对称 单一共享密钥 更高安全级别 高安全要求的内部系统
RS256 非对称 (RSA-SHA256) 私钥签 / 公钥验 公钥可公开分发,私钥保密 公开 API、OAuth2
ES256 非对称 (ECDSA-P256) 私钥签 / 公钥验 签名更短,性能更好 移动端、带宽敏感场景
PS256 非对称 (RSA-PSS) 私钥签 / 公钥验 更安全的 RSA 填充方案 新标准推荐替代 RS
none 禁用 不签名,仅 Base64 编码 生产环境绝对禁用
3.2 对称 vs 非对称选型
维度 对称 (HMAC) 非对称 (RSA/ECDSA)
签名速度 慢(RSA 尤其明显)
验证速度 快(仅需公钥)
密钥管理 困难(多方共享同一密钥) 简单(公钥可公开)
Token 体积 大(RSA 签名 256-512 字节)
适用架构 内部服务、单体应用 开放平台、第三方集成
密钥泄露风险 高(任何持有方都可伪造) 低(仅私钥持有方可伪造)

四、JWT 安全:被低估的攻击面

4.1 算法混淆攻击(Algorithm Confusion / alg: none 攻击)

攻击者修改 Header 中的 algnone,并删除 Signature 段,服务端若未严格校验算法,会跳过签名验证直接信任 Payload。

🔴 攻击示例:

复制代码
原始 Token: eyJhbGciOiJIUzI1NiJ9.xxx.yyy
伪造 Token: eyJhbGciOiJub25lIn0.xxx.  ← alg 改为 none,去掉签名

🛡️ 防御方案:

  • 服务端硬编码允许的算法白名单,拒绝 none
  • 验证时从可信来源读取 alg,不信任 Header 中的声明
  • 对称与非对称算法使用完全独立的密钥
4.2 密钥混淆攻击(Key Confusion)

攻击者将 alg 从 RS256 改为 HS256,然后用公钥作为 HMAC 密钥签名,服务端若用同一公钥验证 HMAC,会导致验证通过。

🛡️ 防御方案:

  • 对称与非对称密钥物理隔离
  • 验证前检查密钥类型与算法是否匹配
  • 不允许客户端指定算法
4.3 暴力破解与密钥泄露
攻击类型 描述 防御方案
密钥暴力破解 短密钥或弱密钥被枚举破解 密码学安全随机数生成器,密钥长度 ≥256 位
密钥硬编码 密钥写在代码/配置中泄露到 GitHub 使用 KMS/HSM 管理,环境变量注入,定期轮换
密钥泄露传播 共享密钥被多方持有后扩散 非对称算法优先,对称密钥最小权限分发
日志泄露 Token 被打印到日志中 禁止日志输出完整 Token,脱敏处理
4.4 Token 生命周期风险
风险 描述 防御方案
永不过期 expexp 极远 强制设置合理过期时间(通常 15 分钟 ~ 2 小时)
无法撤销 签发后服务端无法主动失效 结合黑名单/Redis 存储 Token 状态,或使用短 Token + Refresh Token
重放攻击 截获的 Token 被重复使用 结合 jti + 服务端存储已用 ID,或使用一次性 Token
令牌窃取 XSS 窃取 Token,CSRF 伪造请求 HttpOnly Cookie 存储(防 XSS),SameSite 属性(防 CSRF)

五、JWT 与 Session 深度对比

特性 JWT Session
存储位置 客户端(Cookie/LocalStorage/Header) 服务端(内存/Redis/数据库)
服务端状态 无状态 有状态
跨域支持 天然支持 需 CORS + Cookie 配置
分布式扩展 天然支持 需共享 Session 存储(Redis)
撤销能力 困难(需黑名单机制) 简单(服务端直接删除)
信息暴露 Payload 明文可见 仅 Session ID 暴露
Token 体积 较大(500B ~ 2KB) 极小(~32B)
过期控制 依赖 exp,签发后不可改 服务端随时可调整
适用场景 分布式系统、微服务、开放 API 单体应用、需要即时撤销的场景

六、Refresh Token 机制

6.1 为什么需要双 Token?
  • Access Token:有效期短(15 分钟),减少泄露风险
  • Refresh Token:有效期长(7-30 天),用于在 Access Token 过期后无感知续期
6.2 双 Token 流程
复制代码
用户登录 → 服务端返回 Access Token + Refresh Token
        ↓
客户端用 Access Token 访问 API
        ↓
Access Token 过期(401)
        ↓
客户端用 Refresh Token 请求 /refresh
        ↓
服务端验证 Refresh Token,返回新的 Access Token + Refresh Token
        ↓
Refresh Token 也过期 → 要求用户重新登录
6.3 Refresh Token 安全要点
要点 说明
存储方式 必须 HttpOnly Cookie,禁止前端 JavaScript 访问
轮换机制 每次刷新后同时更新 Access Token 和 Refresh Token,旧 Refresh Token 立即失效
绑定设备 Refresh Token 与设备指纹/IP 绑定,异常环境拒绝刷新
撤销能力 Refresh Token 必须在服务端持久化存储,支持随时撤销

七、JWT 最佳实践清单

✅ 生成 JWT 时
  • 始终设置合理的 exp(建议 15 分钟 ~ 2 小时
  • 敏感数据绝不放入 Payload,需要加密时使用 JWE
  • 使用密码学安全随机数生成器生成密钥
  • 对称密钥长度 ≥256 位 ,非对称密钥 RSA ≥2048 位
  • 设置 issaudjti 等声明,增强 Token 上下文
  • 使用成熟的库(jsonwebtokenPyJWTjjwt),不手写签名逻辑
✅ 验证 JWT 时
  • 硬编码允许的算法白名单,拒绝 none 和意外算法
  • 严格验证签名、过期时间、签发者、受众
  • 对称与非对称密钥物理隔离,防止密钥混淆攻击
  • 设置 Token 最大长度限制,防止畸形数据攻击
  • 验证失败时返回统一错误,不暴露具体失败原因(防止信息泄露)
❌ 避免这样做
  • alg: none允许客户端指定算法
  • 将密钥硬编码在代码仓库中
  • 在 Payload 中存储密码、密钥等敏感信息
  • 设置永不过期的 Token
  • 用 JWT 替代所有 Session 场景(需要即时撤销时选 Session)
  • URL 参数中传递 JWT(泄露风险高)
  • 忽略 Token 体积对带宽的影响

八、什么时候选择 JWT?

场景 推荐方案 核心理由
分布式微服务间身份传递 JWT 无状态,天然适合跨服务调用
开放 API / 第三方集成 JWT (RS256) 公钥可公开分发,私钥保密
单页应用(SPA)身份认证 JWT + Refresh Token 跨域友好,支持无感知续期
移动端 App 认证 JWT (ES256) 签名短,节省带宽
需要即时撤销权限 Session + Redis JWT 撤销困难,Session 可即时删除
内部高安全要求系统 Session 服务端完全控制,可随时干预
一次性密码/邀请链接 jti 的短效 JWT 自包含,无需服务端存储状态

九、在线体验

欢迎体验 BugCome JWT 解码/验证工具,支持:

  • 🔓 一键解码 JWT Header 和 Payload
  • 验证签名有效性(支持 HS256/RS256/ES256)
  • 自动解析过期时间、签发时间等声明
  • 📋 格式化复制 与导出
相关推荐
To_OC1 小时前
写了三天 Next.js,我的 React 世界观被拆了又装回去
前端·全栈·next.js
独泪了无痕2 小时前
viewer.js 安装与配置指南:实现图片预览功能
前端·vue.js
Fluxart.ai4 小时前
电商商品图审核怎么自动化?规则引擎、人工复核与发布门禁
java·前端·自动化
why技术4 小时前
AI 写的文章,可能都带着手敲一遍都去不掉的“隐形水印”。
前端·人工智能·后端
愚公搬代码4 小时前
【愚公系列】《Android应用案例开发大全》016-LBS类应用掌上杭州(辅助工具类的开发)
android·前端
CodeSheep4 小时前
又一个华为天才少年,离职了!
前端·后端·程序员
kyriewen5 小时前
面试官说"打开你的AI工具"——我才发现,他考的根本不是写代码
前端·人工智能·面试
IT_陈寒6 小时前
Vue的双向绑定把我坑惨了,原来这个场景不能用
前端·人工智能·后端
hunterandroid6 小时前
[Android 从零到一] Compose LazyColumn 性能优化:key、稳定性与重组治理
android·前端