功能政策简介

摘要

借助功能政策,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 在 iframe 中添加了对 Feature-Policy HTTP 标头和 allow 属性的支持,但 JavaScript API 是在 Chrome 74 中添加的。

此 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 Surface 都可选择启用或检测功能,因此功能政策非常适合用于渐进式增强

总结

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

其他资源