功能政策简介

摘要

借助功能政策,Web 开发者可以选择性地启用、停用和修改浏览器中某些 API 和 Web 功能的行为。它类似于 CSP,但它控制的是功能,而不是安全性!

功能政策本身是开发者与浏览器之间达成的选择性协议,有助于我们实现构建(和维护)优质 Web 应用的目标。

简介

面向 Web 构建应用是一项艰巨的任务。构建一款性能出色且采用所有最新最佳实践的顶级 Web 应用已经很难了。要想长期保持这种出色的体验,难度就更大了。随着项目的不断发展,开发者会加入,新功能会发布,代码库也会不断扩大。您曾经获得的“卓越体验”™可能会开始恶化,用户体验也开始受到影响!功能政策旨在帮助您保持正轨。

借助功能政策,您可以选择启用一组“政策”,以便浏览器对您网站中使用的特定功能强制执行这些政策。这些政策限制了网站可以访问哪些 API,或可以修改浏览器针对特定功能的默认行为。

以下是您可以使用功能政策执行的一些操作示例:

  • 更改 autoplay 在移动设备和第三方视频上的默认行为
  • 限制网站使用 cameramicrophone 等敏感 API。
  • 允许 iframe 使用 fullscreen API。
  • 禁止使用已过时 API,例如同步 XHR 和 document.write()
  • 确保图片大小适当(例如,防止布局抖动),并且不会过大(例如,浪费用户的带宽)。

政策是开发者与浏览器之间的合同。它们会告知浏览器开发者的意图,从而帮助我们在应用尝试偏离轨道并执行不良操作时保持诚实。如果网站或嵌入的第三方内容尝试违反开发者预先选择的任何规则,浏览器会通过更好的用户体验替换相应行为,或完全屏蔽该 API。

使用特性政策

功能政策提供了两种控制功能的方法:

  1. 通过 Feature-Policy HTTP 标头。
  2. 在 iframe 上使用 allow 属性。

若要使用功能政策,最简单的方法是将 Feature-Policy HTTP 标头随网页响应一起发送。此标头的值是您希望浏览器针对给定来源遵循的一项政策或一组政策:

Feature-Policy: <feature> <allow list origin(s)>

来源许可名单可以采用多种不同的值:

  • *:顶级浏览上下文和嵌套浏览上下文 (iframe) 中允许使用此功能。
  • 'self':顶级浏览上下文和同源嵌套浏览上下文中允许使用此功能。嵌套浏览上下文中的跨源文档不允许使用此属性。
  • 'none':顶级浏览上下文和嵌套浏览上下文不允许使用此功能。
  • <origin(s)>:要为其启用该政策的特定来源(例如 https://example.com)。

示例

假设您想禁止网站上的所有内容使用 Geolocation API。为此,您可以为 geolocation 功能发送 'none' 的严格许可名单:

Feature-Policy: geolocation 'none'

如果某段代码或 iframe 尝试使用 Geolocation API,浏览器会将其屏蔽。即使用户之前已授予分享其位置信息的权限,情况仍然如此

违反设定的地理位置政策
违反了设定的地理位置政策。

在其他情况下,放宽此政策可能更为合适。我们可以在许可名单中设置 'self',以允许我们自己的来源使用 Geolocation API,但阻止第三方内容访问该 API:

Feature-Policy: geolocation 'self'

iframe allow 属性

使用功能政策的第二种方式是控制 iframe 中的内容。使用 allow 属性为嵌入内容指定政策列表:

<!-- Allow all browsing contexts within this iframe to use fullscreen. -->
<iframe src="https://example.com..." allow="fullscreen"></iframe>

<!-- Equivalent to: -->
<iframe src="https://example.com..." allow="fullscreen *"></iframe>

<!-- Allow only iframe content on a particular origin to access the user's location. -->
<iframe
  src="https://another-example.com/demos/..."
  allow="geolocation https://another-example.com"
></iframe>

现有的 iframe 属性会怎么样?

受功能政策控制的部分功能具有用于控制其行为的现有属性。例如,<iframe allowfullscreen> 是一个属性,可允许 iframe 内容使用 HTMLElement.requestFullscreen() API。此外,还有 allowpaymentrequestallowusermedia 属性,分别用于允许使用 Payment Request APIgetUserMedia()

请尽可能使用 allow 属性,而不是这些旧属性。如果您需要支持向后兼容性,可以将 allow 属性与等效的旧版属性(例如 <iframe allowfullscreen allow="fullscreen">)搭配使用。不过请注意,限制更严格的政策会胜出。例如,由于 allow="fullscreen 'none'"allowfullscreen 更具限制性,因此系统不允许以下 iframe 进入全屏模式:

<!-- Blocks fullscreen access if the browser supports feature policy. -->
<iframe allowfullscreen allow="fullscreen 'none'" src="..."></iframe>

同时控制多项政策

通过发送包含以 ; 分隔的政策指令列表的 HTTP 标头,可以同时控制多项功能:

Feature-Policy: unsized-media 'none'; geolocation 'self' https://example.com; camera *;

或者,为每个政策发送单独的标头:

Feature-Policy: unsized-media 'none'
Feature-Policy: geolocation 'self' https://example.com
Feature-Policy: camera *;

此示例会执行以下操作:

  • 禁止对所有浏览上下文使用 unsized-media
  • 禁止对所有浏览上下文使用 geolocation,但网页自己的来源和 https://example.com 除外。
  • 允许 camera 访问所有浏览上下文。

示例:为 iframe 设置多项政策

<!-- Blocks the iframe from using the camera and microphone
     (if the browser supports feature policy). -->
<iframe allow="camera 'none'; microphone 'none'"></iframe>

JavaScript API

虽然 Chrome 60 添加了对 Feature-Policy HTTP 标头和 iframe 上的 allow 属性的支持,但 Chrome 74 中添加了 JavaScript API

借助此 API,客户端代码可以确定网页、框架或浏览器允许使用哪些功能。您可以在主文档的 document.featurePolicy 下或 iframe 的 frame.featurePolicy 下访问其功能。

示例

以下示例展示了在网站 https://example.com 上发送 Feature-Policy: geolocation 'self' 政策的结果:

/* @return {Array<string>} List of feature policies allowed by the page. */
document.featurePolicy.allowedFeatures();
// → ["geolocation", "midi",  "camera", "usb", "autoplay",...]

/* @return {boolean} True if the page allows the 'geolocation' feature. */
document.featurePolicy.allowsFeature('geolocation');
// → true

/* @return {boolean} True if the provided origin allows the 'geolocation' feature. */
document.featurePolicy.allowsFeature(
  'geolocation',
  'https://another-example.com/'
);
// → false

/* @return {Array<string>} List of feature policies allowed by the browser
regardless of whether they are in force. */
document.featurePolicy.features();
// → ["geolocation", "midi",  "camera", "usb", "autoplay",...]

/* @return {Array<string>} List of origins (used throughout the page) that are
   allowed to use the 'geolocation' feature. */
document.featurePolicy.getAllowlistForFeature('geolocation');
// → ["https://example.com"]

政策列表

那么,哪些功能可以通过功能政策进行控制?

目前,我们缺少关于所实施政策以及如何使用这些政策的文档。随着不同浏览器采用该规范并实施各种政策,此列表也会随之不断扩大。功能政策将是一个不断变化的目标,因此我们肯定需要优质的参考文档。

目前,您可以通过以下几种方式查看哪些功能可供控制。

  • 请查看我们的功能政策大全演示。其中包含在 Blink 中实现的每项政策的示例。
  • 如需查看功能名称列表,请参阅 Chrome 的源代码
  • about:blank 上查询 document.featurePolicy.allowedFeatures() 以查找列表:
        ["geolocation",
         "midi",
         "camera",
         "usb",
         "magnetometer",
         "fullscreen",
         "animations",
         "payment",
         "picture-in-picture",
         "accelerometer",
         "vr",
        ...
  • 如需了解 Blink 中已实施或正在考虑的政策,请访问 chromestatus.com

如需确定如何使用其中一些政策,请参阅规范的 GitHub 代码库其中包含一些关于部分政策的说明。

常见问题解答

何时使用功能政策?

所有政策均需用户选择启用,因此请在适当的时间/地点使用功能政策。例如,如果您的应用是图片库,maximum-downscaling-image 政策可帮助您避免向移动设备视口发送超大型图片。

使用 document-writesync-xhr 等其他政策时应更加谨慎。开启这些功能可能会破坏广告等第三方内容。另一方面,特性政策可以作为一种自我检查工具,确保您的网页绝不会使用这些糟糕的 API!

我是在开发环境还是生产环境中使用功能政策?

两者均包含。我们建议您在开发期间启用政策,并在正式版中让政策保持有效状态。在开发期间启用政策有助于您从一开始就走上正轨。这有助于您在任何意外回归发生之前加以排查。在生产环境中启用政策,以确保为用户提供特定的用户体验。

有没有办法向我的服务器举报违反政策的行为?

Reporting API 正在开发中! 与网站可以选择接收有关 CSP 违规弃用的报告类似,您也可以接收有关实际违反功能政策的报告。

iframe 内容的继承规则是什么?

脚本(第一方或第三方)会继承其浏览环境的政策。这意味着顶级脚本会继承主文档的政策。

iframe 会继承其父级网页的政策。如果 iframe 具有 allow 属性,则父级页面和 allow 列表中更严格的政策将胜出。如需详细了解 iframe 的用法,请参阅 iframe 上的 allow 属性

不可以。政策的生命周期仅适用于单次网页导航响应。如果用户转到新页面,则必须在新响应中明确发送 Feature-Policy 标头,才能应用该政策。

哪些浏览器支持功能政策?

如需了解有关浏览器支持的最新详情,请访问 caniuse.com

目前,Chrome 是唯一支持功能政策的浏览器。不过,由于整个 API 接口是用户选择启用或可检测到功能的,功能政策非常适合渐进式增强

总结

功能政策有助于指明通往更好的用户体验和出色效果的道路。在开发或维护应用时,它尤为有用,因为它有助于在潜在的脚本炸弹潜入代码库之前加以防范。

其他资源