权限策略

实验性: 这是一项实验性技术
在生产中使用此技术之前,请仔细检查浏览器兼容性表格

权限策略为 Web 开发者提供了明确声明网站上哪些功能可以使用、哪些功能不能使用的机制。你可以定义一组“策略”,以限制网站代码可以访问哪些 API 或修改浏览器对某些功能的默认行为。这使得你即使在代码库不断演进的情况下,也能强制执行最佳实践,并更安全地整合第三方内容。

权限策略类似于内容安全策略,但它控制的是功能而不是安全行为。

权限策略的应用示例

  • 更改移动端和第三方视频自动播放的默认行为。
  • 限制网站使用摄像头、麦克风或扬声器等敏感设备。
  • 允许 iframe 使用全屏 API
  • 为了提高性能,阻止不在视口中可见的项目被脚本化。

注意:权限策略曾被称为功能策略。名称已更改,HTTP 头语法也已更改,因此如果您过去使用过功能策略,请牢记这一点并查看浏览器支持表格。<iframe allow=" ... "> 语法保持不变。

概念与用法

Web 提供了可能存在隐私或安全风险的功能和 API,如果这些功能被滥用。在这种情况下,你可能希望严格限制网站上功能的使用方式。在每种情况下,Web 开发者都应该有一种直观或不破坏性的方式来检测和处理功能被禁用情况。

一些方法包括

  • 需要用户授予权限的 JavaScript API 返回“权限被拒绝”。
  • 提供功能访问的 JavaScript API 返回 false 值或抛出错误。
  • API 甚至不被暴露,就像它们不存在一样。
  • 控制功能行为的选项具有不同的默认值。

注意:新引入的功能可能具有明确的 API 来表示状态。稍后与权限策略集成的现有功能通常会使用现有机制。

权限策略允许您控制哪些源可以在顶级页面和嵌入的<iframe><iframe>使用哪些功能。其目的是强制执行良好用户体验的最佳实践,并提供对敏感强大功能(即用户在相关代码执行前必须明确同意使用这些功能)的细粒度控制。

权限策略提供了两种指定策略的方式

这些是相互独立但又相互关联的——有关详细信息,请参阅嵌入内容的策略继承

注意:脚本可以通过位于Document.featurePolicyHTMLIFrameElement.featurePolicyFeaturePolicy对象以编程方式查询权限策略信息。

要控制每个功能,您需要编写一个包含以下内容的策略

  • 一个指令,用于标识要控制的功能的名称。请参阅可用指令列表
  • 一个允许列表,它是应该控制该功能的来源列表。您可以为所有或特定来源启用该功能,或阻止其在所有来源中使用。

请参阅下面的多个示例。

与权限 API 的关系

权限策略和权限 API 密切相关,但有所不同。这些技术控制的权限功能有所重叠。

  • 权限策略允许服务器设置是否可以在特定文档(或其中嵌入的<frame>)中使用某个功能。这些功能被称为策略控制功能——请参阅权限策略指令列表
  • 权限 API 根据用户授予的权限来控制对功能的访问。这些功能记录在权限注册表中。

两种技术中用于标识每个功能的字符串保持一致,例如,地理定位 APIgeolocation。权限注册表中的大多数 API 功能也都有相应的权限策略指令。一个例外是通知 API

通常,当权限策略阻止使用强大功能时,甚至不会向用户请求使用该功能的权限,并且权限 API 的query()方法将返回state值为denied

另请参阅权限 > 与权限策略规范的关系

允许列表

允许列表是一个来源列表,包含一个或多个以下括号内的值,用空格分隔

  • *:此文档以及所有嵌套浏览上下文(<iframe>)都将允许该功能,无论其来源如何。
  • () (空允许列表):该功能在顶级和嵌套浏览上下文中被禁用。<iframe> allow 属性的等效值是 'none'
  • self:此文档以及所有同源的嵌套浏览上下文(<iframe>)中都将允许该功能。该功能在嵌套浏览上下文中的跨源文档中不允许。self 可以被视为 https://your-site.example.com 的简写。<iframe> allow 属性的等效值是 'self'
  • 'src':只要加载到此<iframe>中的文档与其src属性中的 URL 来自同一源,则允许在该<iframe>中使用该功能。此值仅在<iframe> allow属性中使用,并且是<iframe>中的默认允许列表值。
  • "<origin>":该功能允许用于特定来源(例如,"https://a.example.com")。来源应以空格分隔。请注意,<iframe> allow 属性中的来源无需加引号。

*() 只能单独使用,而 selfsrc 可以与一个或多个来源组合使用。

注意:指令有一个默认允许列表,对于Permissions-Policy HTTP 头,它始终是*selfnone之一,如果未在策略中明确列出,则控制默认行为。这些在单独的指令参考页面上指定。对于<iframe> allow属性,默认行为始终是src

在支持的情况下,您可以在权限策略源中包含通配符。这意味着您不必在允许列表中明确指定多个不同的子域,而可以使用通配符在一个源中指定它们全部。

因此,不是这样

http
("https://example.com" "https://a.example.com" "https://b.example.com" "https://c.example.com")

您可以指定

http
("https://example.com" "https://*.example.com")

注意: "https://*.example.com" 不匹配 "https://example.example.com"

允许列表示例

  • *
  • ()
  • (self)
  • (src)
  • ("https://a.example.com")
  • ("https://a.example.com" "https://b.example.com")
  • (self "https://a.example.com" "https://b.example.com")
  • (src "https://a.example.com" "https://b.example.com")
  • ("https://*.example.com")

Permissions-Policy 头语法

通用语法如下所示

http
Permissions-Policy: <directive>=<allowlist>

因此,例如要阻止所有对地理位置的访问,您将这样做

http
Permissions-Policy: geolocation=()

或者要允许访问部分源,您可以这样做

http
Permissions-Policy: geolocation=(self "https://a.example.com" "https://b.example.com")

可以通过发送带有逗号分隔策略列表的头文件,或者为每个策略发送单独的头文件,来同时控制多个功能。

例如,以下是等效的

http
Permissions-Policy: picture-in-picture=(), geolocation=(self "https://example.com"), camera=*;

Permissions-Policy: picture-in-picture=()
Permissions-Policy: geolocation=(self "https://example.com")
Permissions-Policy: camera=*

嵌入式框架语法

为了使<iframe>启用某项功能,其允许的源也必须在父页面的允许列表中。由于这种继承行为,建议在 HTTP 头中指定对某项功能最广泛可接受的支持,然后在每个<iframe>中指定所需的子集支持。

通用语法如下所示

html
<iframe src="<origin>" allow="<directive> <allowlist>"></iframe>

因此,例如要阻止所有对地理位置的访问,您将这样做

html
<iframe src="https://example.com" allow="geolocation 'none'"></iframe>

要将策略应用于当前源和其他源,您可以这样做

html
<iframe
  src="https://example.com"
  allow="geolocation 'self' https://a.example.com https://b.example.com"></iframe>

这很重要:默认情况下,如果一个 <iframe> 导航到另一个源,该策略不会应用于 <iframe> 导航到的源。通过在 allow 属性中列出 <iframe> 导航到的源,应用于原始 <iframe> 的权限策略将应用于 <iframe> 导航到的源。

通过在 allow 属性中包含以分号分隔的策略指令列表,可以同时控制多个功能。

html
<iframe
  src="https://example.com"
  allow="geolocation 'self' https://a.example.com https://b.example.com; fullscreen 'none'"></iframe>

src值值得特别提一下。我们上面提到,使用此允许列表值意味着只要加载到此<iframe>中的文档与其src属性中的 URL 来自同一源,则允许在此<iframe>中使用相关功能。此值是allow中列出的功能的默认 allowlist值,因此以下两者是等效的

html
<iframe src="https://example.com" allow="geolocation 'src'">
  <iframe src="https://example.com" allow="geolocation"></iframe
></iframe>

注意:如您所见,<iframe> 策略的语法与 Permissions-Policy 头的语法略有不同。前者仍然使用旧版功能策略规范的相同语法,该规范已被权限策略取代。

围栏框架和权限策略

<fencedframe> 与权限策略的交互方式与 <iframe> 相同,但限制得多。只有设计用于 <fencedframe> 的特定功能才能通过为其设置的权限策略启用;其他策略控制的功能在此上下文中不可用。

有关详细信息,请参阅适用于围栏框架的权限策略

嵌入式内容的策略继承

脚本继承其浏览上下文的策略,无论其来源如何。这意味着顶级脚本继承主文档的策略。

所有 <iframe> 都继承其父页面的策略。如果 <iframe> 具有 allow 属性,并且父页面具有 Permissions-Policy,则父页面和 allow 属性的策略将合并,并采用最严格的子集。为了使 <iframe> 启用某个功能,该源必须同时在父页面和 allow 属性的允许列表中。

在策略中禁用功能是一次性开关。如果父框架为子框架禁用了某个功能,则子框架无法重新启用它,子框架的任何后代也无法重新启用它。

示例

HTTP 头和<iframe>策略的结合

例如,假设我们想在自己的源和来自我们信任的广告网络中的嵌入内容中启用地理位置使用。我们可以这样设置页面范围的权限策略

http
Permissions-Policy: geolocation=(self "https://trusted-ad-network.com")

在我们的广告 <iframe> 中,我们可以这样设置对 https://trusted-ad-network.com 源的访问权限

html
<iframe src="https://trusted-ad-network.com" allow="geolocation"></iframe>

如果不同的源最终被加载到<iframe>中,它将无法访问地理位置

html
<iframe src="https://rogue-origin-example.com" allow="geolocation"></iframe>

规范

规范
权限策略
# permissions-policy-http-header-field

浏览器兼容性

另见