相关网站集:开发者指南

Related Website Set (RWS) 是一种网络平台机制,可帮助浏览器了解一组网域之间的关系。这样,浏览器就可以做出关键决策来启用某些网站功能(例如是否允许访问跨网站 Cookie),并向用户显示这些信息。

许多网站依靠多个网域来提供单一用户体验。组织可能希望为多种用例维护不同的顶级域名,例如面向特定国家/地区的域名或用于托管图片或视频的服务域名。借助 Related Website Set,网站可以通过特定控件跨网域共享数据。

概括来讲,相关网站集是指一组网域,其中包含一个“集主要网域”和可能多个“集成员”。

在以下示例中,primary 列出了主网域,associatedSites 列出了符合关联子集要求的网域。

{
  "primary": "https://primary.com",
  "associatedSites": ["https://associate1.com", "https://associate2.com", "https://associate3.com"]
}

相关网站集列在托管在 GitHub 上的公共 JSON 文件中。这是所有已获批准的集合的规范来源。浏览器会使用此文件来确定网站是否属于同一相关网站集。

只有对网域拥有管理控制权的用户才能使用该网域创建集。提交者必须声明每个“集成员”与其“集主键”之间的关系。集成员可以包含一系列不同的网域类型,并且必须属于基于用例的子集

如果您的应用依赖于对同一 Related Website Set 中各个网站上的跨网站 Cookie(也称为第三方 Cookie)的访问权限,您可以使用 Storage Access API (SAA)requestStorageAccessFor API 请求访问这些 Cookie。浏览器可能会根据每个网站所属的子集来处理请求。

如需详细了解提交套装的流程和要求,请参阅提交指南。提交的集合将接受各种技术检查,以验证提交内容。

如果组织需要在不同的顶级网站上使用某种共享身份,Related Website Set 非常适合。

Related Website Set 的一些用例包括:

  • 国家/地区自定义。利用本地化网站,同时依赖共享基础架构(example.co.uk 可能依赖 example.ca 托管的服务)。
  • 服务网域集成。利用用户从未直接与之互动,但在同一组织的网站上提供服务的服务网域(example-cdn.com)。
  • 用户内容分离。出于安全考虑,访问不同网域上的数据,以将用户上传的内容与其他网站内容分隔开来,同时允许沙盒化网域访问身份验证(和其他)Cookie。如果您要提供用户上传的非活跃内容,或许还可以遵循最佳实践,在同一网域中安全地托管这些内容。
    • 嵌入的经过身份验证的内容。支持来自各个联属媒体资源的嵌入内容(仅限于在顶级网站上登录的用户访问的视频、文档或资源)。
  • 登录。支持跨关联媒体资源登录。FedCM API 可能也适用于某些用例。
  • Google Cloud Analytics。在关联的媒体资源中部署分析和衡量用户转化历程,以提升服务质量。

Related Website Set 集成详情

Storage Access API

Browser Support

  • Chrome: 119.
  • Edge: 85.
  • Firefox: 65.
  • Safari: 11.1.

Source

Storage Access API (SAA) 提供了一种方法,可让嵌入式跨源内容访问通常只能在第一方环境中访问的存储空间。

嵌入式资源可以使用 SAA 方法检查它们当前是否有权访问存储空间,以及向用户代理请求访问权限。

当第三方 Cookie 被屏蔽但已启用相关网站集 (RWS) 时,Chrome 会在 RWS 内上下文中自动授予权限,否则会向用户显示提示。(“RWS 内上下文”是指嵌入式网站和顶级网站位于同一 RWS 中的上下文,例如 iframe。)

检查和请求存储空间访问权限

如需检查自己当前是否有权访问存储空间,嵌入式网站可以使用 Document.hasStorageAccess() 方法。

该方法会返回一个 promise,该 promise 会解析为一个布尔值,指示文档是否已拥有对其 Cookie 的访问权限。如果 iframe 与顶级帧具有相同的来源,该 promise 也会返回 true。

如需在跨网站环境中请求访问 Cookie,嵌入的网站可以使用 Document.requestStorageAccess() (rSA)。

requestStorageAccess() API 应从 iframe 内调用。该 iframe 必须刚刚收到用户互动(所有浏览器都要求执行此用户手势),但 Chrome 还要求用户在过去 30 天内的某个时间点访问过该 iframe 所属的网站,并且专门以顶级文档(而非 iframe)的形式与该网站互动过。

requestStorageAccess() 会返回一个 promise,该 promise 会在授予对存储空间的访问权限时解析。如果因任何原因被拒绝访问,系统会拒绝该 promise 并说明原因。

Chrome 中的 requestStorageAccessFor

Browser Support

  • Chrome: 119.
  • Edge: 119.
  • Firefox: not supported.
  • Safari: not supported.

Source

Storage Access API 仅允许嵌入的网站从已收到用户互动的 <iframe> 元素中请求存储空间访问权限。

这给采用 Storage Access API 的顶级网站带来了挑战,因为这些网站使用需要 Cookie 的跨网站图片或脚本标记。

为解决此问题,Chrome 实现了一种方法,可让顶级网站使用 Document.requestStorageAccessFor() (rSAFor) 代表特定来源请求存储空间访问权限。

 document.requestStorageAccessFor('https://target.site')

requestStorageAccessFor() API 应由顶级文档调用。该文档还必须刚刚收到用户互动。但与 requestStorageAccess() 不同,Chrome 不会检查用户是否在过去 30 天内与顶级文档互动过,因为用户已在该网页上。

检查存储空间访问权限

您可以根据用户授予的权限访问某些浏览器功能,例如相机或地理定位。Permissions API 提供了一种检查访问 API 的权限状态的方法,即权限是已授予、已拒绝,还是需要用户进行某种形式的互动(例如点击提示或与页面互动)。

您可以使用 navigator.permissions.query() 查询权限状态。

如需检查当前上下文的存储空间访问权限,您需要传入 'storage-access' 字符串:

navigator.permissions.query({name: 'storage-access'})

如需检查指定来源的存储空间访问权限,您需要传入 'top-level-storage-access' 字符串:

navigator.permissions.query({name: 'top-level-storage-access', requestedOrigin: 'https://target.site'})

请注意,为保护嵌入源的完整性,此操作仅会检查顶级文档使用 document.requestStorageAccessFor 授予的权限。

具体取决于权限能否自动授予或是否需要用户手势,它将返回 promptgranted

每帧模型

rSA 授予适用于每个。rSA 和 rSAFor 授予被视为单独的权限。

每个新帧都需要单独请求存储空间访问权限,系统会自动授予访问权限。只有第一个请求需要用户手势,iframe 发起的任何后续请求(例如导航或子资源)都无需等待用户手势,因为初始请求会为浏览会话授予该权限。

刷新、重新加载或以其他方式重新创建 iframe 都需要再次请求访问权限。

Cookie 必须同时指定 SameSite=NoneSecure 属性,因为 rSA 仅为已标记为在跨网站情境中使用的 Cookie 提供访问权限

具有 SameSite=LaxSameSite=Strict 或不含 SameSite 属性的 Cookie 仅供第一方使用,无论是否使用 RSA,都绝不会在跨网站上下文中共享。

安全

对于 rSAFor,子资源请求需要在资源上使用跨域资源共享 (CORS) 标头或 crossorigin 属性,以确保明确选择加入。

实现示例

从嵌入的跨源 iframe 请求访问存储空间

显示顶级域名.site 上的嵌入式网站的示意图
在其他网站上的嵌入中使用 requestStorageAccess()

检查您是否拥有存储空间访问权限

如需检查您是否已拥有存储空间访问权限,请使用 document.hasStorageAccess()

如果 promise 解析为 true,您就可以在跨网站上下文中访问存储空间。 如果解析为 false,则需要请求存储空间访问权限。

document.hasStorageAccess().then((hasAccess) => {
    if (hasAccess) {
      // You can access storage in this context
    } else {
      // You have to request storage access
    }
});

请求存储空间访问权限

如果您需要请求存储空间访问权限,请先检查存储空间访问权限 navigator.permissions.query({name: 'storage-access'}),看看是否需要用户手势,还是可以自动授予。

如果权限为 granted,您可以调用 document.requestStorageAccess(),并且无需用户手势即可成功。

如果权限状态为 prompt,您需要在用户执行手势(例如点击按钮)后发起 document.requestStorageAccess() 调用。

示例:

navigator.permissions.query({name: 'storage-access'}).then(res => {
  if (res.state === 'granted') {
    // Permission has already been granted
    // You can request storage access without any user gesture
    rSA();
  } else if (res.state === 'prompt') {
    // Requesting storage access requires user gesture
    // For example, clicking a button
    const btn = document.createElement("button");
    btn.textContent = "Grant access";
    btn.addEventListener('click', () => {
      // Request storage access
      rSA();
    });
    document.body.appendChild(btn);
  }
});

function rSA() {
  if ('requestStorageAccess' in document) {
    document.requestStorageAccess().then(
      (res) => {
        // Use storage access
      },
      (err) => {
        // Handle errors
      }
    );
  }
}

来自框架、导航或子资源的后续请求将自动获得访问跨网站 Cookie 的权限。hasStorageAccess() 返回 true,则系统会在这些请求中发送来自同一关联网站集的跨网站 Cookie,而无需任何额外的 JavaScript 调用。

代表跨源网站请求 Cookie 访问权限的顶级网站

显示 requestStorageAccessFor() 在顶级网站(而非嵌入内容中)使用情况的示意图
在顶级网站上针对其他来源使用 requestStorageAccessFor()

顶级网站可以使用 requestStorageAccessFor() 代表特定来源请求存储空间访问权限。

hasStorageAccess() 仅检查调用它的网站是否具有存储空间访问权限,因此顶级网站可以检查其他来源的权限。

如需了解系统是否会向用户显示提示,或者是否已向指定来源授予存储空间访问权限,请调用 navigator.permissions.query({name: 'top-level-storage-access', requestedOrigin: 'https://target.site'})

如果权限为 granted,您可以调用 document.requestStorageAccessFor('https://target.site')。它应该在没有用户手势的情况下成功。

如果权限为 prompt,则您需要在用户手势(例如按钮点击)后钩住 document.requestStorageAccessFor('https://target.site') 调用。

示例:

navigator.permissions.query({name:'top-level-storage-access',requestedOrigin: 'https://target.site'}).then(res => {
  if (res.state === 'granted') {
    // Permission has already been granted
    // You can request storage access without any user gesture
    rSAFor();
  } else if (res.state === 'prompt') {
    // Requesting storage access requires user gesture
    // For example, clicking a button
    const btn = document.createElement("button");
    btn.textContent = "Grant access";
    btn.addEventListener('click', () => {
      // Request storage access
      rSAFor();
    });
    document.body.appendChild(btn);
  }
});

function rSAFor() {
  if ('requestStorageAccessFor' in document) {
    document.requestStorageAccessFor().then(
      (res) => {
        // Use storage access
      },
      (err) => {
        // Handle errors
      }
    );
  }
}

成功调用 requestStorageAccessFor() 后,如果跨站请求包含 CORS 或 crossorigin 属性,则会包含 Cookie,因此网站可能需要等待一段时间才能触发请求。

请求必须使用 credentials: 'include' 选项,并且资源必须包含 crossorigin="use-credentials" 属性。

function checkCookie() {
    fetch('https://related-website-sets.glitch.me/getcookies.json', {
        method: 'GET',
        credentials: 'include'
      })
      .then((response) => response.json())
      .then((json) => {
      // Do something
      });
  }

如何在本地进行测试

前提条件

如需在本地测试相关网站集,请使用从命令行启动的 Chrome 119 或更高版本,并启用 test-third-party-cookie-phaseout Chrome flag

启用 Chrome 标志

如需启用必要的 Chrome 标志,请从地址栏前往 chrome://flags#test-third-party-cookie-phaseout,然后将该标志更改为 Enabled。更改标志后,请务必重启浏览器。

使用本地相关网站集启动 Chrome

如需使用本地声明的“相关网站集”启动 Chrome,请创建一个包含集成员网址的 JSON 对象,并将其传递给 --use-related-website-set

详细了解如何使用标志运行 Chromium

--use-related-website-set="{\"primary\": \"https://related-website-sets.glitch.me\", \"associatedSites\": [\"https://rws-member-1.glitch.me\"]}" \
https://related-website-sets.glitch.me/

示例

如需在本地启用“相关网站集”,您需要在 chrome://flags 中启用 test-third-party-cookie-phaseout,并使用包含集成员网址的 JSON 对象通过命令行启动 Chrome 并设置 --use-related-website-set 标志。

--use-related-website-set="{\"primary\": \"https://related-website-sets.glitch.me\", \"associatedSites\": [\"https://rws-member-1.glitch.me\"]}" \
https://related-website-sets.glitch.me/

验证您是否有权访问跨网站 Cookie

从要测试的网站调用 API (rSA 或 rSAFor),并验证对跨网站 Cookie 的访问权限。

Related Website Set 提交流程

请按照以下步骤声明网域之间的关系,并指定它们属于哪个子集。

1. 确定您的 RWS

确定相关网域,包括将纳入到 Related Website Set 中的设置主要网域设置成员网域。此外,还要确定每个集合成员所属的子集类型

2. 创建 RWS 提交内容

创建 GitHub 代码库的本地副本(克隆或分支)。在新分支中,对 related_website_sets.JSON 文件进行更改,以反映您的网站集。为确保您的集合具有正确的 JSON 格式和结构,您可以使用 JSON 生成器工具

3. 确保您的 RWS 符合技术要求

确保已满足集合构成要求集合验证要求

4. 在本地测试 RWS

在创建拉取请求 (PR) 以提交您的集合之前,请在本地测试提交内容,确保其通过了所有必要的检查。

5. 提交 RWS

通过向 Chrome 托管规范 Related Website Set 列表的 related_website_sets.JSON 文件创建 PR 来提交 Related Website Set。(您需要拥有 GitHub 账号才能创建 PR,并且您需要先签署贡献者许可协议 (CLA)然后才能为该列表做出贡献。)

创建 PR 后,系统会完成一系列检查,以确保您已满足第 3 步中的要求,例如确保您已签署 CLA 且 .well-known 文件有效。

如果成功,PR 将指示已通过检查。我们会每周手动将批准的 PR 批量合并到规范的 Related Website Set 列表中一次(美国东部时间周二中午 12 点)。如果任何检查失败,提交者会通过 GitHub 上的 PR 失败消息收到通知。提交者可以修复错误并更新 PR,但请注意:

  • 如果提交失败,系统会显示一条错误消息,其中会提供有关提交可能失败的原因的更多信息。(示例)。
  • 所有用于管理套件提交内容的技术检查均在 GitHub 上进行,因此,因技术检查而导致的所有提交失败情况均可在 GitHub 上查看。

企业政策

Chrome 提供了两项政策来满足企业用户的需求:

  • 可能无法与 Related Website Set 集成的系统可以使用 RelatedWebsiteSetsEnabled 政策在 Chrome 的所有企业实例中停用 Related Website Set 功能。
    • 某些企业系统具有仅限内部访问的网站(例如 Intranet),其可注册的域名不同于其“相关网站集”中的域名。如果他们需要将这些网站视为其相关网站集的一部分,但又不想公开显示这些网站(因为这些网域可能属于机密信息),则可以使用 RelatedWebsiteSetsOverrides 政策来补充或替换其公开的相关网站集列表。

Chrome 会通过以下两种方式之一解析公共集和企业集的任何交集,具体取决于是否指定了 replacementsadditions

例如,对于公开集 {primary: A, associated: [B, C]}

replacements 集合: {primary: C, associated: [D, E]}
企业集合会吸收常规网站,以形成新的集合。
生成的集合: {primary: A, associated: [B]}
{primary: C, associated: [D, E]}
additions 集合: {primary: C, associated: [D, E]}
公开版和企业版集合在一起。
生成的集合: {primary: C, associated: [A, B, D, E]}

排查与 Related Website Set 相关的问题

“用户提示”和“用户手势”

“用户提示”和“用户手势”是两码事。对于同一相关网站集中的网站,Chrome 不会向用户显示权限提示,但 Chrome 仍要求用户与相应网页互动。在授予权限之前,Chrome 需要用户执行手势(也称为“用户互动”或“用户激活”)。这是因为,根据Web 平台设计原则,在 Related Website Set 上下文(即 requestStorageAccess())之外使用 Storage Access API 也需要用户手势。

访问其他网站的 Cookie 或存储空间

Related Website Set 不会合并不同网站的存储空间:它只是允许更轻松地(无提示)进行 requestStorageAccess() 调用。Related Website Set 只是降低了用户使用 Storage Access API 的摩擦,但不会规定在恢复访问权限后要执行的操作。如果 A 和 B 是同一 Related Website Set 中的不同网站,并且 A 嵌入了 B,则 B 可以调用 requestStorageAccess() 并获得对第一方存储空间的访问权限,而无需向用户发出提示。相关网站集不会执行任何跨站通信。例如,设置关联的网站集不会导致属于 B 的 Cookie 开始发送到 A。如果您想共享这些数据,则必须自行共享,例如从 B iframe 向 A 帧发送 window.postMessage

Related Website Set 不允许在不调用任何 API 的情况下隐式访问未分区的 Cookie。默认情况下,相关网站集不会在其中提供跨网站 Cookie;Related Website Set 只是允许相关网站集内的网站跳过 Storage Access API 权限提示。如果 iframe 想要访问其 Cookie,则必须调用 document.requestStorageAccess();或者,顶级页面可以调用 document.requestStorageAccessFor()

分享反馈

在 GitHub 上提交一组测试,并使用 Storage Access API 和 requestStorageAccessFor API,您可以借此机会分享您在该过程中的经验以及遇到的任何问题。

如需加入有关 Related Website Set 的讨论,请执行以下操作: