JWT 最大的卖点是无状态,最大的坑也是无状态——令牌发出去就收不回。存储位置同样不省心:localStorage 怕 XSS,Cookie 怕 CSRF。本文把 JWT 的优势、代价与适用边界摊开讲,并给出一份”什么时候不该用它”的清单。

它解决什么问题

Session-Cookie 方案里,会话状态保存在服务端,每个请求都要查一次存储,多实例部署还得解决会话共享。JWT 把身份声明签进令牌,服务端凭密钥自验,省掉中心化会话存储,天然适配多实例水平扩展、跨服务调用和移动端。这套设计在分布式系统里确实好用,但它不是免费的:状态被推到客户端的同时,服务端也放弃了对会话的即时控制权。分析 JWT 的优缺点,本质上是评估这笔交换在你的系统里划不划算。

核心原理:无状态这把双刃剑

优势一侧:

  • 水平扩展:验签只需密钥,任意实例都能处理,扩容不用操心会话同步;
  • 跨服务、跨端友好:令牌放在 Authorization 头里,不受 Cookie 同源策略约束,微服务网关、单点登录都好落地;
  • 移动端友好:不依赖 Cookie,App 本地存储即可,也没有跨平台会话管理的麻烦。

代价一侧,全部来自同一个根源——服务端不存状态:

  • 吊销困难:退出登录、封号、改密码,令牌在过期前照样有效;
  • 权限滞后:用户角色调整了,旧令牌里固化的声明不会跟着变;
  • 体积偏大:三段结构加 Base64URL 编码,比一个随机 SessionID 长得多,且每次都跟着请求走。

深入机制:存储位置之争

浏览器端令牌存在哪,是在两类风险之间做选择。

localStorage:押注 XSS 防线

Web Storage 里的令牌对同源页面的所有脚本可读。只要站点存在任何一处 XSS 注入点,恶意脚本就能把令牌直接打包外发。防 XSS 靠的是输出到 HTML、属性、JS、URL 等不同上下文时分别正确编码,再加 CSP 做纵深防御——但”全站绝无注入点”是个很难下保证的命题。好处是令牌不随请求自动发送,天然绕开了传统 CSRF。

Cookie:押注 CSRF 缓解

浏览器会自动携带 Cookie,于是有了 CSRF:攻击者诱导用户浏览器向目标站发起请求,Cookie 跟着走,服务端难辨真假。缓解手段是组合拳:HttpOnly(脚本读不到,挡住 XSS 窃取)、Secure(仅 HTTPS 传输)、SameSite=Lax/Strict(跨站请求不携带,挡住大部分 CSRF),敏感操作再叠加 CSRF Token 或 Origin/Referer 校验。SameSite 应视为纵深防御的一环,而不是唯一防线。

一句话总结:localStorage 把风险押在 XSS 上,Cookie 把风险押在 CSRF 上。CSRF 的缓解手段比”保证全站绝无 XSS”更可控,所以浏览器场景通常更推荐 HttpOnly Cookie,或者干脆用 BFF 架构把令牌留在服务端。

工程实践:什么系统不该用 JWT

  • 需要即时踢人、精细会话控制的系统:后台管理、金融风控、异地登录检测这类场景,Session 或”不透明 token + Redis”删除即失效,比给 JWT 打补丁直接得多;
  • 权限频繁变化的系统:声明签发即固化,改权限要等令牌过期,或被迫维护黑名单;
  • 安全储备不足的团队:算法混淆、密钥轮换、刷新令牌重放检测,每个都是实打实的坑,不透明 token 的出错面小得多;
  • 简单单体应用:Session-Cookie 成熟到不需要额外理由去替换。

反过来,开放平台 API、微服务间调用、SSO 的 ID Token——这些”签发方与消费方分离、令牌生命周期短”的场景,才是 JWT 的主场。另外,续期问题也不容忽视:推荐短寿命 access token 配合服务端管理、可轮换的 refresh token,而不是把令牌有效期拉到一整天。

对比与权衡

维度 JWT Session-Cookie
服务端状态 无(除非加黑名单) 会话存服务端或 Redis
水平扩展 天然支持 需共享存储或粘滞会话
吊销能力 难,靠黑名单或等过期 删除会话即生效
跨域与移动端 友好 受 Cookie 策略限制
CSRF 风险 放 Authorization 头则无 需 SameSite 加 Token 防护
XSS 窃取风险 存 localStorage 则高 HttpOnly Cookie 可缓解
请求体积 较大,数百字节起步 只有一个 SessionID

面试视角

JWT 最大的缺点是什么?怎么缓解?

无状态导致无法即时吊销。缓解靠短寿命 access token 加可撤销的 refresh token,高危操作再配合 jti 黑名单;代价是重新引入服务端状态。

令牌存 localStorage 还是 Cookie?

localStorage 怕 XSS,脚本可直接读走;Cookie 怕 CSRF,但可用 HttpOnly、Secure、SameSite 加 CSRF Token 组合缓解。浏览器场景通常选后者,或直接上 BFF。

JWT 和 Session-Cookie 怎么选?

看三点:是否需要即时吊销、客户端形态是浏览器还是 App/第三方、令牌内权限是否频繁变化。要即时控制选 Session,跨域跨端、追求无状态扩展选 JWT。

用了 JWT 系统就无状态了吗?

不一定。一旦引入黑名单、刷新令牌存储、强制下线这些功能,服务端状态又回来了。JWT 只是让你可以把状态减到最少,而不是消灭状态。

小结

  • JWT 的优点和缺点同源:无状态换来扩展性,同时失去即时控制。
  • 存储之争没有银弹:localStorage 押注 XSS 防线,Cookie 押注 CSRF 缓解,后者更可控。
  • 需要强会话控制的系统不该用 JWT;签发与消费分离、令牌短命的开放场景才是它的主场。
  • 任何宣称”JWT 完全无状态”的生产方案,都值得追问一句:那你们怎么踢人下线?