摘要
借助功能政策,Web 开发者可以选择性地启用、停用和修改浏览器中某些 API 和 Web 功能的行为。它与 CSP 类似,但控制的是功能,而不是控制安全性!
功能政策本身是开发者与浏览器之间达成的选择性协议,有助于我们实现构建(和维护)优质 Web 应用的目标。
简介
面向 Web 构建应用是一项艰巨的任务。构建一款性能出色且采用所有最新最佳实践的顶级 Web 应用已经很难了。要想长期保持这种出色的体验,难度就更大了。随着项目的不断发展,开发者会加入,新功能会发布,代码库也会不断扩大。您曾经获得的“卓越体验”™可能会开始恶化,用户体验也开始受到影响!“功能政策”旨在帮助您随时掌握最新动态。
借助功能政策,您可以选择启用一组“政策”,以便浏览器对您网站中使用的特定功能强制执行这些政策。这些政策会限制网站可以访问哪些 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,但阻止第三方内容访问该 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 在 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-write
和 sync-xhr
等其他政策时应更加谨慎。开启这些功能可能会破坏广告等第三方内容。另一方面,特性政策可以作为一种自我检查工具,确保您的网页绝不会使用这些糟糕的 API!
我在开发环境还是生产环境中使用功能政策?
两者均包含。我们建议您在开发期间启用政策,并在正式版中让政策保持有效状态。在开发期间启用政策有助于您从一开始就走上正轨。这有助于您及时发现任何意外回归问题。在生产环境中将政策保持为启用状态,以确保为用户提供特定的用户体验。
有没有办法向我的服务器举报违反政策的行为?
Reporting API 正在开发中! 与网站可以选择接收有关 CSP 违规或弃用的报告类似,您也可以接收有关实际违反功能政策的报告。
iframe 内容的继承规则是什么?
脚本(第一方或第三方)会继承其浏览上下文的政策。这意味着顶级脚本会继承主文档的政策。
iframe
会继承其父级网页的政策。如果 iframe
具有 allow
属性,则父级页面和 allow
列表中更严格的政策将胜出。如需详细了解 iframe
的用法,请参阅 iframe 上的 allow
属性。
如果我应用了政策,该政策是否会在网页导航期间保持有效?
不会。政策的有效期针对的是单页导航响应。如果用户转到新页面,则必须在新响应中明确发送 Feature-Policy
标头,才能应用该政策。
哪些浏览器支持功能政策?
如需了解有关浏览器支持的最新详情,请访问 caniuse.com。
目前,Chrome 是唯一支持功能政策的浏览器。不过,由于整个 API Surface 都可选择启用或检测功能,因此功能政策非常适合用于渐进式增强。
总结
功能政策有助于指明通往更好的用户体验和出色效果的道路。在开发或维护应用时,它尤为有用,因为它有助于在潜在的脚本炸弹潜入代码库之前加以防范。
其他资源:
- 功能政策说明
- 功能政策规范
- 厨房水槽演示
- 功能政策开发者工具扩展程序 - 用于在网页上试用功能政策的测试工具。
- chromestatus.com 条目