Cookies vs localStorage vs sessionStorage:选择客户端存储
在构建 Web 应用程序时,您通常需要在客户端存储数据——无论是用户的主题偏好、购物车还是身份验证令牌。三种主要的选择是 cookies、localStorage 和 sessionStorage。每种都有其独特的特性,适用于不同的场景。选择错误可能导致安全漏洞、性能问题或糟糕的用户体验。
本文详细分析了它们之间的差异,提供了实用指南,并帮助您为下一个项目决定使用哪种存储机制。
快速比较
在深入细节之前,这里有一个关于这三种存储类型的高层次概述:
| 特性 | Cookies | localStorage | sessionStorage |
|---|---|---|---|
| 容量 | 每个域约 4KB | 每个源约 5-10MB | 每个源约 5-10MB |
| 持久性 | 可配置的过期时间 | 直到显式清除 | 直到标签页/窗口关闭 |
| 发送到服务器 | 自动随每个 HTTP 请求发送 | 否 | 否 |
| 可通过 JavaScript 访问 | 是(除非设置了 HttpOnly) | 是 | 是 |
| 作用域 | 域和路径 | 源(协议 + 域 + 端口) | 源 + 标签页/窗口 |
| 易受 XSS 攻击 | 是(如果未设置 HttpOnly) | 是 | 是 |
| 易受 CSRF 攻击 | 是(如果用于身份验证) | 否 | 否 |
Cookies:最早的客户端存储
Cookies 自 Web 早期就已存在。它们是浏览器存储的小块数据(最大约 4KB),并自动随每个对同一域的 HTTP 请求发送到服务器。
何时使用 Cookies
- 身份验证会话:存储服务器需要验证每个请求的会话 ID 或令牌。使用
HttpOnly、Secure和SameSite标志来降低 XSS 和 CSRF 风险。 - 服务器端个性化:当服务器在渲染页面之前必须知道用户偏好(例如语言、主题)时。
- 跟踪和分析:如果配置得当,Cookies 可以跨会话持久存在并跨子域共享。
安全考虑
Cookies 会自动发送,因此如果在没有额外保护的情况下用于身份验证,它们容易受到 CSRF 攻击。始终设置 SameSite 属性(Lax 或 Strict),并考虑使用 CSRF 令牌。对于敏感数据,使用 HttpOnly 来阻止 JavaScript 访问,从而减少 XSS 影响。
在 HTTP 响应中设置安全 cookie 的示例:
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600
localStorage:持久的键值存储
localStorage 提供了一个简单的键值存储,即使浏览器关闭后数据仍然存在。数据按源(协议 + 域 + 端口)存储,不会自动发送到服务器。它非常适合存储应在页面刷新和浏览器重启后仍然保留的非敏感数据。
何时使用 localStorage
- 用户偏好:主题(深色/浅色)、字体大小、语言或布局设置。
- 缓存:存储 API 响应或静态数据,以减少网络请求并改善离线体验。
- 客户端状态:购物车内容、草稿表单数据或功能标志。
安全考虑
localStorage 可通过 JavaScript 访问,因此任何 XSS 漏洞都可能暴露所有存储的数据。除非有强大的 XSS 防护措施,否则切勿存储密码、个人识别号码或身份验证令牌等敏感信息。如果必须存储令牌,请考虑使用 HttpOnly cookie 方法。
使用 localStorage 的示例:
// 保存用户偏好
localStorage.setItem('theme', 'dark');
// 检索偏好
const theme = localStorage.getItem('theme');
// 移除项
localStorage.removeItem('theme');
sessionStorage:按标签页存储
sessionStorage 与 localStorage 类似,但生命周期更短:当标签页或窗口关闭时,数据会被清除。它的作用域仅限于单个标签页,因此即使对于同一源,数据也不会在标签页或窗口之间共享。
何时使用 sessionStorage
- 多步骤表单:在用户逐步填写时临时存储表单数据,完成后不持久保留。
- 单标签页状态:不应在标签页之间泄露的数据,例如临时身份验证状态或一次性令牌。
- 敏感操作:当您希望用户关闭标签页时自动清除数据,以减少暴露。
安全考虑
与 localStorage 一样,sessionStorage 也容易受到 XSS 攻击。然而,其有限的生命周期和按标签页的作用域减少了攻击者的机会窗口。尽管如此,仍应避免存储高度敏感的数据。
使用 sessionStorage 的示例:
// 保存表单数据
sessionStorage.setItem('formStep1', JSON.stringify({name: 'John'}));
// 检索表单数据
const step1 = JSON.parse(sessionStorage.getItem('formStep1'));
如何选择:决策指南
使用以下有序列表来指导您的决策:
- 服务器是否需要在每个请求上读取数据?如果是,使用 cookies。示例:会话 ID。
- 数据是否需要跨浏览器会话持久存在?如果是,使用 localStorage。示例:用户偏好。
- 数据是否应仅限于单个标签页?如果是,使用 sessionStorage。示例:多步骤表单数据。
- 数据是否敏感?避免将其存储在 localStorage 或 sessionStorage 中。对于令牌使用 HttpOnly cookies,并且永远不要存储密码。
- 数据是否很大?Cookies 限制在约 4KB;localStorage 和 sessionStorage 提供更大的容量。
安全最佳实践
- 始终验证和清理输入以防止 XSS,XSS 可能危及任何客户端存储。
- 对身份验证令牌使用 HttpOnly、Secure 和 SameSite cookies以降低 XSS 和 CSRF 风险。
- 避免在 localStorage 或 sessionStorage 中存储敏感数据。如果必须,请加密并使用短过期时间。
- 实施内容安全策略(CSP)以降低 XSS 风险。
- 定期清除陈旧数据以避免达到存储限制并减少暴露。
常见问题
我可以使用 localStorage 存储身份验证令牌吗?
不推荐,因为 localStorage 可通过 JavaScript 访问,使令牌容易受到 XSS 攻击。优先使用带有 Secure 和 SameSite 标志的 HttpOnly cookies。
当我复制标签页时,sessionStorage 会发生什么?
当您复制标签页时,新标签页会在复制时获得原始标签页 sessionStorage 的副本。之后,它们就是独立的。
Cookies 是否会在每个请求上发送到服务器?
是的,当前域的 cookies 会自动包含在每个 HTTP 请求中,如果您存储太多数据,可能会影响性能。请谨慎使用。
需要快速格式化或验证您存储的 JSON 数据吗?试试我们的 JSON Formatter,在将 JSON 负载保存到客户端存储之前美化并调试它们。