相关网站集:开发者指南

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

许多网站依靠多个网域来提供单一的用户体验。 组织可能希望针对多种使用情形(例如特定于国家/地区的网域或用于托管图片或视频的服务网域)维护不同的顶级网域。Related Website Set 允许网站在网域之间共享数据,并提供特定控制机制。

从宏观层面来看,Related Website Set 是一组网域,其中包含一个“set primary”和可能多个“set members”。

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

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

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

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

如果您的应用依赖于对同一 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 Sets 集成详情

Storage Access API

Browser Support

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

Source

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

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

当第三方 Cookie 被屏蔽但 Related Website Sets (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 并说明原因。

Chrome 中的 requestStorageAccessFor

Browser Support

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

Source

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

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

为了解决此问题,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 请求存储空间访问权限

图表:显示顶级网域中的嵌入式网站
在其他网站的嵌入内容中使用 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 flag

如需启用必要的 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,并通过命令行启动 Chrome,同时使用 --use-related-website-set 标志以及包含属于某个集的网址的 JSON 对象。

--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 Sets 提交流程

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

1. 确定您的 RWS

确定相关网域,包括将成为 Related Website Set 一部分的主要网站成员网站。还可确定每个集合成员所属的子集类型

2. 创建 RWS 提交内容

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

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

确保满足组形成要求组验证要求

4. 在本地测试 RWS

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

5. 提交您的 RWS

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

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

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

  • 如果 PR 失败,错误消息会提供有关提交可能失败的原因的更多信息。 (示例)。
  • 所有与提交内容相关的技术检查均在 GitHub 上进行,因此,因技术检查而导致的所有提交失败都可在 GitHub 上查看。

企业政策

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

  • 可能无法与 Related Website Sets 集成的系统可以通过 RelatedWebsiteSetsEnabled 政策在所有企业版 Chrome 实例中停用 Related Website Sets 功能。
    • 某些企业系统具有仅限内部访问的网站(例如公司内部网),这些网站的注册域名与其相关网站集中的域名不同。如果他们需要将这些网站视为其相关网站集的一部分,但又不想公开这些网站(因为网域可能是机密信息),则可以使用 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 需要用户手势(也称为“用户互动”或“用户激活”)。这是因为,根据网络平台设计原则,在 Related Website Set 上下文(即 requestStorageAccess())之外使用 Storage Access API 也需要用户手势。

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

Related Website Sets 不会合并不同网站的存储空间,只会允许更轻松地(无需提示)进行 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 Sets 不允许在不调用任何 API 的情况下隐式访问未分区的 Cookie。默认情况下,该组中的网站无法使用跨网站 Cookie;Related Website Set 只是允许该组中的网站跳过 Storage Access API 权限提示如果 iframe 想要访问其 Cookie,则必须调用 document.requestStorageAccess();或者,顶级页面可以调用 document.requestStorageAccessFor()

分享反馈

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

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