易君召
发布于 2026-08-26 / 作者:易君召 / 2 阅读
0

前端安全存储 JWT 令牌

核心结论:不要把 JWT 存在 localStorage /sessionStorage 做身份认证,极易遭受 XSS 窃取;优先使用 HttpOnly + Secure Cookie 存储 JWT,这是业界最安全方案。

方案对比

表格

存储方式

XSS 风险

CSRF 风险

适用场景

localStorage

🔴高,JS 可直接读取

🟢无 CSRF

不适合存身份 JWT,适合非敏感业务数据

sessionStorage

🔴高,JS 可直接读取

🟢无 CSRF

页面会话临时数据,禁止存登录凭证

HttpOnly Cookie

🟢JS 无法读取,防 XSS 窃取

🟡存在 CSRF 风险,需防御

✅推荐存储 Access‑Token / Refresh‑Token

内存 (React/Vue 变量)

🟢XSS 拿不到

🟢无 CSRF

页面刷新令牌丢失,需要配合后端 Cookie 拿新令牌


方案一:HttpOnly Cookie(生产最优)

后端 Set‑Cookie 关键属性(重点)

Set‑Cookie: access_token=xxxJWTxxx;
HttpOnly;          // JS document.cookie 无法读取,抵御XSS偷令牌
Secure;            // 仅HTTPS下发送,生产必须开启;http本地开发关闭
SameSite=Strict/Lax; // 防御CSRF,Lax兼容性更好
Path=/;
Max‑Age=3600;      // token过期时间
  • Access Token:短期有效期(15‑60min),放在 HttpOnly Cookie

  • Refresh Token:长时效,同样放入 HttpOnly Cookie,用于无感刷新令牌

前端不需要写任何 JS 存取 token,浏览器自动在请求头携带 Cookie。

CSRF 配套防御(必须做)

SameSite 不能 100% 兜底,建议搭配:

  1. SameSite=LaxStrict

  2. CSRF Token:后端返回一个 JS 可读取的 token(放 localStorage/meta),每次 POST/PUT 请求放在请求头 X‑CSRF‑Token,后端校验。

流程:浏览器自动带 Cookie (JWT) + 请求头携带 CSRF 随机串,双重校验。

方案二:内存存储(SPA 纯前端,无 HttpOnly 条件)

没有办法设置后端 Cookie 时的降级方案,刷新页面令牌丢失,需要登录或者调用刷新接口重新获取。

  1. JWT 仅保存在 Vue/React state、pinia/vuex 内存变量中,绝不写入 localStorage

  2. 页面初始化,调用后端接口获取 access token,放在内存

  3. axios 请求拦截器从内存取出放到 Authorization: Bearer xxx

  4. 页面刷新内存清空,跳转登录;或者用 HttpOnly 的 refresh cookie 静默刷新拿到新 access 放入内存。

// axios示例:token只存在内存pinia,不落地存储
const authStore = useAuthStore()
request.interceptors.request.use(config => {
  if(authStore.accessToken){
    config.headers.Authorization = `Bearer ${authStore.accessToken}`
  }
  return config
})

优点:XSS 拿到 JS 环境也拿不到令牌;缺点:刷新页面丢失会话。

❌为什么不推荐 localStorage 存 JWT

  1. XSS 漏洞一旦出现,攻击者 JS 直接执行 localStorage.getItem('token'),把 JWT 发送到黑客服务器,完全接管账号。

  2. 很多 SPA 框架(Vue/React)如果存在富文本、渲染用户输入,很容易出现 XSS。

很多老教程写 localStorage 存 JWT,属于过时不安全实践。

Refresh Token 最佳实践

  1. AccessToken:短期,HttpOnly Cookie;

  2. RefreshToken:更长时效,HttpOnly Cookie;

  3. 刷新接口 /refresh:接收 Cookie 里的 refresh token,返回新 access token;

  4. 黑名单机制:登出时后端把 refresh token 加入黑名单,即使 token 没过期直接作废;

  5. 支持主动吊销会话,防止令牌泄露永久可用。

常见坑点

  1. ❌ 开启 HttpOnly,前端 JS 就拿不到 token,不要试图 document.cookie 读取 JWT,设计如此。

  2. ❌ 开发环境 http 不能设置 Secure,生产环境必须 HTTPS+Secure。

  3. ❌ SameSite=None 的时候必须带上 Secure,否则浏览器拒绝写入 Cookie。

  4. ❌ 不要把敏感信息放在 JWT payload,JWT 只是编码不是加密,前端可以解码看到 payload。

简单选型总结

  1. 后端可控,优先:HttpOnly + Secure + SameSite Cookie 存 JWT,搭配 CSRF Token(最安全)

  2. 后端不能改 Cookie:内存保存 access token,refresh token 尽量走 HttpOnly Cookie

  3. 禁止:localStorage/sessionStorage 存放登录身份 JWT

补充:如果必须 localStorage(遗留项目,不得已)

只能作为妥协,必须额外做防护:

  • CSP 内容安全策略,禁止内联脚本,降低 XSS 攻击面

  • JWT 有效期尽量短

  • 做好 XSS 漏洞审计,过滤所有用户输入


本文原创作者:易君召,详见:https://www.yijunzhao.cn/authors/yijunzhao,转载请注明出处。

原文链接 https://www.yijunzhao.cn/archives/frontend-secure-jwt-token-storage-guide

欢迎访问 小易撩挨踢

https://www.yijunzhao.cn/