🦉前言
作为 JavaScript + Express + Vue 开发者,本人之前都是使用LocalStorage进行Token的存储
今天来扩展下其他的存储方案,为后续的业务开发增加一些思路
一、为什么需要关注 token 存储?
在认证流程中,服务器颁发 token(如 JWT)后,客户端需要安全存储这些凭证。选择不当的存储方案可能导致:
- 安全漏洞(如 XSS、CSRF 攻击)
- 不良用户体验(如频繁重新登录)
- 应用功能限制(如多标签页同步问题)
什么是XSS攻击?
全称:Cross-Site Scripting(跨站脚本攻击)
坏人把恶意代码(比如偷cookie的脚本)塞进网页,别人一打开网页就中招,相当于"网页里藏毒"。
一句话说就是坏人利用用户对网站的信任(恶意代码在网页里执行)。
什么是CSRF攻击?Cross-Site Request Forgery(跨站请求伪造)(虽然XSS本该缩写是CSS,但为了和层叠样式表区分,改叫XSS)
坏人诱导你点链接/图,偷偷用你的登录状态发恶意请求(比如转账),相当于"冒充你的身份干坏事"。
一句话说就是坏人利用网站对用户浏览器的信任(伪造你的身份发请求)。
二、主要 token 存储方案及比较
1. LocalStorage
实现方式:
javascript
// 存储
localStorage.setItem('auth_token', token);
// 读取
const token = localStorage.getItem('auth_token');
// 删除
localStorage.removeItem('auth_token');
优势:
- 简单易用,API 直接
- 持久化存储,浏览器关闭后仍然存在
- 容量较大(通常 5MB+)
劣势:
- 易受 XSS 攻击:任何注入页面的恶意 JavaScript 都能读取
- 无法自动随请求发送,需手动添加到请求头
- 同源策略限制,子域名间不共享
适用场景:快速原型开发、对安全性要求不高的内部应用
2. SessionStorage
实现方式:
javascript
// 存储
sessionStorage.setItem('auth_token', token);
// 读取
const token = sessionStorage.getItem('auth_token');
// 删除
sessionStorage.removeItem('auth_token');
优势:
- 会话级存储,关闭标签页后自动清除
- 同样简单易用的 API
- 比 cookies 更大的存储空间
劣势:
- 同样易受 XSS 攻击(没错,又是它)
- 多标签页间不共享(可能造成重复登录)
- 刷新页面会保留,但关闭标签页即清除
适用场景 :单标签页应用、高度敏感数据的临时存储
3. Cookies(HttpOnly + Secure)
补充
HttpOnly:阻止 JavaScript 访问 Cookie,有效防御 XSS 攻击窃取敏感信息。
Secure:仅允许通过 HTTPS 传输,防止中间人攻击(MITM)窃取 Cookie。
什么**中间人【Man-in-the-Middle Attack】*攻击? 简单说就是黑客在通信双方之间拦截或篡改数据,窃取敏感信息(如密码、Cookie)的攻击方式。此处不展开。
Express 服务器端设置:
javascript
res.cookie('auth_token', token, {
httpOnly: true,
secure: true, // 仅 HTTPS
sameSite: 'strict', // 防止 CSRF
maxAge: 24 * 60 * 60 * 1000 // 1天
});
优势:
- 防 XSS :
httpOnly
使 JavaScript 无法读取 - 防 CSRF :配合
sameSite
属性 - 自动随请求发送,无需手动处理
- 可设置过期时间
劣势:
- 存储空间有限(约 4KB 每个 cookie,50 个左右/域名)
- 需要服务器端配合设置
- 每个请求都会携带,可能增加带宽消耗
适用场景:安全性要求高的生产环境,特别是 SSR 应用
4. Cookies(可被 JavaScript 读取)
Cookie简介: Cookie 是网站在用户浏览器中存储 的一小段数据(通常不超过 4KB ),用于跟踪用户会话、存储用户偏好或身份验证令牌 等。它由服务器通过 HTTP 响应头(
Set-Cookie
)发送给浏览器,之后浏览器会在每次请求中自动携带 Cookie(通过Cookie
请求头)发送回服务器。
实现方式:
javascript
// 使用 js-cookie 库
Cookies.set('auth_token', token, { secure: true, sameSite: 'strict' });
const token = Cookies.get('auth_token');
优势:
- 比 localStorage 稍安全(可设置 secure 和 sameSite)
- 自动过期管理
- 可跨子域名共享(通过 domain 设置)
劣势:
- 仍然可能被 XSS 读取
- 有存储空间限制
适用场景:需要子域名共享 token 且信任子域环境的场景
5. 内存存储
关键词:最安全的一种方式
为什么?
🍭因为 Token 只存在内存中,关闭页面就消失,完全不留痕迹,彻底杜绝持久化攻击风险。
Vue 实现:
javascript
// 在 Vuex/Pinia 中
const authStore = useAuthStore();
authStore.setToken(token);
// 或简单变量
let inMemoryToken = null;
优势:
- 最安全:完全不被持久化,关闭页面即消失
- 不受存储限制
- 无 XSS 持久化风险
劣势:
- 页面刷新即丢失,需重新认证
- 多标签页间不共享
- 需配合其他持久化方案使用
适用场景:极高安全要求的金融/医疗应用,通常配合短期 token 使用
6. IndexedDB
关键词:大容量!
IndexedDB 是浏览器提供的一种底层 NoSQL 数据库,允许网页应用大规模(通常 50MB+)存储结构化数据,支持异步高性能检索,适合离线 Web 应用存储复杂数据。
实现方式:
javascript
/* 前端代码中使用 */
// 使用 idb 库简化操作
const db = await openDB('authDB', 1, {
upgrade(db) {
db.createObjectStore('tokens');
}
});
await db.put('tokens', token, 'auth_token');
const token = await db.get('tokens', 'auth_token');
优势:
- 大容量存储(通常 50MB+)
- 异步操作,不阻塞 UI
- 可加密存储(配合 Web Crypto API)
劣势:
- 仍然可能被 XSS 读取
- API 较复杂
- 老旧浏览器支持有限
适用场景 :需要存储大容量认证数据或加密需求的复杂应用
三、决策流程图
下方的流程图可以作为后续开发的一个方案选择思路
markdown
是否需要自动随请求发送?
├─ 是 → 使用 Cookies
│ ├─ 需要防 XSS? → HttpOnly + Secure
│ └─ 需要 JS 读取? → 常规 Cookie + sameSite
└─ 否 →
├─ 需要持久化?
│ ├─ 是 → LocalStorage 或 IndexedDB
│ └─ 否 → 内存存储
└─ 需要最高安全性? → 内存存储 + 短期 token
✍️最后
技术的多 不应该成为程序员的负担
技术多代表的,可供选择的一个个方案
而不是技术的枷锁
先写一个Demo
再去慢慢优化它吧
而不是被繁杂的技术吓住
很希望自己这句话能被年轻的我看到
不多说了
收摊!