本地存储与 Cookie

我想通过将所有 Cookie 移到本地存储中来减少其加载时间,因为它们似乎具有相同的功能。除了明显的兼容性问题以外,使用本地存储替换 cookie 功能是否有任何利弊(尤其是性能方面的优势)?

答案

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

如果它是您的客户端(您的 JavaScript),则一定要切换。通过在每个 HTTP 标头中发送所有数据来浪费带宽。

如果是您的服务器,则本地存储不是那么有用,因为您必须沿某种方式转发数据(使用 Ajax 或隐藏的表单字段等)。如果服务器仅需要每个请求的全部数据的一小部分,则可以这样做。

无论哪种方式,您都希望将会话 cookie 保留为 cookie。

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

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

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

在 JWT 的上下文中 ,Stormpath 写了一篇相当有帮助的文章,概述了存储它们的可能方法以及与每种方法有关的(缺点)优点。

它还简要概述了 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 存储在传输期间不会强制执行任何安全标准。读取并使用 Web 存储的任何人都必须进行尽职调查,以确保他们始终通过 HTTPS 发送 JWT,而不是通过 HTTP 发送 JWT。

饼干

问题:

与 HttpOnly cookie 标志一起使用时,cookie 无法通过 JavaScript 访问,并且不受 XSS 的影响。您还可以设置安全 cookie 标志,以确保仅通过 HTTPS 发送 cookie。这是过去曾经利用 cookie 来存储令牌或会话数据的主要原因之一。现代开发人员不愿使用 Cookie,因为传统上他们要求将状态存储在服务器上,从而破坏了 RESTful 最佳实践。如果将 JWT 存储在 cookie 中,则 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 保护xsrfToken无状态:

{
  "iss": "http://galaxies.com",
  "exp": 1300819380,
  "scopes": ["explorer", "solar-harvester", "seller"],
  "sub": "tom@andromeda.com",
  "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/

/* 
* 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
}

好吧,本地存储速度很大程度上取决于客户端使用的浏览器以及操作系统。 Mac 上的 Chrome 或 Safari 可能比 PC 上的 Firefox 快得多,尤其是使用较新的 API 时。与往常一样,测试是您的朋友(我找不到任何基准)。

我真的没有看到 Cookie 与本地存储的巨大差异。另外,您应该更加担心兼容性问题:并不是所有的浏览器都已经开始支持新的 HTML5 API,因此 cookie 是提高速度和兼容性的最佳选择。

还值得一提的是,当用户在某些版本的移动 Safari 中以 “私有” 模式浏览时,不能使用localStorage

引用自 MDN( https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage ):

注意:从 iOS 5.1 开始,Safari Mobile 会根据操作系统的要求(通常是在空间不足的情况下)将 localStorage 数据存储在缓存文件夹中,该文件夹有时会被清理。 Safari Mobile 的 “私有浏览” 模式还阻止了完全写入 localStorage。

本地存储最多可以存储 5mb 的脱机数据,而会话最多也可以存储 5mb 的数据。但是 Cookie 只能以文本格式存储 4kb 数据。

LOCA1 和 Session 以 JSON 格式存储数据,因此易于解析。但是 Cookies 数据是字符串格式。

饼干

1 在 HTML5 之前引入。

2 具有到期日期。

通过 JS 或浏览器的清除浏览数据或在到期日期之后进行 3-Cleard。

每个请求将 4 - 发送到服务器。

5 - 容量为 4KB。

仅 6 个字符串可以存储在 cookie 中。

7-Cookie 分为两种:持久性和会话性。

本地存储:

1-HTML5 引入。

2 - 没有到期日期。

通过 JS 或浏览器的清除浏览数据进行 3-Cleard。

4 - 您可以选择何时必须将数据发送到服务器。

5 - 容量为 5MB。

6 字符串,JavaScript 原语和对象都可以存储在其中。

7 - 只有一种类型。