Storage Access API

Chrome 正在取消对第三方 Cookie 的支持,以减少跨网站跟踪。对于依赖嵌入式上下文中的 Cookie 的网站和服务,这给身份验证等用户体验历程带来了挑战。Storage Access API (SAA) 可让这些用例继续正常运行,同时尽可能限制跨网站跟踪。

实现状态

浏览器支持

  • 119
  • 85
  • 65
  • 11.1

来源

Storage Access API 适用于所有主流浏览器,但各个浏览器之间存在细微的实现差异。这些差异已在本文的相关部分重点介绍。

实现 API 标准化之前,我们会继续努力解决所有剩余的阻碍性问题

什么是 Storage Access API?

Storage Access API 是一种 JavaScript API,可让 iframe 在浏览器设置拒绝访问时请求存储访问权限。如果嵌入的用例依赖于加载跨网站资源,则可以根据需要使用该 API 向用户请求访问权限。

获准存储请求后,iframe 将能访问其跨网站 Cookie,用户将其作为顶级网站访问时,也可以使用这些 Cookie。

借助 Storage Access API,您能够以尽可能少的负担向最终用户提供特定的跨网站 Cookie 访问,同时仍可阻止常规的跨网站 Cookie 访问(像通常用于用户跟踪一样)。

用例

某些第三方嵌入需要访问跨网站 Cookie,以便为用户提供更好的体验,而这在第三方 Cookie 被弃用后将无法使用。

用例包括:

  • 需要登录会话详细信息的嵌入式评论 widget。
  • 需要登录会话详细信息的社交媒体“赞”按钮。
  • 需要登录会话详细信息的嵌入式文档。
  • 为嵌入视频而提供的优质体验(例如,不向已登录的用户展示广告,或者了解用户对字幕的偏好或限制某些视频类型)。
  • 嵌入式支付系统。

以下许多用例都涉及在嵌入式 iframe 中持久保留登录访问权限。

何时使用 Storage Access API 而非其他 API

Storage Access API 是使用第三方 Cookie 的替代方案之一,因此请务必了解何时使用此 API(与其他 API 相比)。它适用于同时满足以下两个条件的用例:

  • 用户会与嵌入的内容互动,也就是说,它不是被动 iframe 或隐藏 iframe。
  • 用户已在顶级上下文中访问嵌入的源,即该源未嵌入到其他网站时。

还有适用于各种应用场景的替代 API:

  • 借助具有独立分区状态的 Cookie (CHIPS),开发者可以选择将 Cookie 用于“分区”存储,并为每个顶级网站使用单独的 Cookie jar。例如,第三方网络聊天微件可能依靠设置 Cookie 来保存会话信息。会话信息是按网站保存的,因此无需在嵌入了该微件的其他网站上也能访问由微件设置的 Cookie。如果嵌入式第三方 widget 需要跨不同源共享相同的信息(例如,用于登录会话详细信息或偏好设置),则 Storage Access API 非常有用。
  • Related Websites Set (RWS) 可让组织声明网站之间的关系,以便浏览器允许出于特定目的访问有限的第三方 Cookie。网站仍需通过 Storage Access API 请求访问权限,但对于集合中的网站,无需用户提示即可授予访问权限。
  • 联合凭据管理 (FedCM) 是一种用于联合身份服务的隐私保护方法。Storage Access API 用于处理登录后访问 Cookie。对于某些用例,FedCM 提供了 Storage Access API 的替代解决方案,这可能是可取的,因为它具有更面向登录的浏览器提示。但是,采用 FedCM 通常需要对代码进行额外更改,例如支持其 HTTP 端点。
  • 此外,还存在防欺诈广告相关衡量 API,Storage Access API 无意解决此类问题。

使用 Storage Access API

Storage Access API 有两种基于 promise 的方法:

它还与 Permissions API 集成。这样,您就可以在第三方上下文中检查存储空间访问权限的状态,该状态会指示是否会自动授予对 document.requestStorageAccess() 的调用:

使用 hasStorageAccess() 方法

网站首次加载时,可以使用 hasStorageAccess() 方法检查是否已获得对第三方 Cookie 的访问权限。

// Set a hasAccess boolean variable which defaults to false.
let hasAccess = false;

async function handleCookieAccessInit() {
  if (!document.hasStorageAccess) {
    // Storage Access API is not supported so best we can do is
    // hope it's an older browser that doesn't block 3P cookies.
    hasAccess = true;
  } else {
    // Check whether access has been granted via the Storage Access API.
    // Note on page load this will always be false initially so we could be
    // skipped in this example, but including for completeness for when this
    // is not so obvious.
    hasAccess = await document.hasStorageAccess();
    if (!hasAccess) {
      // Handle the lack of access (covered later)
    }
  }
  if (hasAccess) {
    // Use the cookies.
  }
}
handleCookieAccessInit();

只有在 iframe 文档调用 requestStorageAccess(), 后,系统才会向其授予存储空间访问权限,因此 hasStorageAccess() 最初将始终返回 false,除非已经向同一 iframe 中的其他同源文档授予访问权限。在 iframe 内的同源导航过程中,授权将保留,特别是在对要求在 HTML 文档初始请求中存在 Cookie 的网页授予访问权限后,允许重新加载。

使用 requestStorageAccess() 方法

如果 iframe 没有访问权限,可能需要使用 requestStorageAccess() 方法请求访问权限:

if (!hasAccess) {
  try {
    await document.requestStorageAccess();
  } catch (err) {
    // Access was not granted and it may be gated behind an interaction
    return;
  }
}

首次请求此请求时,用户可能需要通过浏览器提示批准此访问权限,之后 promise 将解析或拒绝,这会导致出现异常(如果使用了 await)。

为防止滥用行为,此浏览器提示仅在用户互动后显示。因此,最开始需要从用户激活的事件处理脚本调用 requestStorageAccess(),而不是在 iframe 加载时立即调用:

async function doClick() {

  // Only do this extra check if access hasn't already been given
  // based on the hasAccess variable.
  if (!hasAccess) {
    try {
      await document.requestStorageAccess();
      hasAccess = true; // Can assume this was true if above did not reject.
    } catch (err) {
      // Access was not granted.
      return;
    }
  }

  if (hasAccess) {
    // Use the cookies
  }
}

document.querySelector('#my-button').addEventListener('click', doClick);

权限提示

当用户首次点击该按钮时,系统会自动显示浏览器提示(通常显示在地址栏中)。以下是 Chrome 的提示示例,但其他浏览器具有类似的界面:

Chrome Storage Access API 权限提示的屏幕截图
Chrome 的 Storage Access API 权限提示

在某些情况下,浏览器可能会跳过提示,并会自动提供权限:

  • 在接受提示后的 30 天内,网页和 iframe 是否使用过。
  • 嵌入式 iframe 是否是 Related Website Set 的一部分。
  • 在 Firefox 中,对于已知的网站(您在顶级进行过互动的网站),在前五次尝试中也会跳过该提示。

或者,在某些情况下,系统可能会自动拒绝该方法而不显示提示:

  • 如果用户之前没有访问过将 iframe 作为顶级文档(而不是在 iframe 中)的网站,并且与该网站互动过。这意味着,Storage Access API 仅适用于用户之前在第一方环境中访问过的嵌入式网站。
  • 在用户互动事件之外调用 requestStorageAccess() 方法时,在互动后未经提示事先批准。

虽然系统会在用户首次使用时提示用户,但后续访问可在不提示用户的情况下解析 requestStorageAccess(),且无需用户在 Chrome 和 Firefox 中互动。请注意,Safari 始终需要用户互动。

由于 Cookie 访问权限可能会在无需提示或无需用户互动的情况下被授予,通常可以通过在网页加载时调用 requestStorageAccess(),在支持第三方 Cookie 访问权限的浏览器(Chrome 和 Firefox)上与用户发生互动之前获得第三方 Cookie 访问权限。这样一来,您甚至可以在用户与 iframe 互动之前,立即访问第三方跨网站 Cookie 并提供更全面的体验。相较于等待用户互动,在某些情况下,这样做可以提供更好的用户体验。

使用 storage-access 权限查询

如需检查是否可以在没有用户互动的情况下授予访问权限,您可以检查 storage-access 权限的状态,仅在不需要用户操作时提前调用 requestStoreAccess(),而不是在需要互动时调用该权限并使其失败。

这样,您还可以通过显示不同的内容(例如登录按钮)来预先满足对提示的需求。

以下代码将在前面的示例中添加 storage-access 权限检查:

// Set a hasAccess boolean variable which defaults to false except for
// browsers which don't support the API - where we assume
// such browsers also don't block third-party cookies.
let hasAccess = false;

async function hasCookieAccess() {
  // Check if Storage Access API is supported
  if (!document.requestStorageAccess) {
    // Storage Access API is not supported so best we can do is
    // hope it's an older browser that doesn't block 3P cookies.
    return true;
  }

  // Check if access has already been granted
  if (await document.hasStorageAccess()) {
    return true;
  }

  // Check the storage-access permission
  // Wrap this in a try/catch for browsers that support the
  // Storage Access API but not this permission check
  // (e.g. Safari and older versions of Firefox).
  let permission;
  try {
    permission = await navigator.permissions.query(
      {name: 'storage-access'}
    );
  } catch (error) {
    // storage-access permission not supported. Assume no cookie access.
    return false;
  }

    if (permission) {
    if (permission.state === 'granted') {
      // Permission has previously been granted so can just call
      // requestStorageAccess() without a user interaction and
      // it will resolve automatically.
      try {
        await document.requestStorageAccess();
        return true;
      } catch (error) {
        // This shouldn't really fail if access is granted, but return false
        // if it does.
        return false;
      }
    } else if (permission.state === 'prompt') {
      // Need to call requestStorageAccess() after a user interaction
      // (potentially with a prompt). Can't do anything further here,
      // so handle this in the click handler.
      return false;
          } else if (permission.state === 'denied') {
            // Currently not used. See:
      // https://github.com/privacycg/storage-access/issues/149
      return false;
          }
    }

  // By default return false, though should really be caught by one of above.
  return false;
}

async function handleCookieAccessInit() {
  hasAccess = await hasCookieAccess();

  if (hasAccess) {
    // Use the cookies.
  }
}

handleCookieAccessInit();

沙盒化 iframe

沙盒化 iframe 中使用 Storage Access API 时,需要以下沙盒权限:

  • 必须具备 allow-storage-access-by-user-activation 才能允许访问 Storage Access API。
  • 必须具备 allow-scripts 才能允许使用 JavaScript 调用该 API。
  • 如需允许访问同源 Cookie 和其他存储空间,则必须提供 allow-same-origin

例如:

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

要在 Chrome 中通过 Storage Access API 进行访问,必须使用以下两个属性设置跨网站 Cookie:

  • SameSite=None - 将 Cookie 标记为跨网站所必需的属性
  • Secure - 用于确保只能访问由 HTTPS 网站设置的 Cookie。

在 Firefox 和 Safari 中,Cookie 默认为 SameSite=None。它们不会将 SSA 限制为 Secure Cookie,因此这些属性不是必需的。建议您明确指定 SameSite 属性并始终使用 Secure Cookie。

顶级网页访问权限

Storage Access API 旨在实现对嵌入式 iframe 中的第三方 Cookie 的访问权限。

另外,还有一些其他用例,即顶级网页需要访问第三方 Cookie。例如,受 Cookie 限制的图片或脚本,网站所有者可能希望将其直接包含在顶级文档中,而不是包含在 iframe 中。为了应对这种使用情形,Chrome 提议了 Storage Access API 扩展程序,其中添加了 requestStorageAccessFor() 方法。

requestStorageAccessFor() 方法

浏览器支持

  • 119
  • 119
  • x
  • x

来源

requestStorageAccessFor() 方法的工作方式与 requestStorageAccess() 类似,但适用于顶级资源。它只能用于 Related Website Set 中的网站,以防止授予对第三方 Cookie 的常规访问权限。

如需详细了解如何使用 requestStorageAccessFor(),请参阅 Related Website Set:开发者指南

top-level-storage-access 权限查询

浏览器支持

  • 119
  • 119
  • x
  • x

storage-access 权限类似,此 API 也具有 top-level-storage-access 权限,用于检查是否可以为 requestStorageAccessFor() 授予访问权限。

与 RWS 搭配使用的 Storage Access API 有何不同?

将 Related Website Set 与 Storage Access API 搭配使用时,您还可以使用下表中详细介绍的某些其他功能:

不使用 RWS 带 RWS 功能
需要用户通过手势来发起存储空间访问权限请求
要求用户在授予访问权限之前在顶级上下文中访问请求的存储源
可以跳过首次的用户提示
如果之前已授予访问权限,则不需要调用 requestStorageAccess
自动授予对 Related Website 网站中其他网域的访问权限
支持使用 requestStorageAccessFor 进行顶级页面访问
不搭配 Related Website Set 使用 Storage Access API 与使用 Related Website Set 的使用有何区别

演示:设置和访问 Cookie

以下演示显示了如何通过演示的第二个网站的嵌入式框架访问您在演示第一个屏幕中设置的 Cookie:

storage-access-api-demo.glitch.me

此演示需要使用已停用第三方 Cookie 的浏览器:

  • 设置了 chrome://flags/#test-third-party-cookie-phaseout 标志的 Chrome 118 或更高版本,并重启了浏览器。
  • Firefox
  • Safari

资源