
6 月
JWT 没有死:2026 年 Web 认证该选 Session、JWT 还是混合方案
可引用摘要: JWT 是一种声明格式,不是完整的登录、会话或授权方案。对同源 Web 应用,服务端 Session 配合安全 Cookie 通常更容易撤销和管理;对跨服务 API、第三方授权或分布式资源服务器,短期 JWT 仍然有价值。安全选型的重点不是“JWT 还是 Cookie”二选一,而是令牌存放位置、有效期、撤销机制、签名验证、刷新令牌保护和业务架构是否匹配。
“JWT 已死”是一个吸引点击但容易误导的结论。JWT 仍被 OAuth、OpenID Connect 和大量 API 系统使用;真正发生变化的是,工程团队越来越少把长期 JWT 当成无需服务端状态的万能会话方案。
更准确的问题应该是:你的系统为什么需要 JWT,它解决了什么边界问题,又由什么机制承担撤销、轮换和泄漏后的响应?
先分清四个容易混淆的概念
| 概念 | 作用 | 常见误解 |
|---|---|---|
| Cookie | 浏览器存储并随请求发送数据的机制 | Cookie 不等于 Session,也不等于天然安全 |
| Session | 服务端维护的会话状态 | Session ID 仍是凭证,被窃取后同样可能遭到冒用 |
| JWT | 以 JSON 表达声明的令牌格式 | JWT 不等于 OAuth,也不保证加密 |
| OAuth 2.0 | 委托授权框架 | OAuth 不规定所有 access token 都必须是 JWT |
JWT 可以放在 Cookie 中,Session ID 也可以通过 Cookie 传输。把“JWT vs Cookie”作为二选一,本身就混合了令牌格式和传输机制两个层次。
JWT 的真实风险是什么
已签名不等于已加密
常见的 JWS 形式 JWT 使用 Base 64 URL 编码 Header 和 Payload,并用签名保证完整性。拿到令牌的人通常可以读取其中声明,因此不应把密码、身份证号、密钥或其他不必要的敏感信息放入 Payload。
但不能因此说所有 JWT 都“只能明文”。JOSE 体系也定义了 JWE 加密令牌。实际系统应明确自己使用的是签名 JWT、加密 JWT,还是不透明令牌。
长有效期令牌难以及时撤销
如果资源服务器仅验证 JWT 签名和过期时间,不查询服务器状态,那么令牌在过期前通常会继续有效。登出、封号、权限回收和密钥泄漏都会因此变得复杂。
常见缓解措施包括:缩短 access token 有效期、维护 denylist、使用令牌内省、轮换密钥、绑定会话版本,或者把高风险操作重新交给服务端状态检查。引入这些机制并不说明 JWT “失败”,而是说明无状态验证存在明确代价。
算法与声明验证必须显式配置
alg: none 和算法混淆问题通常来自验证器错误接受未授权算法,而不是 JWT 必然允许攻击者绕过签名。RFC 8725 要求调用方限制允许的算法,并验证 issuer、audience、subject、过期时间等声明。
使用成熟库也不能代替配置。应用必须明确允许算法、密钥来源和声明约束,不能相信令牌自己声明的验证方式。
存放位置决定一部分攻击面
把 access token 放入 localStorage 会让同源脚本读取它,一旦发生 XSS,令牌可能被直接窃取。HttpOnly Cookie 可以阻止 JavaScript 读取,但浏览器会自动附带 Cookie,因此还需要 SameSite、CSRF 防护、Secure、作用域和会话更新策略。
不存在“换成 Session Cookie 就没有任何令牌泄漏风险”的方案。Session ID 仍是 bearer credential,必须保护传输、存储和生命周期。
三种常见架构如何选
同源传统 Web 应用:优先考虑服务端 Session
如果浏览器和后端属于同一产品,服务端可以稳定访问共享 Session 存储,并且业务需要即时登出、封号和权限回收,那么不透明随机 Session ID 往往最简单。
建议至少做到:
- 使用足够随机、不可预测的 Session ID;
- Cookie 设置
HttpOnly、Secure和合适的SameSite; - 登录和权限提升后更新 Session ID;
- 设置空闲与绝对过期时间;
- 在登出、改密和安全事件后撤销会话;
- 不把敏感业务数据直接写入客户端 Cookie。
跨服务 API:短期 JWT 可以减少同步查询
当多个资源服务器需要验证同一个授权服务器签发的声明时,短期 JWT 可以减少每次请求的中心化查询,并让服务独立验证签名。
代价是需要严格管理 issuer、audience、scope、密钥轮换和撤销窗口。JWT 应保持短期、最小权限,并避免承载经常变化的权限数据。
浏览器 OAuth 客户端:优先评估 BFF 或安全刷新机制
对于浏览器应用,Backend-for-Frontend(BFF)模式可以把 OAuth token 保留在服务端,仅向浏览器发送受保护的会话 Cookie。如果业务必须向公共客户端签发 refresh token,RFC 9700 要求使用发送者约束或 refresh token rotation 来检测重放。
这项要求来自 OAuth 2.0 Security Best Current Practice,而不是“OAuth 2.1 已经正式淘汰 JWT”。OAuth 2.1 在本文核验时仍属于持续演进的规范工作,不能把草案状态写成已生效的最终标准。
如果团队正在把认证能力接入 Agent 或工具协议,还可以结合智盒的MCP 与 AI 基础设施观察评估信任边界;涉及 Codex 与应用开发流程时,可参考ChatGPT 与 Codex 集成观察。
一张可执行的决策表
| 场景 | 优先方案 | 需要额外确认 |
|---|---|---|
| 同源网站、单一后端 | 服务端 Session + 安全 Cookie | Session 存储、高可用、CSRF 与撤销 |
| 多个内部资源服务 | 短期 JWT 或不透明 token + introspection | audience、scope、密钥轮换、撤销窗口 |
| 第三方 API 授权 | 标准 OAuth/OIDC 流程 | 客户端类型、PKCE、token 绑定与最小权限 |
| 浏览器 SPA | 优先评估 BFF | XSS、CSRF、刷新令牌存放方式 |
| 高风险即时权限变更 | 服务端状态检查或短期 token | 封号、改密、支付等事件如何立刻生效 |
适合与不适合
适合
- 正在为新 Web 应用选择认证架构的开发团队;
- 需要审查现有长期 JWT、localStorage 或刷新令牌方案的人;
- 希望区分 Session、Cookie、JWT 与 OAuth 职责边界的工程师。
不适合
- 把本文当作针对具体系统的渗透测试或合规认证;
- 不结合威胁模型就直接复制固定的 token 有效期;
- 用“JWT 已死”或“Session 永远更安全”替代架构评估。
FAQ
JWT Payload 是否任何人都能读取?
常见的签名 JWT 可以被持有者解码读取,但签名可以防止未授权篡改。JWE 可以提供加密。无论使用哪种形式,都不应放入不必要的敏感数据。
JWT 是否无法撤销?
JWT 格式本身没有自动撤销机制,但系统可以通过短有效期、denylist、令牌内省、会话版本或密钥策略实现撤销。问题在于这些措施会增加状态和复杂度。
Session Cookie 是否天然比 JWT 安全?
不是。安全性取决于随机性、Cookie 属性、CSRF/XSS 防护、传输安全、会话固定防护、过期和撤销策略。被窃取的 Session ID 同样可能被重放。
Access token 应该设置成 5 分钟还是 15 分钟?
没有适用于所有系统的固定答案。有效期应结合数据敏感度、刷新机制、用户体验、撤销能力和攻击检测速度确定,并通过威胁模型记录理由。
refresh token rotation 能阻止所有令牌盗用吗?
不能。它主要用于检测旧 refresh token 的重放,并在发现重复使用时撤销令牌族。它不能替代 TLS、安全存储、客户端绑定、XSS 防护和异常检测。
官方参考来源
- IETF RFC 7519:JSON Web Token
- IETF RFC 8725:JSON Web Token Best Current Practices
- IETF RFC 9700:Best Current Practice for OAuth 2.0 Security
- IETF:OAuth 2.0 for Browser-Based Applications
- OWASP:Session Management Cheat Sheet
- OWASP:REST Security Cheat Sheet(JWT 验证与撤销建议)
本文由 AI(Codex)基于公开来源整理并完成结构化核验,发布由智盒运营流程执行。










