你以为第三方 Cookie 被浏览器彻底封了?今天 Storage Access API 把这件事用标准接口彻底接上了

做过嵌入式登录的人大概都踩过这个坑——iframe 里的第三方内容需要读写 Cookie,浏览器默认把这件事拦了。传统解法是让用户自己去关隐私设置,今天 Chrome/Firefox/Safari 集体给出了标准答案:Storage Access API。这个 API 让 iframe 里的跨站内容,在用户触发的前提下,光明正大地申请 Cookie 访问权限。

问题:第三方 Cookie 为什么被拦

现代浏览器默认把跨站 iframe 的 Cookie 给隔离开了——同一个 Cookie,在 a.com 嵌入 b.com 的 iframe 里读写,和直接在 b.com 主站读写,是两个完全独立的存储空间。

这个隔离叫存储分区(Storage Partitioning),目的是防止 A 网站通过第三方 Cookie 追踪你在 B 网站的行为。社交媒体的点赞按钮、第三方评论组件、带登录态的视频播放器,都是这个政策的受害者。

核心 API:两行代码申请权限

Storage Access API 的核心是两个方法。

hasStorageAccess() 检查当前状态,requestStorageAccess() 在用户点击等手势事件中调用申请权限。拿到权限后,当前浏览器会话里这个 iframe 就能读写对应域名的 Cookie 了——权限一次申请 30 天内有效,不需要每次刷新都重新申请。

核心流程如下:

const hasAccess = await document.hasStorageAccess();
if (hasAccess) {
// 已经能读写 Cookie 了
console.log(document.cookie);
} else {
// 申请权限(必须在用户点击/触摸等瞬时激活状态下调用)
document.requestStorageAccess().then(() => {
console.log(document.cookie);
}).catch(() => {
console.log(“Storage access denied”);
});
}

Chrome 133 新增:HTTP 头方案,绕过 JS 重新加载

2025 年 2 月 Chrome 133 引入了一套 HTTP 头方案,让存储访问权限的激活可以在服务端完成,不需要 JS 驱动一次页面重新加载。

请求头 Sec-Fetch-Storage-Access 会在跨站带凭证请求里自动带上,三个值代表三种状态:

none:embed 没有存储访问权限,Cookie 读写不了
inactive:权限存在但还没激活,Cookie 读不了
active:存储访问权限已激活,Cookie 随请求发出

服务端看到这个请求头,可以回应 Activate-Storage-Access: retry,告诉浏览器这个 embed 有权限,你激活一下然后重新把请求发过来。浏览器激活权限后自动重试请求,这次带上 Cookie,整个过程用户无感知,不需要 JS 介入。

如果 embed 已经有权限,服务端也可以直接回 Activate-Storage-Access: load,浏览器立即激活权限。

这套头方案有两个明显好处:第一是省掉 JS API 方案里权限授予后的重新加载,延迟从两次往返变成一次;第二是它能覆盖图片、脚本这些被动资源——它们根本没法跑 JS,现在也能享受存储访问激活的收益。

CHIPS:另一种思路,不申请权限,换一种存储方式

如果你嵌入第三方内容只是想在这个 embed 里保存偏好设置(比如语言偏好、字幕开关),不想做跨站追踪,CHIPS(Cookies Having Independent Partitioned State)可能是更轻量的选择。

给 Cookie 加一个 partitioned 属性:

Set-Cookie: lang=zh; SameSite=None; Secure; Partitioned

带 Partitioned 的 Cookie 不受第三方 Cookie 政策影响,会随跨站请求发出,但存储空间是按顶级站点隔离的——同一个 embed 在 a.com 和 b.com 里读写的是两份完全独立的 Cookie,不会跨站追踪。

但要注意:这种 Cookie 在 embed 之间不共享,适合单站点偏好,不适合 SSO 等需要跨站共享状态的场景。

三个必须满足的前提

第一,iframe 必须有 allow-storage-access-by-user-activation 权限标记。如果你的 iframe 是用 sandbox 属性创建的,必须带上这个 token:

iframe src=”https://third-party.example/widget” sandbox=”allow-storage-access-by-user-activation allow-scripts allow-same-origin” /iframe

第二,Cookie 必须是 SameSite=None; Secure。跨站 Cookie 的基本要求,缺了浏览器压根不会发。

第三,必须做特性检测。Storage Access API 是实验性功能,Safari/Firefox/Chrome 支持情况不同,必须先判断 document.hasStorageAccess 是否存在,再决定走哪条路。

浏览器差异:三个逻辑

Chrome 会在首次请求时弹窗问用户是否允许 embedded.example 读写 Cookie,如果用户选择允许,之后 30 天浏览器使用期内不再弹窗。如果 embed 域名用户在最近 30 天内作为一级域名访问过,Chrome 会静默授权,不弹窗。

Firefox 策略不同:同一个 embed 在同一个顶级网站下,前 5 次 requestStorageAccess() 调用不弹窗直接给,第 6 次开始才弹。

Safari(iOS 和 macOS)用的是自己的启发式策略,行为和 Chrome/Firefox 都不一样,但核心 API 用法一致。

权限不是永久的

拿到权限不等于这个 embed 永久有 Cookie 访问权。Chrome 的授权在用户 30 天浏览器使用期后失效,需要重新申请。权限也可能被用户在浏览器设置里手动撤销。所以代码里每次 iframe 加载都要走一遍 hasStorageAccess() → 没有就 requestStorageAccess() → 拿到再读 Cookie 的流程,别假设上次能读这次也能读。

三个下一步

第一,先用 hasStorageAccess() 完整走一遍检测链路,确保你的 iframe 在各种浏览器、各种权限状态下都能优雅降级而不是直接报错。

第二,如果你的 embed 需要覆盖图片/CDN 资源这类被动资源,升级到 Chrome 133+ 的 HTTP 头方案(Sec-Fetch-Storage-Access + Activate-Storage-Access),可以在服务端统一控制存储访问激活,不需要在每个资源上注入 JS。

第三,检查你的 Cookie 场景:需要跨站共享会话(SSO/FedCM)用 Storage Access API;只需要在 embed 自己域名内保存偏好(字幕/语言)用 CHIPS,代码更简单,隐私争议也更小。

Storage Access API 是 W3C Privacy CG 的标准工作项,不是 Chrome 私有方案,Firefox 和 Safari 都已实现。Sec-Fetch-Storage-Access 和 Activate-Storage-Access 是 Chrome 133 引入的扩展,Firefox 在 Nightly 里也在跟进,是未来的跨浏览器方向。

传统方案是让用户去浏览器设置里关掉第三方 Cookie 限制,或者把域名加白名单——这两种都对用户隐私不友好。Storage Access API 是浏览器官方给出的合法后门:在用户明确触发(点击/触摸)的前提下,iframe 里的跨站内容可以申请它本来就有权访问的 Cookie,权限粒度精确到一个 embed,一次授权 30 天有效。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 14 阅读