跳转到内容

CHIPS:分区的第三方 Cookie 详解

发布于 更新于

一句话: 根据 MDN,“Cookies Having Independent Partitioned State (CHIPS, also known as Partitioned cookies) allows developers to opt a cookie into partitioned storage, with a separate cookie jar per top-level site.”(具有独立分区状态的 Cookie,即 CHIPS,也 称为分区 Cookie,允许开发者为某个 Cookie 选择加入分区存储,为每个顶级站点提供独立的 Cookie 罐。)

MDN 解释了 CHIPS 所解决的问题:“cookies marked Partitioned are double-keyed: by the origin that sets them and the origin of the top-level page. This means they can only be read within the context of the top-level site they were set on.”(标记为 Partitioned 的 Cookie 采用双键:一个键是设置它的 origin,另一个键是顶级页面的 origin。这意味着它们只能在其被设置时所处的顶级站点上下文中被读取。)如果没有这种机制, “third-party cookies can enable services to track users and associate their information across unrelated top-level sites”(第三方 Cookie 可能让服务用于跟踪用户, 并把用户信息在互不相关的顶级站点之间关联起来)——而双键机制在阻止这类跟踪的同时,仍能支 持合理的用例,例如“persisting state of embedded maps or chat widgets across a domain and its subdomains”(在一个域名及其子域名之间,为嵌入的地图或聊天小部件保持状态)。

根据 MDN,站点通过在 Set-Cookie 响应头中加入 Partitioned 属性来选择加入:

Set-Cookie: __Host-example=34d8g; SameSite=None; Secure; Path=/; Partitioned;

MDN 指出,“partitioned cookies must be set with Secure”(分区 Cookie 必须同时设置 Secure),并建议“如果不需要在子域名之间共享 Cookie”,可使用 __Host- 前缀。

设置了 Partitioned 之后,MDN 将由此产生的存储键描述为一对:“the host key and a new partition key”(宿主键与一个新的分区键),其中分区键“is based on the site, including the scheme, of the top-level URL the browser was visiting when the request was made to the URL endpoint that set the cookie”(基于浏览器发起设置该 Cookie 的请求时所访问的顶级 URL 的站点,包括其协议方案)。由 3rd-party.example 在嵌入 site-a.example 时设置的 Cookie,其键为 {("https://site-a.example"), ("3rd-party.example")};因此同一个第三方 稍后被嵌入 site-b.example 时会得到不同的分区,无法读回该 Cookie。

CookieStore API 的 getAll() 方法直接暴露了每个 Cookie 的分区状态:根据 MDN 的 CookieStore.getAll() 参考页,其结果字段中记录了 partitioned:“A boolean indicating whether the cookie is a partitioned cookie (true) or not (false).”(一个布尔值,表 示该 Cookie 是否为分区 Cookie。)这为需要在依赖 CookieStore 之前先判断其是否受支持的代码 提供了一条真实可用的特性检测路径:

async function readPartitionedCookies() {
if (!('cookieStore' in window)) {
// 没有 CookieStore API —— 根据 MDN,document.cookie 的 getter 只返回
// 分号分隔的 name=value 列表,不包含 Partitioned 等属性,因此解析它同样
// 无法还原分区状态,这里只能把分区情况当作未知处理。
return null;
}
const cookies = await window.cookieStore.getAll();
return cookies.filter((cookie) => cookie.partitioned);
}

MDN 的状态分区(State Partitioning)文章描述了一个目标相似、但默认行为不同的、更广泛的 Firefox 专属机制:“State Partitioning is a broad effort by Mozilla to rework how Firefox manages client-side state… to mitigate the ability of websites to abuse state for cross-site tracking.”(状态分区是 Mozilla 的一项广泛工作,旨在重新设计 Firefox 管理客户端状态的方式……以削弱网站滥用状态进行跨站跟踪的能力。)与 CHIPS 的选择加 入模型不同,MDN 指出 Firefox 默认“double-keys all client-side state by the origin of the resource being loaded and by the top-level site”(按加载资源的 origin 与顶级站点对 所有客户端状态进行双键处理),涵盖 localStorage、sessionStorage、IndexedDB 与 Service Worker 等存储 API,此外还对网络缓存(HTTP 缓存、DNS、连接池等)做了另一套不可配 置的分区,MDN 称其“is permanent”(是永久性的),并且“websites can’t control or relax” (网站无法控制或放宽这些限制)。

MDN 的 CHIPS 页面直接指出了两者的对比:“CHIPS is similar to the state partitioning mechanism implemented by Firefox. However, state partitioning partitions cookie storage by default for third-party contexts, whereas CHIPS allows opt-in to partitioned cookies for both first-party and third-party contexts. It is recommended to use the opt-in mechanism of CHIPS rather than state partitioning to provide the most compatible partitioned cookies.”(CHIPS 与 Firefox 实现的状态分区机制类似。但状态 分区默认只对第三方上下文的 Cookie 存储进行分区,而 CHIPS 允许在第一方与第三方上下文中都 选择加入分区 Cookie。建议使用 CHIPS 的选择加入机制而非状态分区,以获得兼容性最好的分区 Cookie。)

MDN 针对 Set-Cookie 的 Partitioned 属性的兼容性数据显示,各引擎的支持时间点不同: Chrome 从 114 版本开始,Firefox 从 141 版本开始,Safari 从 26.2 版本开始。在生产环境依赖 Partitioned 之前,请查阅 MDN 的实时兼容性表格,因为这三个引擎的支持都还比较新。

  • 始终将 Partitioned 与 Secure 搭配使用——MDN 指出这是该属性生效的必要条件,而非 可选项。
  • 不要假设在某个顶级站点嵌入时设置的分区 Cookie,在同一内容被嵌入到别处时仍可读取 ——根据 MDN 对存储键的描述,不同的顶级站点会产生不同的分区键。
  • 不要依赖 document.cookie 来判断某个 Cookie 是否已分区——根据 MDN 的 Document.cookie 参考页,其 getter 只返回分号分隔的 name=value 列表,不含任何 per-cookie 属性,因此 Cookie 携带的 Partitioned 状态永远不会出现在其中;真正把 这一信息暴露给脚本的是 CookieStore API getAll() 的 partitioned 字段。
  • 如果你的目标用户特别包含 Firefox,请记住 MDN 的建议:相比依赖状态分区对第三方的默 认行为,更推荐使用 CHIPS 显式的选择加入机制,因为 CHIPS 作为标准化机制,在第一方与 第三方上下文中的行为是一致的。
  • Storage Access API —— 第三方 frame 用 于请求未分区 Cookie 访问权限的 API,适用于需要脱离分区而非选择加入分区的场景
  • Web 能力索引 —— 相关的、需要存储或权限授予的浏览器能力