协慌网

登录 贡献 社区

本地存储与 Cookie

我希望通过将所有 cookie 移动到本地存储来减少我的网站上的加载时间,因为它们似乎具有相同的功能。除了明显的兼容性问题之外,使用本地存储替换 cookie 功能是否有任何优点 / 缺点(特别是在性能方面)?

答案

Cookie 和本地存储有不同的用途。 Cookie 主要用于读取服务器端 ,本地存储只能由客户端读取。所以问题是,在你的应用程序中,谁需要这些数据 - 客户端还是服务器?

如果它是您的客户端(您的 JavaScript),那么无论如何切换。您通过发送每个 HTTP 标头中的所有数据来浪费带宽。

如果它是您的服务器,本地存储不是那么有用,因为您必须以某种方式转发数据(使用 Ajax 或隐藏的表单字段或其他内容)。如果服务器只需要每个请求的总数据的一小部分,那么这可能没问题。

不管怎样,您都希望将会话 cookie 保留为 cookie。

根据技术差异,以及我的理解:

  1. 除了作为一种保存数据的旧方法之外,Cookies 还为您提供了4096字节(实际为 4095 字节)的限制 - 每个 cookie。本地存储每个域大到5MB - SO 问题也提到了它

  2. localStorageStorage接口的实现。它存储的数据没有过期日期只能通过 JavaScript 清除,或清除浏览器缓存 / 本地存储的数据 - 与 cookie 过期不同。

在 JWT 的背景下 ,Stormpath 撰写了一篇相当有用的文章,概述了存储它们的可能方法,以及与每种方法相关的(dis-)优势。

它还简要概述了 XSS 和 CSRF 攻击,以及如何对抗它们。

我附上了以下文章的一些简短片段,以防他们的文章脱机 / 他们的网站出现故障。

本地存储

问题:

Web 存储(localStorage / sessionStorage)可通过同一域上的 JavaScript 访问。这意味着您站点上运行的任何 JavaScript 都可以访问 Web 存储,因此可能容易受到跨站点脚本(XSS)攻击。简而言之,XSS 是一种漏洞,攻击者可以在其中注入将在您的页面上运行的 JavaScript。基本的 XSS 攻击试图通过表单输入注入 JavaScript,攻击者在其中发出警报('你被黑了'); 进入表单以查看它是否由浏览器运行并且可以被其他用户查看。

预防:

为了防止 XSS,常见的响应是转义并编码所有不受信任的数据。但这远不是完整的故事。 2015 年,现代网络应用程序使用托管在 CDN 或外部基础架构上的 JavaScript。现代网络应用程序包括用于 A / B 测试的第三方 JavaScript 库,漏斗 / 市场分析和广告。我们使用像 Bower 这样的包管理器将其他人的代码导入我们的应用程序。

如果您使用的其中一个脚本遭到入侵,该怎么办?恶意 JavaScript 可以嵌入到页面中,并且 Web 存储会受到损害。这些类型的 XSS 攻击可以让每个人在不知情的情况下访问您的网站。这可能是为什么一群组织建议不要存储任何有价值的东西或信任网络存储中的任何信息。这包括会话标识符和令牌。

作为存储机制,Web 存储在传输过程中不会强制执行任何安全标准。无论谁阅读 Web 存储并使用它,都必须尽职尽责,以确保他们始终通过 HTTPS 发送 JWT,而不是 HTTP。

饼干

问题:

当与 HttpOnly cookie 标志一起使用时,Cookie 无法通过 JavaScript 访问,并且不受 XSS 的影响。您还可以设置安全 cookie 标记以保证 cookie 仅通过 HTTPS 发送。这是过去利用 cookie 来存储令牌或会话数据的主要原因之一。现代开发人员对使用 cookie 犹豫不决,因为他们传统上需要将状态存储在服务器上,因此破坏了 RESTful 最佳实践。如果要在 cookie 中存储 JWT,作为存储机制的 Cookie 不需要将状态存储在服务器上。这是因为 JWT 封装了服务器为请求提供服务所需的一切。

但是,cookie 容易受到不同类型的攻击:跨站点请求伪造(CSRF)。 CSRF 攻击是一种攻击,当恶意网站,电子邮件或博客导致用户的 Web 浏览器在用户当前已对其进行身份验证的受信任站点上执行不需要的操作时,就会发生此类攻击。这是对浏览器处理 cookie 的方式的一种利用。 Cookie 只能发送到允许它的域。默认情况下,这是最初设置 cookie 的域。无论您是在 galaxies.com 还是 hahagonnahackyou.com,都会发送 cookie 以获取请求。

预防:

可以使用同步令牌模式来防止 CSRF。这听起来很复杂,但所有现代 Web 框架都支持这一点。

例如,AngularJS 有一个解决方案来验证 cookie 只能由您的域访问。直接来自 AngularJS 文档:

执行 XHR 请求时,$ http 服务从 cookie(默认情况下为 XSRF-TOKEN)读取令牌并将其设置为 HTTP 头(X-XSRF-TOKEN)。由于只有在您的域上运行的 JavaScript 才能读取 cookie,因此您的服务器可以确保 XHR 来自您域上运行的 JavaScript。您可以通过包含xsrfToken JWT 声明来使此 CSRF 保护无状态:

{
  "iss": "http://galaxies.com",
  "exp": 1300819380,
  "scopes": ["explorer", "solar-harvester", "seller"],
  "sub": "[email protected]",
  "xsrfToken": "d9b9714c-7ac0-42e0-8696-2dae95dbc33e"
}

利用您的 Web 应用程序框架的 CSRF 保护,使得 cookie 可以用于存储 JWT。通过检查 API 中的 HTTP Referer 和 Origin 标头,也可以部分阻止 CSRF。 CSRF 攻击将具有与您的应用程序无关的 Referer 和 Origin 标头。

完整的文章可以在这里找到: https//stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/

他们还有一篇关于如何最好地设计和实现 JWT 的文章,关于令牌本身的结构: https ://stormpath.com/blog/jwt-the-right-way/

使用localStorage ,Web 应用程序可以在用户的浏览器中本地存储数据。在 HTML5 之前,应用程序数据必须存储在 cookie 中,包含在每个服务器请求中。可以在本地存储大量数据,而不会影响网站性能。虽然localStorage更现代,但这两种技术都有一些优点和缺点。

饼干

优点

  • 遗产支持(它一直存在)
  • 持久数据
  • 到期日期

缺点

  • 每个域将其所有 cookie 存储在一个字符串中,这可能使解析数据变得困难
  • 数据未加密,这成为一个问题,因为...... 虽然规模很小,但每次 HTTP 请求都会发送 cookie 限制大小(4KB)
  • 可以从 cookie 执行 SQL 注入

本地存储

优点

  • 大多数现代浏览器支持
  • 直接存储在浏览器中的持久数据
  • 同源规则适用于本地存储数据
  • 不会随每个 HTTP 请求一起发送
  • 每个域约 5MB 存储空间(即 5120KB)

缺点

  • 以前没有任何支持:IE 8,Firefox 3.5,Safari 4,Chrome 4,Opera 10.5,iOS 2.0,Android 2.0
  • 如果服务器需要存储客户端信息,则您必须发送它。

localStorage使用与会话几乎完全相同。他们有非常精确的方法,所以从 session 到localStorage转换真的是孩子的游戏。但是,如果存储的数据对您的应用程序非常重要,那么您可能会使用 cookie 作为备份,以防localStorage不可用。如果要检查对localStorage浏览器支持,您只需运行这个简单的脚本:

/* 
* function body that test if storage is available
* returns true if localStorage is available and false if it's not
*/
function lsTest(){
    var test = 'test';
    try {
        localStorage.setItem(test, test);
        localStorage.removeItem(test);
        return true;
    } catch(e) {
        return false;
    }
}

/* 
* execute Test and run our custom script 
*/
if(lsTest()) {
    // window.sessionStorage.setItem(name, 1); // session and storage methods are very similar
    window.localStorage.setItem(name, 1);
    console.log('localStorage where used'); // log
} else {
    document.cookie="name=1; expires=Mon, 28 Mar 2016 12:00:00 UTC";
    console.log('Cookie where used'); // log
}

“安全(SSL)页面上的 localStorage 值是孤立的”正如有人注意到的那样,请记住,如果您从'http' 切换到'https' 安全协议,localStorage 将无法使用,其中 cookie 仍然是可访问的。如果您使用安全协议,这一点很重要。