使用权限政策控制浏览器功能

管理您的网页和网页上的第三方 iframe 对浏览器功能的使用权限。

Kevin K. Lee
Kevin K. Lee

权限政策(以前称为“功能政策”)允许开发者通过声明一组政策来强制执行页面,从而控制页面可用的浏览器功能、页面 iframe 和子资源。这些政策适用于响应标头来源列表中提供的来源。源列表可以包含同源和/或跨源,并且可让开发者控制第一方和第三方对浏览器功能的访问权限。

用户对更强大的功能拥有最终决定权,并且需要通过提示提供明确许可。

权限政策允许顶级网站定义自己及其第三方打算使用的内容,并让用户轻松确定功能访问权限请求是否合法。例如,通过“权限”政策禁止所有第三方使用地理定位功能,开发者可以确保任何第三方都无法访问用户的地理位置。

权限政策的变更

“权限政策”以前称为“功能政策”。关键概念保持不变,但除了名称之外,还有一些重要变化。

结构化字段用法

结构化字段提供了一组常见的数据结构,用于对 HTTP 标头字段值的解析和序列化进行标准化。如需详细了解结构化字段,请参阅 Fastly 的博文“利用结构化标头字段改进 HTTP”。

旧优惠
  geolocation 'self' https://example.com; camera 'none'

之前介绍的是功能政策。

新观看者
  geolocation=(self "https://example.com"), camera=()

新增了权限政策。

通过 iframe allow 属性合并标头

借助功能政策,您可以通过以下两种方式向跨源框架添加该功能:将来源添加到标头来源列表中,或向 iframe 标记添加 allow 属性。使用权限政策时,如果您向来源列表添加跨源框架,则该来源的 iframe 代码必须包含 allow 属性。 如果响应不包含权限政策标头,系统会认为来源列表具有默认值 *。向 iframe 添加 allow 属性后,您便可访问相应功能。

因此,我们建议开发者在响应中明确设置权限政策标头。这样一来,即使存在 allow,系统仍会阻止源列表中未列出的跨源 iframe 访问此功能。

Chrome 88 之后,功能政策仍可使用,但它充当权限政策的别名。除了语法,没有其他逻辑差异。如果同时使用权限政策和功能政策标头,则 Permissions-Policy 标头的优先级将更高,并且将覆盖 Feature-Policy 标头提供的值。

如何使用权限政策?

简要概述

在深入探究之前,我们先快速了解一下您是网站所有者并希望控制网站和第三方代码使用浏览器功能的方式的常见场景。

  • 您的网站是 https://your-site.example
  • 您的网站嵌入了来自同源 (https://your-site.example) 的 iframe。
  • 您的网站嵌入了您信任的 https://trusted-site.example 提供的 iframe。
  • 您的网站还会显示 https://ad.example 投放的广告。
  • 您只希望为您的网站和可信网站启用地理定位,而不希望为广告启用地理定位。

在本例中,请使用以下标头:

Permissions-Policy: geolocation=(self "https://trusted-site.example")

此外,还要将 allow 属性设置为可信网站的 iframe 代码:

<iframe src="https://trusted-site.example" allow="geolocation">

权限政策使用情况的快速概览图。

在此示例中,标头来源列表仅允许您的网站 (self) 和 trusted-site.example 使用地理定位功能。ad.example不可以使用地理定位。

  1. 在征得用户同意后,您的网站 your-site.example 可以使用地理定位功能。
  2. 无需使用 allow 属性,即可允许同源 iframe (your-site.example) 使用此功能。
  3. 如果某个 iframe 通过其他子网域 (subdomain.your-site-example) 投放,但相应子网域未添加到来源列表中,且在 iframe 代码中设置了 allow 属性,则该 iframe 无法使用此功能。不同的子网域会被视为同网站但跨源。
  4. 如果跨源 iframe (trusted-site.example) 已添加到来源列表中,且在 iframe 代码中设置了 allow 属性,那么跨源 iframe 将可以使用该功能。
  5. 如果跨源 iframe (trusted-site.example) 已添加到源列表,但没有 allow 属性,则系统将阻止使用此功能。
  6. 未添加到源列表的跨源 iframe (ad.example) 无法使用该功能,即使 iframe 标记中添加了 allow 属性也是如此。

Permissions-Policy HTTP 响应标头

用户发出请求,服务器返回“Permissions Policy”标头,然后浏览器根据该标头授予访问权限。

Permissions-Policy: &lt;feature&gt;=(&lt;token&gt;|&lt;origin(s)&gt;)

在来自服务器的响应中使用 Permissions-Policy 标头为功能设置允许的来源。标头值可以接受令牌和源字符串的组合。可用令牌为所有源的 * 和同源的 self

如果标题涉及多个地图项,请使用英文逗号分隔这些地图项。如果您列出了多个源站,请使用空格分隔源列表中的每个源站。对于列出跨源请求的来源的标头,iframe 代码必须包含 allow 属性。

以下是一些键值对示例:

  • 语法:[FEATURE]=*
    • 已应用于所有源的政策
    • 示例:geolocation=*
  • 语法:[FEATURE]=(self)
    • 应用于同源的政策
    • 示例:geolocation=(self)
  • 语法:[FEATURE]=(self [ORIGIN(s)])
    • 政策已应用于同一来源和指定的来源
    • 示例:geolocation=(self "https://a.example" "https://b.example")
    • selfhttps://your-site.example 的简写形式
  • 语法:[FEATURE]=([ORIGIN(s)])
    • 政策已应用于同一来源和指定的来源
    • 示例:geolocation=("https://your-site.example" "https://a.example" "https://b.example")
    • 使用此语法时,其中一个源应为嵌入器的源。如果嵌入器页面本身未被授予权限,那么即使嵌入该页面的 iframe 已添加到来源列表中,也会被屏蔽,因为权限政策会授予相关权限。您也可以使用 self 令牌。
  • 语法:[FEATURE]=()
    • 已针对所有源停用功能
    • 示例:geolocation=()

不同的子网域和路径

不同的子网域(例如 https://your-site.examplehttps://subdomain.your-site.example)会被视为同网站但跨源。因此,在来源列表中添加子网域不允许访问同一网站的另一个子网域。必须将想要使用此功能的每个嵌入式子网域单独添加到源列表中。例如,如果只允许使用标头 Permissions-Policy: browsing-topics=(self) 同源访问用户的浏览主题,则来自同一网站的不同子网域 https://subdomain.your-site.example 的 iframe 将无法访问这些主题。

不同的路径(例如 https://your-site.examplehttps://your-site.example/embed)会被视为同源,且不必在源列表中列出不同的路径。

iframe allow 属性

iframe 设置

对于跨域使用,iframe 需要代码中的 allow 属性才能访问该功能。

语法:<iframe src="[ORIGIN]" allow="[FEATURE] <'src' | [ORIGIN(s)]"></iframe>

例如:

<iframe src="https://trusted-site.example" allow="geolocation">

处理 iframe 导航

iframe 导航设置

默认情况下,如果 iframe 导航到其他来源,此政策不会应用于 iframe 导航到的来源。如果在 allow 属性中列出 iframe 所导航到的来源,则应用于原始 iframe 的权限政策也将应用于 iframe 所导航到的来源。

<iframe src="https://trusted-site.example" allow="geolocation https://trusted-site.example https://trusted-navigated-site.example">

要查看实际操作效果,请访问 iframe 导航演示

权限政策设置示例

您可以在演示中找到以下设置的示例。

已允许在所有源上使用该功能

允许访问该功能的所有源的架构

Permissions-Policy: geolocation=*
<iframe src="https://trusted-site.example" allow="geolocation">
<iframe src="https://ad.example" allow="geolocation">

如果来源列表设置为 * 令牌,则网页上存在的所有来源(包括自身和所有 iframe)都可使用此功能。在本例中,通过 https://your-site.example 提供的所有代码以及通过 https://trusted-site.example iframe 和 https://ad.example 提供的代码都可以访问用户浏览器中的地理定位功能。请注意,除了将来源添加到标头来源列表中,还必须在 iframe 本身上设置 allow 属性。

您可以在演示中查看此设置。

仅限同源的功能

仅允许同一来源访问该功能的架构

Permissions-Policy: geolocation=(self)

使用 self 令牌仅允许使用同源地理位置。跨源功能将无法使用此功能。在本例中,只有 https://trusted-site.example (self) 可以使用地理定位。如果您只想为网页使用该功能,而不想将其用于其他人,可以使用此语法。

您可以在演示中查看此设置。

允许在同源和特定跨源上使用该功能

允许访问相应功能的指定源的架构

Permissions-Policy: geolocation=(self "https://trusted-site.example")

此语法允许对 self (https://your-site.example) 和 https://trusted-site.example 使用地理定位。请务必向 iframe 代码明确添加 allow 属性。如果存在另一个具有 <iframe src="https://ad.example" allow="geolocation"> 的 iframe,则 https://ad.example 将无法访问地理定位功能。只有源列表中列出的原始网页和 https://trusted-site.example 在 iframe 代码中具有 allow 属性,才能使用用户的功能。

您可以在演示中查看此设置。

已在所有源上屏蔽功能

被阻止访问该功能的所有源的架构

Permissions-Policy: geolocation=()

如果来源列表为空,系统会针对所有来源屏蔽该功能。您可以在演示中查看此设置。

使用 JavaScript API

在文档或元素 (document.featurePolicy or element.featurePolicy) 上找到功能政策的现有 JavaScript API 作为对象。权限政策的 JavaScript API 尚未实施。

Feature Policy API 可用于由权限政策设置的政策,但存在一些限制。关于 JavaScript API 实现,还有一些未解决的问题,并提出了一项提案,旨在将该逻辑移至 Permissions API。如果您有任何想法,请加入讨论。

featurePolicy.allowsFeature(feature)

  • 如果允许针对默认来源使用该功能,则返回 true
  • 权限政策所设置的两项政策的行为与之前的功能政策相同
  • 对 iframe 元素 (iframeEl.featurePolicy.allowsFeature('geolocation')) 调用 allowsFeature() 时,返回值反映是否在 iframe 上设置了 allow 属性

featurePolicy.allowsFeature(feature, origin)

  • 如果该地图项适用于指定的出发地,则返回 true
  • 如果在 document 上调用该方法,则此方法将不再像 Feature Policy 那样告知您指定的来源是否允许该功能。现在,此方法会指示相应地图项允许到达相应起点。您必须再检查一下 iframe 是否设置了 allow 属性。开发者必须对 iframe 元素的 allow 属性再进行一次检查,以确定第三方来源是否支持该功能。

使用 element 对象检查 iframe 中的地图项

您可以使用接受 allow 属性的 element.allowsFeature(feature),这一点与 document.allowsFeature(feature, origin) 不一样。

const someIframeEl = document.getElementById('some-iframe')
const isCameraFeatureAllowed = someIframeEl.featurePolicy.allowsFeature('camera')

featurePolicy.allowedFeatures()

  • 返回使用默认来源时允许使用的功能列表。
  • 权限政策和功能政策所设置的政策的行为相同
  • 如果关联的节点是 iframe,则需要考虑 allow 属性。

featurePolicy.features()

  • 返回浏览器中可用的功能列表。
  • 权限政策和功能政策所设置的政策的行为相同

Chrome 开发者工具集成

Chrome 开发者工具与权限政策的集成

查看“权限”政策在开发者工具中的运作方式。

  1. 打开 Chrome 开发者工具
  2. 打开 Application 面板,查看每个帧允许使用的功能和不允许使用的功能。
  3. 在边栏中,选择您要检查的帧。系统会向您显示所选帧允许使用的功能列表,以及该帧中被屏蔽的功能列表。

从 Feature-Policy 迁移

如果您目前使用的是 Feature-Policy 标头,则可以按照以下步骤迁移到权限政策。

将功能政策标头替换为权限政策标头

由于只有基于 Chromium 的浏览器才支持功能政策标头,且自 Chrome 88 版开始支持权限政策标头,因此您可以使用权限政策放心地更新现有标头。

旧优惠
Feature-Policy:
  autoplay *;
  geolocation 'self';
  camera 'self' 'https://trusted-site.example';
  fullscreen 'none';

之前介绍的是功能政策。

新观看者
Permissions-Policy:
  autoplay=*,
  geolocation=(self),
  camera=(self "https://trusted-site.example"),
  fullscreen=()

新增了权限政策。

更新 document.allowsFeature(feature, origin) 使用情况

如果要使用 document.allowsFeature(feature, origin) 方法检查 iframe 允许的功能,请使用附加到 iframe 元素(而不是包含 document)的 allowsFeature(feature) 方法。element.allowsFeature(feature) 方法会考虑 allow 属性,而 document.allowsFeature(feature, origin) 则不会。

正在向 document 检查功能访问权限

若要继续将 document 用作基本节点,您必须对 iframe 代码中的 allow 属性再进行一次检查。

<iframe id="some-iframe" src="https://example.com" allow="camera"></iframe>
Permissions-Policy: camera=(self "https://example.com")
const isCameraPolicySet = document.featurePolicy.allowsFeature('camera', 'https://example.com')

const someIframeEl = document.getElementById('some-iframe')
const hasCameraAttributeValue = someIframeEl.hasAttribute('allow')
&& someIframeEl.getAttribute('allow').includes('camera')

const isCameraFeatureAllowed = isCameraPolicySet && hasCameraAttributeValue

建议像上例一样对 element 对象调用 allowsFeature(),而不是使用 document 更新现有代码。

报告 API

Reporting API 以一致的方式为 Web 应用提供报告机制,并且针对权限政策违规行为的 Reporting API 是一项实验性功能。

如果您想要测试该实验性功能,请按照演示操作,并在 chrome://flags/#enable-experimental-web-platform-features 中启用相应标志。启用该标志后,您可以在开发者工具中的 Application 标签页下观察权限政策违规行为:

以下示例展示了如何构建 Reporting API 标头:

Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"

Content-Security-Policy: script-src 'self'; object-src 'none'; report-to main-endpoint;
Document-Policy: document-write=?0; report-to=main-endpoint;

在当前的实现中,您可以通过配置名为“default”的端点(如上例所示),从该框架内发生的任何违规行为收到违规报告。子框架需要有自己的报告配置。

了解详情

如需更深入地了解权限政策,请参阅以下资源: