别再把 JWT 存在 localStorage 里了!2025 年前端鉴权新思路


对于许多前端开发者来说,下面这行代码可能已经形成了肌肉记忆:

简单、直接、有效。多年来,将 JWT (JSON Web Token) 存储在 localStorage
中,似乎是前后端分离架构下的“标准答案”。然而,随着网络安全威胁的不断演进,这个曾经的“最佳实践”如今已然成为一个巨大的安全隐患。

2025
年即将到来,前端生态日新月异。如果我们还在沿用旧的鉴权模式,无异于将我们精心构建的应用暴露在风险之中。是时候更新我们的知识库,拥抱更安全的鉴权新思路了。

localStorage 的“原罪”:为何它不再安全?

localStorage 的核心问题在于其 ** 脆弱的安全性 ** ,这主要体MAT现在对 ** XSS (Cross-Site
Scripting, 跨站脚本攻击) ** 的无力抵抗上。

什么是 XSS 攻击?

简单来说,XSS 攻击是指攻击者设法在我们的网站上注入并执行了恶意的 JavaScript
脚本。注入的途径多种多样,可能是一个被用户渲染的恶意评论,也可能是一个包含恶意代码的 URL 参数。

XSS 如何窃取 localStorage 中的 Token?

一旦恶意脚本在我们的页面上成功执行,它就拥有了与我们自己的前端代码几乎完全相同的权限。这意味着:

** 它可以轻松访问 localStorage ! **

攻击者只需要注入一行简单的代码,就可以将我们存储的 JWT 发送到他自己的服务器上:

一旦 Token 被盗,攻击者就可以冒充我们的用户,为所欲为。所有依赖于这个 Token 的后端接口都将对攻击者敞开大门。这无疑是毁灭性的。

** 结论: ** localStorage 本质上是一个对 JavaScript
完全开放的沙盒。任何能够在我们页面上执行的脚本,都能读写其中的所有数据。将敏感的、具有用户身份凭证的 JWT
存放在这里,就像把家门钥匙挂在了门外的钉子上——方便了自己,也方便了小偷。


“老派绅士”:HttpOnly Cookie——完美的解决方案吗?

为了解决 XSS 盗取 Token 的问题,社区很早就提出了一个经典的方案: ** 使用 HttpOnly Cookie ** 。

当服务器在设置 Cookie 时,如果添加了 HttpOnly 标志,那么这个 Cookie 将无法通过客户端 JavaScript ( document.cookie ) 来访问。浏览器只会在发送 HTTP 请求时自动携带它。

** 优点: **

  • ** 有效防御 XSS 盗取 ** :由于 JS 无法读取,XSS 攻击者无法直接窃取 Token。
  • ** 浏览器自动管理 ** :无需前端代码手动在每个请求头中添加 Authorization

** 但它也并非完美,带来了新的挑战:CSRF 攻击 ** 。

什么是 CSRF 攻击?

CSRF (Cross-Site Request Forgery, 跨站请求伪造)
是指攻击者诱导用户在一个已经登录的网站上,从一个恶意网站发起非本意的请求。

例如,我们登录了 bank.com ,浏览器保存了 bank.com HttpOnly
Cookie。此时,我们访问了一个恶意网站 evil.com ,该网站上有一个自动提交的表单,其目标是 bank.com
的转账接口。当我们打开 evil.com 时,浏览器会 ** 自动携带 ** bank.com 的 Cookie
发起转账请求,从而在我们自己不知情的情况下完成转账。

** 解决方案 ** :
幸运的是,CSRF 也有成熟的防御手段:

  1. ** SameSite 属性 ** :在设置 Cookie 时,将 SameSite 属性设置为 Strict Lax ,可以有效阻止跨站请求携带 Cookie。
  2. ** CSRF Token ** :服务器生成一个随机的 CSRF Token,前端在每次发起状态变更的请求时,都需要在请求体或请求头中携带这个 Token,服务器进行验证。

HttpOnly Cookie 方案虽然可行,但要求后端进行精细的 Cookie 配置和 CSRF
防御,对于现代前后端分离、特别是需要跨域调用的场景,配置会变得更加复杂。


2025 年的新浪潮:前端鉴权新思路

那么,有没有既能有效防范 XSS,又能优雅地适应现代前端架构的方案呢?答案是肯定的。以下是两种值得在 2025 年及以后重点关注的鉴权模式。

BFF 模式并非新技术,但它在解决前端鉴权困境上展现了巨大的威力。

** 核心思想 ** :在前端应用和后端微服务之间增加一个“服务于前端的后端”(BFF)。这个 BFF 专门为我们的前端应用服务,负责鉴权、API
聚合、数据转换等。

** 鉴权流程 ** :

  1. ** 登录 ** :前端将用户名密码发送给 BFF。
  2. ** 认证与换取 ** :BFF 将凭证发送给真正的认证服务,获取 JWT。
  3. ** 设置安全 Cookie ** :BFF ** 并不将 JWT 返回给前端 ** 。取而代之,BFF 创建一个会话(Session),并将 Session ID 存储在一个 ** 安全的、 HttpOnly SameSite=Strict 的 Cookie ** 中,返回给浏览器。
  4. ** API 请求 ** :前端向 BFF 发起所有 API 请求(例如 /api/user )。由于是同域请求(或配置了 withCredentials ),浏览器会自动携带上述 Session Cookie。
  5. ** 代理与鉴权 ** :BFF 收到请求后,通过 Session Cookie 找到对应的会话和 JWT,然后将 JWT 添加到请求头中,再将请求转发给后端的微服务。

** 优点 ** :

  • ** 极致安全 ** :JWT 完全不暴露给前端,XSS 攻击者无从窃取。
  • ** 前端无感 ** :前端开发者无需关心 Token 的存储、刷新和携带,就像在使用传统的 Session 一样。
  • ** 架构清晰 ** :BFF 层可以处理所有与安全和后端服务通信相关的复杂逻辑,让前端更专注于 UI。

** 缺点 ** :

  • ** 增加了架构复杂度 ** :需要额外维护一个 BFF 服务。

思路二:Service Worker + 内存存储

这是一个更“激进”和“纯前端”的方案,利用了 Service Worker 的强大能力。

** 核心思想 ** :将 Token 的管理权完全交给 Service Worker,主线程(我们的 React/Vue 应用)不直接接触 Token。

** 鉴权流程 ** :

  1. ** 登录 ** :主线程登录成功后,通过 postMessage 将获取到的 JWT 发送给激活的 Service Worker。
  2. ** 内存存储 ** :Service Worker 接收到 Token 后,将其存储在自身的 ** 作用域内的一个变量 ** 中(即内存中)。它不使用 localStorage IndexedDB
  3. ** 拦截请求 ** :前端应用像往常一样发起 fetch('/api/data') 请求,但 ** 不添加 Authorization 头 ** 。
  4. ** 注入 Token ** :Service Worker 监听 fetch 事件,拦截所有出站的 API 请求。它会克隆原始请求,并将内存中存储的 Token 添加到新请求的 Authorization 头中。
  5. ** 发送请求 ** :Service Worker 将带有 Token 的新请求发送到网络。

** 优点 ** :

  • ** 有效隔离 ** :Token 存储在 Service Worker 的独立运行环境中,与主线程的 window 对象隔离,常规的 XSS 脚本无法访问 Service Worker 的内部变量,安全性远高于 localStorage
  • ** 逻辑集中 ** :Token 的刷新逻辑(Refresh Token)也可以封装在 Service Worker 中,对应用代码完全透明。
  • ** 无需额外服务 ** :相比 BFF,这是一个纯前端的解决方案。

** 缺点 ** :

  • ** 实现复杂 ** :Service Worker 的生命周期和通信机制比 localStorage 复杂得多。
  • ** 兼容性与稳定性 ** :需要考虑浏览器兼容性,以及 Service Worker 被意外终止或更新的场景。

方案对比:一图胜千言

方案 防御 XSS 窃取 防御 CSRF 前端复杂度 后端/架构复杂度 推荐场景
** localStorage ** ❌ 极差 ✅ (天然免疫) ⭐ 极低 ⭐ 极低 ** 不推荐 ** 用于生产环境的敏感数据
** HttpOnly Cookie ** ✅ 优秀 ⚠️ 需手动防御 ⭐⭐ 较低 ⭐⭐⭐ 中等 传统 Web 应用,或有能力处理 CSRF 的团队
** BFF + Cookie ** ✅✅ 顶级 ✅✅ 顶级 ⭐ 极低 ⭐⭐⭐⭐ 较高 中大型应用,微服务架构,追求极致安全与清晰分层
** Service Worker ** ✅ 优秀 ✅ (天然免疫) ⭐⭐⭐⭐ 较高 ⭐ 极低 PWA,追求纯前端解决方案,愿意接受更高复杂度的创新项目

将 JWT 存储在 localStorage 的时代正在过去。这并非危言耸听,而是对日益严峻的网络安全形势的积极响应。

  • 对于 ** 新项目或有重构计划的项目 ** ,强烈建议采用 ** BFF + Cookie ** 模式。它虽然增加了架构成本,但换来的是顶级的安全性和清晰的职责划分,从长远看是值得的。
  • 对于 ** 追求极致前端技术或构建 PWA ** 的团队, ** Service Worker ** 方案提供了一个充满想象力的选择,能够将安全边界控制在前端内部。
  • 如果我们的应用规模较小,且暂时无法引入 BFF,那么退而求其次, **HttpOnly Cookie 配合严格的 SameSite 策略和 CSRF Token ** ,依然是比 localStorage 安全得多的可靠选择。