摘要
借助功能政策,Web 开发者可以选择性地启用、停用和修改浏览器中某些 API 和 Web 功能的行为。它与 CSP 类似,但控制的是功能,而不是控制安全性!
功能政策本身是开发者与浏览器之间达成的选择性协议,有助于我们实现构建(和维护)优质 Web 应用的目标。
简介
面向 Web 构建应用是一项艰巨的任务。构建一款性能出色且采用所有最新最佳实践的顶级 Web 应用已经很难了。要想长期保持这种出色的体验,难度就更大了。随着项目的发展,开发者会参与进来,推出新功能,并且代码库也会在不断增长。您曾经获得的“Great Experience TM”(超棒体验)可能会开始恶化,用户体验开始下降!功能政策旨在帮助您保持正轨。
通过 Feature Policy,您可以选择一组“政策”,以便浏览器对整个网站使用的特定功能强制执行。这些政策限制了网站可以访问哪些 API,或限制了网站可以修改浏览器针对特定功能的默认行为。
以下是您可以使用功能政策执行的一些操作示例:
- 更改
autoplay
在移动设备和第三方视频上的默认行为。 - 限制网站使用
camera
或microphone
等敏感 API。 - 允许 iframe 使用
fullscreen
API。 - 禁止使用已过时 API,例如同步 XHR 和
document.write()
。 - 确保图片大小适当(例如,防止布局抖动),并且不会过大(例如,浪费用户的带宽)。
政策是开发者与浏览器之间的约定。它们会告知浏览器开发者的意图,从而帮助我们在应用尝试偏离轨道并执行不良操作时保持诚实。如果网站或嵌入的第三方内容尝试违反开发者预先选择的任何规则,浏览器会通过更好的用户体验替换相应行为,或完全屏蔽该 API。
使用特性政策
功能政策提供了两种控制功能的方法:
- 通过
Feature-Policy
HTTP 标头。 - 在 iframe 上使用
allow
属性。
Feature-Policy
HTTP 标头
若要使用功能政策,最简单的方法是将 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,但禁止第三方内容访问它:
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 的属性。此外,还有 allowpaymentrequest
和 allowusermedia
属性,分别用于允许 Payment Request API 和 getUserMedia()
。
尽可能尝试使用 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-write
和 sync-xhr
等其他政策时应更加谨慎。开启这些功能可能会破坏广告等第三方内容。另一方面,特性政策可以作为一种自我检查工具,确保您的网页绝不会使用这些糟糕的 API!
我在开发环境还是生产环境中使用功能政策?
两者均包含。我们建议您在开发期间启用政策,并在正式版中让政策保持有效状态。在开发期间启用政策有助于您从一开始就走上正轨。这有助于您及时发现任何意外回归问题。在生产环境中启用政策,以确保为用户提供特定的用户体验。
能否向我的服务器报告违反政策的情况?
Reporting API 正在开发中! 与网站如何选择接收关于 CSP 违规或弃用的报告类似,您也能收到关于普遍违反功能政策的报告。
iframe 内容的继承规则是什么?
脚本(第一方或第三方)会继承其浏览环境的政策。这意味着顶级脚本会继承主文档的政策。
iframe
会继承其父级网页的政策。如果 iframe
具有 allow
属性,则父级页面和 allow
列表中更严格的政策将胜出。如需详细了解 iframe
的用法,请参阅 iframe 上的 allow
属性。
如果我应用了政策,该政策是否会在网页导航期间保持有效?
不会。政策的生命周期仅适用于单次网页导航响应。如果用户转到新页面,则必须在新响应中明确发送 Feature-Policy
标头,才能应用该政策。
哪些浏览器支持 Feature Policy?
如需了解有关浏览器支持的最新详情,请访问 caniuse.com。
目前,Chrome 是唯一支持功能政策的浏览器。不过,由于整个 API 接口是用户选择启用或可检测到功能的,功能政策非常适合渐进式增强。
总结
特征政策有助于为实现更出色的用户体验和出色性能提供良好的途径。在开发或维护应用时,它尤为有用,因为它有助于在潜在的脚本炸弹潜入代码库之前加以防范。
其他资源:
- 功能政策说明
- 功能政策规范
- 厨房水槽演示
- 功能政策开发者工具扩展程序 - 用于在网页上试用功能政策的测试工具。
- chromestatus.com 条目