安全地将内容嵌入网页,而不会共享跨网站数据。
实现状态
为什么需要围栏框架?
fenced frame (<fencedframe>) 是一种用于嵌入内容的 HTML 元素,类似于 iframe。与 iframe 不同,围栏框架会限制与嵌入上下文的通信,以允许框架访问跨网站数据,而不会与嵌入上下文共享这些数据。部分 Privacy Sandbox API 可能要求在 Fenced Frame 中呈现所选文档。
同样,嵌入上下文中的任何第一方数据都无法与围栏框架共享。
例如,如果 news.example(嵌入上下文)在 fenced frame 中嵌入来自 shoes.example 的广告,则 news.example 无法从 shoes.example 广告中窃取数据,并且 shoes.example 无法从 news.example 中了解第一方数据。
通过存储空间分区增强跨网站隐私保护
在浏览网页时,您可能在一个网站上看过某些商品,然后又在完全不同的网站上的广告中看到这些商品。
如今,这种广告技术主要通过跟踪技术来实现,该技术使用第三方 Cookie 在网站之间共享信息。
Chrome 正在开发存储空间分区功能,该功能可按网站分隔浏览器存储空间。如果不进行分区,如果 shoes.example 中的 iframe 嵌入到 news.example 中,并且该 iframe 将值存储到存储空间中,则可以从 shoes.example 网站读取该值。存储空间分区后,跨网站 iframe 将不再共享存储空间,因此 shoes.example 将无法访问 iframe 存储的信息。如果 iframe 是从 *.shoes.example 提供的,并嵌入到 *.shoes.example 中,则浏览器存储空间将共享,因为它们被视为同网站。
存储空间分区将应用于标准存储 API,包括 LocalStorage、IndexedDB 和 Cookie。在分区世界中,第一方存储空间中的信息泄露将显著减少。
使用跨网站数据
围栏框架是一项 Privacy Sandbox 功能,建议顶级网站对数据进行分区。许多 Privacy Sandbox 提案和 API 旨在满足跨网站用例,而无需使用第三方 Cookie 或其他跟踪机制。例如:
- Protected Audience API 可让广告客户以可保护隐私的方式投放基于兴趣的广告。
- 借助共享存储空间,您可以在安全的环境中访问未分区的跨网站数据。
隔离框架旨在与 Protected Audience API 搭配使用。借助 Protected Audience API,用户的兴趣会以兴趣群体的形式在广告客户的网站上注册,同时注册的还有用户可能感兴趣的广告。然后,在另一个网站(称为“发布商”)上,系统会对相关兴趣组中注册的广告进行竞价,并在受限框架中展示胜出的广告。
如果发布商在 iframe 中展示胜出的广告,并且脚本可以读取 iframe 的 src 属性,则发布商可以从该广告的网址推断出访问者的兴趣信息。这种方式无法保护隐私。
借助 fenced frame,发布商可以展示符合访问者兴趣的广告,但 src 和兴趣群体将仅对框架中的广告客户可见。发布者无法访问此信息。
围栏框架是如何运作的?
围栏框架使用 FencedFrameConfig 对象进行导航。此对象可从 Protected Audience API 竞价或 Shared Storage 的网址选择操作返回。然后,将配置对象设置为 fenced frame 元素的 config 属性。这与 iframe 不同,在 iframe 中,网址或不透明 URN 会分配给 src 属性。FencedFrameConfig 对象具有只读的 url 属性;不过,由于当前使用情形需要隐藏内部资源的实际网址,因此此属性在读取时会返回字符串 opaque。
fenced frame 无法使用 postMessage 与其嵌入者通信。不过,fenced frame 可以在 fenced frame 内使用 iframe 来搭配 postMessage。
围栏框架还会以其他方式与发布商隔离。例如,发布商无法访问围栏框架内的 DOM,而围栏框架也无法访问发布商的 DOM。此外,围栏框架中不提供 name 等属性(可将其设置为任意值并由发布商观察)。
围栏框架的行为方式与顶级浏览上下文(例如浏览器标签页)类似。虽然在某些使用情形(例如基于兴趣的重访定位广告)中,围栏框架可以包含跨网站数据(例如 Protected Audience API 兴趣群体),但该框架无法访问未分区的存储空间或 Cookie。围栏框架可以访问基于随机数的唯一 Cookie 和存储分区。
有关围栏框架的特征,请参阅说明文档了解更多详情。
受限框架与 iframe 相比如何?
现在,您已经了解了围栏框架的功能和限制,接下来可以将其与现有的 iframe 功能进行比较。
| 功能 | iframe |
fencedframe |
|---|---|---|
| 嵌入内容 | 是 | 是 |
| 嵌入式内容可以访问嵌入上下文 DOM | 是 | 否 |
| 嵌入上下文可以访问嵌入内容 DOM | 是 | 否 |
可观测的属性,例如 name |
是 | 否 |
网址 (http://example.com) |
是 | 是(取决于使用场景) |
浏览器管理的不透明来源 (urn:uuid) |
否 | 有(取决于使用情形) |
| 访问跨网站数据 | 否 | 有(取决于使用情形) |
为了保护隐私,围栏框架支持的外部通信选项较少。
围栏框架会取代 iframe 吗?
最终,围栏框架不会取代 iframe,您也不必使用它们。 围栏框架是一种更私密的框架,适用于需要在同一页面上显示来自不同顶级分区的数据的情况。
同源 iframe(有时称为友好 iframe)被视为可信内容。
使用 Fenced Frames
围栏框架将与其他 Privacy Sandbox API 结合使用,以在单个网页中显示来自不同存储分区的文档。我们正在讨论潜在的 API。
目前,此组合的候选对象包括:
- 在 TURTLEDOVE API 系列(Protected Audience API 的基础)中,围栏框架可与使用 Shared Storage 的转化量提升情况衡量搭配使用。
- 另一种方法是允许围栏框架为只读或访问未分区的存储空间。
如需了解详情,请参阅 Fenced Frame 使用场景说明。
示例
如需获取 Fenced Frame config 对象,您必须将 resolveToConfig: true 传递给 Protected Audience API 的 runAdAuction() 调用或 Shared Storage 的 selectURL() 调用。如果未添加该属性(或将其设置为 false),则生成的 promise 将解析为只能在 iframe 中使用的 URN。
const frameConfig = await navigator.runAdAuction({ // ...auction configuration resolveToConfig: true });
const frameConfig = await sharedStorage.selectURL('operation-name', { resolveToConfig: true });
获取配置后,您可以将其分配给围栏框架的 config 属性,以使框架导航到配置所表示的资源。旧版 Chrome 不支持 resolveToConfig 属性,因此您仍必须确认 Promise 是否解析为 FencedFrameConfig,然后才能进行导航:
if (window.FencedFrameConfig && frameConfig instanceof FencedFrameConfig) { const frame = document.createElement('fencedframe'); frame.config = frameConfig; }
如需了解详情,请参阅 Fenced Frame 和 Fenced Frame 配置说明。
标头
浏览器将为从 fenced frame 和嵌入在 fenced frame 内的 iframe 发出的请求设置 Sec-Fetch-Dest: fencedframe。
Sec-Fetch-Dest: fencedframe
服务器必须设置 Supports-Loading-Mode: fenced-frame 响应标头,才能在 fenced frame 中加载文档。对于 fenced frame 内的任何 iframe,也必须存在该标头。
Supports-Loading-Mode: fenced-frame
Shared Storage 上下文
您可能需要使用 Private Aggregation 来报告与嵌入器中的上下文数据相关联的围栏框架中的事件级数据。通过使用 fencedFrameConfig.setSharedStorageContext() 方法,您可以将一些上下文数据(例如事件 ID)从嵌入器传递到由 Protected Audience API 启动的共享存储区工作程序。
在以下示例中,我们将嵌件网页上的一些数据和围栏框架中的一些数据存储在共享存储空间中。在嵌入器网页中,模拟事件 ID 设置为共享存储空间上下文。从 fenced frame 中,传入框架事件数据。
在嵌入器页面中,您可以将上下文数据设置为共享存储上下文:
const frameConfig = await navigator.runAdAuction({ resolveToConfig: true });
// Data from the embedder that you want to pass to the shared storage worklet
frameConfig.setSharedStorageContext('some-event-id');
const frame = document.createElement('fencedframe');
frame.config = frameConfig;
在 fenced frame 中,您可以将框架中的事件级数据传递到共享存储空间 worklet(与上述嵌入者的上下文数据无关):
const frameData = {
// Data available only inside the fenced frame
}
await window.sharedStorage.worklet.addModule('reporting-worklet.js');
await window.sharedStorage.run('send-report', {
data: {
frameData
},
});
您可以从 sharedStorage.context 读取嵌入器的上下文信息,从 data 对象读取框架的事件级数据,然后通过私密聚合报告这些信息:
class ReportingOperation {
convertEventIdToBucket(eventId) { ... }
convertEventPayloadToValue(info) { ... }
async run(data) {
// Data from the embedder
const eventId = sharedStorage.context;
// Data from the fenced frame
const eventPayload = data.frameData;
privateAggregation.contributeToHistogram({
bucket: convertEventIdToBucket(eventId),
value: convertEventPayloadToValue(eventPayload)
});
}
}
register('send-report', ReportingOperation);
如需详细了解 fenced frame 配置对象中的嵌入器上下文,请参阅说明文档。
尝试 fenced frame
使用 Chrome 标志在 chrome://flags/#enable-fenced-frames 处启用 Fenced Frame API。
对话框中有多个选项。我们强烈建议您选择*启用*,这样 Chrome 就能在有新架构可用时自动更新到该架构。
其他选项(启用 ShadowDOM 和启用多页面架构)提供了不同的实现策略,仅与浏览器工程师相关。目前,启用 的工作方式与 启用(使用 ShadowDOM)相同。未来,启用将映射到启用多页面架构。
功能检测
如需确定是否定义了围栏框架,请执行以下操作:
if (window.HTMLFencedFrameElement) {
// The fenced frame element is defined
}
如需确定围栏帧配置是否可用,请执行以下操作:
if (window.FencedFrameConfig && frameConfig instanceof FencedFrameConfig) {
// The fenced frame config is available
}
浏览器支持
互动和分享反馈
围栏框架目前正在积极讨论中,将来可能会发生变化。如果您试用了此 API 并有反馈意见,欢迎随时告诉我们。