Storage Access API - 提供跨源访问存储的方法

这是一个实验中的功能
此功能某些浏览器尚在开发中,请参考浏览器兼容性表格以得到在不同浏览器中适合使用的前缀。由于该功能对应的标准文档可能被重新修订,所以在未来版本的浏览器中该功能的语法和行为可能随之改变。

Storage Access API(存储访问 API)为嵌入的、跨源的内容提供了一种不受限制地访问存储的方法,而这些存储通常只有在第一方上下文中才能访问 (我们将其称为源的第一方存储)。

API 提供的方法允许嵌入式资源检查它们当前是否有权访问其第一方存储,并从用户代理请求访问其第一方存储。

概念和用法

大多数浏览器实施了许多存储访问策略,这些策略限制对嵌入式跨域资源的 Cookie 和站点数据的访问。 这些限制范围从为每个顶级源下的嵌入式资源提供唯一的存储空间到在第三方上下文中加载资源时彻底阻止存储访问。

围绕第三方 cookie 阻止策略的语义因浏览器而异,但核心功能是相似的:嵌入在第三方环境中的跨源资源无法访问与它们在第一方环境中加载时相同的 Cookie 和网站存储。

众所周知,这些 Cookie 阻止策略会破坏需要访问其第一方存储的嵌入式跨域内容。例如,联合登录通常需要访问存储在第一方存储中的身份验证 Cookie,并且如果这些 Cookie 不可用,则要求用户单独登录(或完全中断)每个站点。在中断的情况下,网站所有者经常鼓励用户将其网站作为例外添加,或者完全禁用该策略。因此,希望继续与嵌入式内容交互的用户被迫大大放松他们对从所有嵌入式来源加载的资源,以及可能跨所有网站加载的资源的阻止策略。

存储访问接口就是为了解决这个问题;嵌入的跨源内容可以通过 Document.requestStorageAccess() 方法逐个站点地请求对其第一方存储的无限制访问,并通过 Document.hasStorageAccess() 方法检查它是否已经拥有访问权限。

此外,出于安全原因,默认情况下无法授予沙箱中的 <iframe> 存储访问权限。因此,接口还增加了 allow-storage-access-by-user-activation 沙盒令牌。嵌入式网站需要加上此项才能让存储访问请求成功,同时加上 allow-scriptsallow-same-origin 才能调用接口,并在可以有 Cookie 的源中执行:

<iframe sandbox="allow-storage-access-by-user-activation
                 allow-scripts
                 allow-same-origin">
  ...
</iframe>

该 API 旨在当用户已表现出交互意图时才可使用。 这是通过以下约束强制执行的:

  • 除非嵌入的内容当前正在处理用户手势,例如轻触或点击,否则访问请求将被自动拒绝。这还可以防止页面上的嵌入内容向浏览器或用户发送过多的访问请求。
  • 从未作为第一方进行过交互的来源没有第一方存储的概念。从用户的角度来看,他们与该来源只有第三方关系。如果浏览器检测到用户最近没有与第一方上下文中的嵌入内容进行交互(在 Firefox 中,“最近”是 “30 天内”),访问请求会被自动拒绝。

浏览器可以决定让用户参与是否准许进入的存储访问请求的决定。关于存储授权的有效期以及浏览器可能决定通知用户的情况的细节目前正在处理中,一旦准备好,将立即公布。

用户提示

当嵌入的跨域文档调用 requestStorageAccess() 时,用户代理可以选择让用户参与决定是否授予对请求源的存储访问权限。目前,存储访问 API 的两个实现者的提示启发式方法各不相同 —— Safari 对所有先前未获得存储权限的嵌入式跟踪内容显示提示,而 Firefox 仅在跟踪源在超过阈值数量的网站上请求存储权限后才会提示用户。有关详细信息,请参阅 Document.requestStorageAccess()

Safari 实现的差异

尽管 API 表面是相同的,但使用 Storage Access API 的网站在 Firefox 和 Safari 之间接收的存储访问级别和范围应该有所不同。 这是由于两种浏览器中实现的存储访问策略的差异造成的。 Firefox 独有的设计属性总结如下:

  • 如果嵌入源点 tracker.example 已经获得了顶级源点 foo.example 的第一方存储访问权限,并且用户在不到 30 天的时间内再次访问 foo.example 嵌入 tracker.example 页面的页面,则该嵌入源点在加载时将立即获得存储访问权限。
  • 如果来自顶级源 foo.example 的页面嵌入了多个来自 tracker.example<iframe>,并且其中一个 <iframe> 使用存储访问 API 已成功获得存储访问权限,顶级源 foo.example 中的所有其他源为 tracker.example 的 iframe 也将立即获得存储访问权限,而无需单独调用 requestStorageAccess()
  • 如果 tracker.example 的嵌入页面之前已经成功获取了顶级源 foo.example 的存储访问权限,则 tracker.example 的所有嵌入子资源 (如脚本、图像、样式表等)。将加载对其第一方存储的访问权限,这意味着他们可以发送 Cookie 标头并接受传入的 Set-Cookie 标头。
  • 在 Firefox 中,当 requestStorageAccess() 返回的承诺被解析时,嵌入页面将获得对其整个第一方存储的访问权限,而不仅仅是 Cookie。包括访问Web StorageIndexedDBDOM 缓存等接口。
  • 在 Firefox 中,存储访问权限在 30 天后逐步取消,而在 Safari 中,存储访问权限会在浏览器使用 30 天且无用户交互后逐步取消。这是目前 Firefox 实现的一个限制,我们可能会在未来的版本中解决这个问题。在 Safari 中,成功使用存储访问 API 会重置此计数器。

Firefox 用于阻止跟踪 Cookie 的新存储访问策略的文档包括对存储访问授权范围的详细描述

存储访问 API 方法

存储 API 方法在 Document 接口上实现:

Document.hasStorageAccess()

返回一个 Promise,它解析为一个布尔值,该值指示文档是否有权访问其第一方存储。

Document.requestStorageAccess()

返回一个 Promise,它解析为是否授予对第一方存储的访问权限,如果访问被拒绝则返回拒绝。

注意: 用户的交互会传播到这两个方法返回的 Promise 中,允许调用者执行需要用户交互的操作,而无需用户再次单击。例如,调用者可以从已解析的承诺中打开弹出窗口,而不会触发 Firefox 的弹出窗口拦截程序。

<iframe> sandbox 沙箱的扩展

<iframe> 元素的 sandbox 属性有一个新的令牌, allow-storage-access-by-user-activation ,它允许沙箱中的 <iframe> 使用存储访问 API 来请求存储访问。

规范

API 目前仅处于提议阶段 -- 标准化进程尚未开始。您目前可以在苹果的介绍存储访问 API 博客文章,以及 WHATWG HTML 问题 3338 - 提议:存储访问 API 中找到该 API 的规范详细信息。

桌面浏览器兼容性

特性ChromeEdgeFirefoxInternet ExplorerOperaSafari
基础支持 不支持 不支持65 不支持 不支持11.1

移动浏览器兼容性

特性AndroidChrome for AndroidEdge mobileFirefox for AndroidIE mobileOpera AndroidiOS Safari
基础支持 不支持 不支持 未知65 未知 不支持11.3

桌面浏览器兼容性

特性ChromeEdgeFirefoxInternet ExplorerOperaSafari
基础支持 不支持 不支持65 不支持 不支持11.1

移动浏览器兼容性

特性AndroidChrome for AndroidEdge mobileFirefox for AndroidIE mobileOpera AndroidiOS Safari
基础支持 不支持 不支持 未知65 未知 不支持11.3

相关链接

使用存储访问 API