1. 简介
Web 平台不断扩展功能和 API,提供更丰富的功能、更好的开发者体验和更高的性能。但开发者在应用内选择性地启用、禁用或修改部分浏览器功能和 API 的行为,仍然缺乏机制:
- 开发者可能希望选择性地禁用某些浏览器功能和 API,以“锁定”应用,作为安全或性能预防措施,防止自身或第三方内容在应用中执行时引入不期望或意外行为。
- 开发者可能希望选择性地启用某些默认禁用的浏览器功能和 API。例如某些功能在嵌入上下文中默认禁用,除非明确启用;有些功能还可能受其他策略要求约束。
- 开发者可能希望用策略向客户端或嵌入方声明有关某些功能和 API 的使用或不使用承诺。例如启用某些类型的浏览器“快速路径”优化,或声明符合其他嵌入方(如社交网络、搜索引擎等)的某些要求。
本规范定义了一种策略机制,解决上述使用场景。
本规范原名为 Feature Policy(特性策略)。
2. 示例
SecureCorp 公司希望禁用其应用中的全屏和地理定位 API。可以通过发送如下 HTTP 响应头定义权限策略:
Permissions-Policy: fullscreen=(), geolocation=()
指定空的来源列表后,相关功能将对所有文档(包括嵌套文档)禁用,无论其来源如何。
地理定位在所有跨域框架中默认禁用。FastCorp 公司有一个特定的跨域 iframe 需要启用地理定位。可以在 iframe 元素上添加 "allow
" 属性实现:
<iframe src="https://other.com/map" allow="geolocation"></iframe>
iframe 属性可以选择性地为某些框架启用功能,而不是全部,即使这些框架包含来自同一来源的文档。
SecureCorp 公司希望完全禁用除自身来源和 "https://example.com
" 来源外的所有后代可导航对象的地理定位 API,即使攻击者能在 SecureCorp 页面嵌入自己的 iframe。可以通过如下
HTTP 响应头为地理定位定义受限权限策略:
Permissions-Policy: geolocation=(self "https://example.com")
允许名单是一组包含一个或多个来源的列表,可包含应用自身来源(可用
"self
" 关键字表示)以及任何第三方来源。
启用此策略后,仍可通过 iframe 的 "allow
" 属性为特定框架授权地理定位,但只有托管来自 http://example.com 或 SecureCorp
本身内容的框架才会实际获得该 API 的使用权限。
SecureCorp 公司重组域名,现在需要将地理定位 API 的使用授权给其自身来源 ("https://example.com
") 及三个子域名
("https://geo.example.com
"、"https://geo2.example.com
" 和
"https://new.geo2.example.com
"),同时应禁用所有其他浏览上下文的地理定位 API。可以通过如下 HTTP 响应头实现:
Permissions-Policy: geolocation=(self "https://example.com" "https://geo.example.com" "https://geo2.example.com" "https://new.geo2.example.com")
如果 SecureCorp 公司认可授权给 "https://example.com
" 的任何子域,则可以用如下 HTTP 响应头:
Permissions-Policy: geolocation=(self "https://example.com" "https://*.example.com")
上述头部不仅允许 "https://geo.example.com
"、"https://geo2.example.com
" 和
"https://new.geo2.example.com
" 使用地理定位 API,也允许 "https://example.com
"
的其他所有子域使用。注意 "https://example.com
" 并不包含在 允许名单项 "https://*.example.com
" 中,需单独添加。
SecureCorp 公司重组服务,现在需要将地理定位 API 的使用授权给其自身来源 ("https://example.com
") 及三个非默认端口
("https://example.com:444
"、"https://example.com:445
" 和
"https://example.com:446
"),同时应禁用所有其他浏览上下文的地理定位 API。可以通过如下 HTTP 响应头实现:
Permissions-Policy: geolocation=(self "https://example.com" "https://example.com:444" "https://example.com:445" "https://example.com:446")
如果 SecureCorp 公司认可授权给 "https://example.com
" 的所有端口,则可以用如下 HTTP 响应头:
Permissions-Policy: geolocation=(self "https://example.com:*")
上述头部不仅允许 "https://example.com:444
"、"https://example.com:444
" 和
"https://example.com:445
" 使用地理定位 API,也允许 "https://example.com
" 的其他端口使用。
JSPlaygroundCorp 公司希望托管用户生成的 Web 应用,但希望浏览器能将这些应用对强大功能的权限彼此隔离。可以为每个 Web 内容或内容创作者创建独立子域,并将其作为顶级文档导航(框架和用户内容仍可用同源 iframe 分离)。
这是因为用户在浏览器中授予权限是针对他们认为在交互的顶级域名。
JSPlaygroundCorp 在此场景下应避免使用自身域名通过
allow
属性 iframe 用户生成的 Web 应用,否则会给予自身域名所有权限。
PlatformCorp 公司希望在其顶级域名下提供可嵌入第三方组件的市场,包括游戏。希望合理授权强大功能如 getUserMedia()
API,并承担追踪哪些组件应用需要某项功能的责任,通过定制化“安装”界面让终端用户掌控权限。
摄像头和麦克风在所有跨域框架中默认禁用。每个第三方组件有各自的子域,可用跨域 iframe 嵌入。PlatformCorp 可以在
allow
属性或
iframe
元素上控制是否授权每个子域摄像头或麦克风访问。
如果组件 "app1" 需摄像头权限,"app2" 需麦克风权限,"app3" 需两者,iframe 可如下:
<iframe allow="camera https://app1.site.com https://app3.site.com; microphone https://app2.site.com https://app3.site.com" src="https://doc1.site.com" sandbox="allow-same-origin allow-scripts"> </iframe>
iframe 属性可选择性地为某些框架启用功能,而不是全部,即使这些框架来自同源。沙箱令牌列表在实际应用中可能更长。
由于浏览器通常要求用户对顶级域名授权,组件请求摄像头或麦克风权限时,如果用户已信任 PlatformCorp,可能不会有额外的权限提示。
3. 其他及相关机制
[HTML5] 定义了
sandbox
属性用于
iframe
元素,允许开发者通过施加限制降低引入潜在不可信内容的风险——比如禁止提交表单、运行脚本和插件等。由 sandbox 指令定义的 [CSP2]
将此能力扩展到任意资源,无论是否被框架包裹,都可以要求同样的限制——比如通过 HTTP 响应头
(Content-Security-Policy: sandbox
)。这些机制使开发者可以:
- 通过 CSP 为任意资源设置和定制沙箱策略。
- 在应用内的每个
iframe
元素上设置和定制独立沙箱策略。
但上述机制存在一些局限:开发者无法自动为所有上下文应用策略,这使得在某些场景(如第三方内容注入框架且开发者无法控制时)难以或无法一致强制执行;没有机制选择性启用默认关闭的功能;沙箱机制会自动禁用所有沙箱特性,开发者需要逐项选择恢复,因此扩展沙箱特性集存在重大兼容风险。
权限策略旨在与沙箱机制结合使用(不会重复沙箱已涵盖的特性控制),并提供可扩展机制以解决上述局限。
4. 框架
4.1. 策略控制的特性
策略控制的特性是一种可通过权限策略在文档中启用或禁用的 API 或行为。
4.2. 策略
空权限策略是一个权限策略,其继承策略在每个已支持特性上都包含"Enabled
",其声明的策略的声明和报告配置均为空有序映射。
4.3. 继承策略
特性的继承策略feature是继承策略中以feature为键的值。在权限策略初始化后,其继承策略会包含每个已支持特性的值。
4.4. 头部策略
4.5. 容器策略
除了头部策略外,每个 子可导航对象 都有一个容器策略, 它是一个策略指令,可以为空。 容器策略可以通过 可导航容器上的属性进行设置。
容器策略对于
子可导航对象
会影响加载到该可导航对象中的任何Document
的
继承策略。
(参见 第9.7节 在容器中为来源定义特性的继承策略)。
4.6. 策略指令
策略指令 是一个有序映射, 将策略控制的特性 映射到对应的允许名单。
策略指令 在 HTTP 头中以 sf-dictionary 结构序列化表示,在 HTML 属性中则为其 ASCII 序列化。
4.7. 允许名单
权限策略中的允许名单 在概念上是一组来源。 一个允许名单可以是:
'self'
、'src'
和 'none'
可出现在允许名单的头部和属性字符串表示中。
这些关键词在解析时始终按上下文解释,仅其所指的来源会存储在允许名单中,关键词本身不在允许名单里。
要判断允许名单 是否匹配某个来源 origin,请执行如下步骤:
注意:未采用 CSP 的通配符匹配方案,因为其要求 HTTPS 协议。
4.8. 默认允许名单
每个策略控制的特性
都有一个默认允许名单。
默认允许名单
决定了在没有声明策略的
Document
中以及在顶级可遍历对象
时该特性是否允许,以及是否自动授权给子可导航对象中的文档。
默认允许名单 的可能取值有:
*
-
该特性在顶级可遍历对象中的
Document
及所有子可导航对象中默认允许。 可通过在可导航容器上显式指定 容器策略来禁用该特性, 或者通过为任意可导航对象 提供合适的Permissions-Policy
头部实现禁用。 'self'
- 该特性在顶级可遍历对象中的 文档, 以及子可导航对象中 文档与其 父对象的 文档为 同源时默认允许, 且父文档允许该特性。在子可导航对象中, 文档与 父对象的 文档为跨域时默认不允许。
5. 权限策略序列化
5.1. HTML 属性序列化
策略指令 在 HTML 属性中以其 ASCII 序列化形式表示,ABNF 如下:
serialized-permissions-policy = serialized-policy-directive *(";" serialized-policy-directive) serialized-policy-directive = feature-identifier RWS allow-list feature-identifier = 1*( ALPHA / DIGIT / "-") allow-list = allow-list-value *(RWS allow-list-value) allow-list-value = permissions-source-expression / "*" / "'self'" / "'src'" / "'none'" permissions-source-expression = scheme-source / host-source
5.2. 结构化头部序列化
策略指令在 HTTP 头中以结构化字段表示。[RFC8941]在该表示中,策略指令以字典结构表示。
每个字典成员将一个特性与一个允许名单关联。成员名称必须是 Token。如果该 token 不是用户代理的已支持特性,则该字典成员会在处理步骤中被忽略。
成员值代表允许名单,必须为以下之一:
-
包含 ASCII 权限来源表达式的字符串
-
Token
*
-
Token
self
-
包含零个或多个上述项的内部列表(Inner List)。
成员值可以有名为 "report-to"
的参数,其值必须为字符串。其他参数将被忽略。
内部列表中的其他项会在处理步骤中被忽略,成员值将按未包含这些项的方式处理。其他形式的成员值会导致整个字典成员在处理步骤中被忽略。
6. 传递
6.1. `Permissions-Policy
` HTTP
头字段
`Permissions-Policy
`
HTTP 头字段可用于响应(从服务器到客户端)以告知客户端应强制执行的权限策略。
`Permissions-Policy
` 是结构化头部,其值必须为字典。其
ABNF 为:
PermissionsPolicy = sf-dictionary
该字典的语义定义见 第5.2节 结构化头部序列化。
处理步骤定义见 第9.2节 从字典和来源构建策略。
6.2.
iframe
元素的 allow
属性
iframe
元素有一个
allow
属性,内容为
ASCII 序列化策略指令。
属性中指定特性的允许名单可以为空;此时允许名单的默认值为
'src'
,表示 iframe 的
src
属性 URL 的来源。
6.3. 支持旧特性的附加属性
部分由权限策略控制的特性已有 iframe 属性定义。本文规范将这些属性重新定义为影响
iframe
的
内容可导航对象的容器策略。
6.3.1. allowfullscreen
allowfullscreen
iframe
属性控制对
requestFullscreen()
的访问。
如果 iframe 元素有一个
allow
属性且值包含 "fullscreen
",则
allowfullscreen
属性必须无效。
否则,iframe 元素存在
allowfullscreen
属性时,会为 "fullscreen
" 特性在
iframe
元素的
内容可导航对象的容器策略添加 允许名单 *
。
<iframe allow="fullscreen">
的行为不同,是为了兼容现有 allowfullscreen
用法。如果
allow="fullscreen"
和 allowfullscreen
同时出现在 iframe 元素上,则会采用更严格的
allow="fullscreen"
的允许名单。
7. 脚本中的策略自省
7.1. 概述
文档中当前生效的策略可以被脚本观察。这可以用于决策,例如在无法确定某项特性是否启用的情况下决定展示什么用户界面。(有些特性可能没有可观察的失败模式,或者特性检测有副作用。)
文档和 iframe 都提供一个 PermissionsPolicy
对象,可用于检查适用于它们的权限策略。
7.1.1. 文档策略
要获取当前生效的策略,请使用
document.permissionsPolicy
。它返回一个 PermissionsPolicy
对象,可用于:
-
查询当前文档中指定特性的状态(允许或拒绝),
-
获取当前文档中所有可用特性(无论是否允许)的列表,
-
获取当前文档中所有允许特性的列表,或
-
获取当前文档中指定特性的允许名单。
<!doctype html> <script> const policy = document.permissionsPolicy; // 如果当前文档可以使用 WebUSB,则为 true。 const can_use_usb = policy.allowsFeature('usb'); // 如果 https://example.com 的新 frame 被允许使用 WebXR,则为 true。 if (policy.allowsFeature('xr-spatial-tracking', 'https://example.com')) { // 显示用于创建 frame 的 UI。 } else { // 显示其他 UI。 } // 获取被允许请求支付的所有来源列表。结果为显式来源列表,或单一元素 ['*'],表示允许所有来源。 const allowed_payment_origins = policy.getAllowlistForFeature('payment'); // 获取当前文档支持的所有特性(即使未被允许)。结果为字符串数组,每个代表一个特性。 const all_features = policy.features(); if (all_features.includes('geolocation')) { // 添加一个子 frame 到第三方地图服务。 } </script>
7.1.2. 框架策略
也可以从包含 iframe 的文档中检查 iframe 元素上的策略。此时的策略对象代表该框架的可观察策略,仅依赖于当前文档和 iframe 元素的属性。它不会透露特性在该框架中当前是否被允许,因为框架中的文档可能已通过 HTTP 头应用了自己的策略,或已导航到新的来源。此时如果透露 iframe 元素嵌套导航中的实际策略,可能会泄露跨域文档的行为信息。
<!doctype html> <iframe id="frame" allow="fullscreen; xr-spatial-tracking"></iframe> <script> const iframe_element = document.getElementById("frame"); const iframe_policy = iframe_element.permissionsPolicy; // 如果被嵌入的文档允许使用 WebXR,则为 true if (iframe_policy.allowsFeature('xr-spatial-tracking')) { // 显示虚拟现实控制 } </script>
iframe 元素上的可观察策略与实际加载到框架中的内容无关(避免跨域信息泄露),甚至与是否在文档树中也无关。
<!doctype html> <!-- 当 src 属性中的文档被加载时,该 frame 不允许使用 fullscreen --> <iframe id="frame" allow="fullscreen https://example.com" src="https://example.net/" ></iframe> <script> const iframe_element = document.getElementById("frame"); const iframe_policy = iframe_element.permissionsPolicy; // 由于 src 属性中的 URL 未被策略允许使用 fullscreen,这里为 false。 const is_fullscreen_allowed_in_frame = iframe_policy.allowsFeature('fullscreen'); const new_frame = document.createElement('iframe'); new_frame.allow = 'sync-xhr'; // 这里为 true,因为 iframe 被允许在其 src 属性指定的任何 URL 上使用 sync-xhr,即使该属性尚未设置。 const is_sync_xhr_allowed = new_frame.permissionsPolicy.allowsFeature('sync-xhr'); </script>
7.2. permissionsPolicy 对象
[Exposed =Window ]interface {
PermissionsPolicy boolean (
allowsFeature DOMString ,
feature optional DOMString );
origin sequence <DOMString >();
features sequence <DOMString >();
allowedFeatures sequence <DOMString >(
getAllowlistForFeature DOMString ); };
feature partial interface Document { [SameObject ]readonly attribute PermissionsPolicy ; };
permissionsPolicy partial interface HTMLIFrameElement { [SameObject ]readonly attribute PermissionsPolicy ; };
permissionsPolicy
PermissionsPolicy
对象有一个关联节点,
即一个 Node
。
关联节点在创建
PermissionsPolicy
对象时设置。
PermissionsPolicy
对象有一个默认来源,
是一个来源,其值取决于
PermissionsPolicy
对象的关联节点状态:
-
如果
PermissionsPolicy
对象的 关联节点是Document
, 则其 默认来源为Document
的 来源。 -
如果
PermissionsPolicy
对象的 关联节点是Element
, 则其 默认来源为Element
的 声明来源。
每个 Document
都有一个策略对象,
是一个 PermissionsPolicy
实例,其 关联节点即该
Document
。
获取 Document
的
permissionsPolicy
IDL 属性时,必须返回该 Document
的
策略对象。
每个
iframe
元素有一个策略对象,
是一个 PermissionsPolicy
实例,其 关联节点为
该元素本身。
获取
iframe
的
permissionsPolicy
IDL 属性时,必须返回该
iframe
的
策略对象。
allowsFeature(feature, origin)
方法必须执行以下步骤:
-
如果 origin 被省略,则将 origin 设为该
PermissionsPolicy
对象的 默认来源。 -
令 policy 为该对象的可观察策略。
-
如果 policy 允许 feature 对 origin,返回 true。
-
否则返回 false。
features()
方法必须执行以下步骤:
-
令 result 为一个空有序集合。
-
对每个已支持特性 feature:
-
将 feature 添加到 result。
-
-
返回 result
allowedFeatures()
方法必须执行以下步骤:
-
令 result 为一个空有序集合。
-
令 origin 为该对象的 默认来源。
-
令 policy 为该对象的可观察策略。
-
对每个已支持特性 feature:
-
如果 policy 允许 feature 对 origin,则将 feature 添加到 result。
-
-
返回 result
getAllowlistForFeature(feature)
方法必须执行以下步骤:
-
令 result 为一个空列表。
-
令 origin 为该对象的 默认来源。
-
令 policy 为该对象的可观察策略。
-
如果 feature 未被 policy 允许对 origin,返回 result
-
如果 allowlist 是特殊值
*
:-
将 "
*
" 添加到 result -
返回 result。
-
-
如果 allowlist 的 self-origin 不为 null, 则将其序列化添加到 result。
-
如果 allowlist 的 src-origin 不为 null, 则将其序列化添加到 result。
-
否则,对 allowlist 的 表达式中的每个权限来源表达式 item:
-
将 item 添加到 result
-
-
返回 result。
任何 Node 的可观察策略是一个权限策略,包含从当前文档可见的可导航对象策略信息。
获取 Document document 的可观察策略,返回 document 的权限策略。
获取 Element node 的可观察策略,执行以下步骤:
-
令 inherited policy 为一个空有序映射。
-
-
令 isInherited 为运行 在容器中为来源定义特性的继承策略方法,参数为 feature、node 和 node 的 声明来源。
-
设置 inherited policy[feature] 为 isInherited。
-
-
返回一个新的权限策略,其继承策略为 inherited policy, 声明策略为一个具有空 声明和 报告配置的新有序映射的结构体。
获取 Element node 的声明来源,执行以下步骤:
-
如果 node 的 节点文档的 沙箱来源浏览上下文标志已设置,则返回一个新的不透明来源。
-
如果 node 的
sandbox
属性已设置,且不包含allow-same-origin
关键字,则返回一个新的不透明来源。 -
如果 node 的
src
属性已设置:-
令 url 为解析 node 的 src 属性(相对于 node 的 节点文档)的结果。
-
如果 url 不是失败,则返回 url 的来源。
-
-
返回 node 的 节点文档的来源。
声明来源概念旨在表示嵌入页面意图加载到框架中的文档来源。这意味着,例如,如果浏览器不支持
sandbox
或 srcdoc
属性,则在计算声明来源时不应考虑这些属性。
8. 报告
权限策略违规报告表示某些Document的行为违反了权限策略。每个具体策略控制特性的规范需定义什么情况属于违反该策略,以及如何判断违规发生。
权限策略违规报告的报告类型为 "permissions-policy-violation"。
权限策略违规报告对ReportingObserver是可见的。
[Exposed =Window ]interface :
PermissionsPolicyViolationReportBody ReportBody { [Default ]object ();
toJSON readonly attribute DOMString ;
featureId readonly attribute DOMString ?;
sourceFile readonly attribute long ?;
lineNumber readonly attribute long ?;
columnNumber readonly attribute DOMString ;
disposition readonly attribute DOMString ?;
allowAttribute readonly attribute DOMString ?; };
srcAttribute
权限策略违规报告的body,在 JavaScript
中由 PermissionsPolicyViolationReportBody
表示,包含如下字段:
-
sourceFile:如已知,为违规发生的文件,否则为 null。
-
lineNumber:如已知,为sourceFile中违规发生的行号,否则为 null。
-
columnNumber:如已知,为sourceFile中违规发生的列号,否则为 null。
-
disposition:字符串,指示本次违规的权限策略是否被强制执行。disposition为 "enforce" 表示策略被强制执行,为 "report" 则表示仅生成了本报告(用户代理未采取其他措施)。
8.1. `Permissions-Policy-Report-Only
`
HTTP 头字段
`Permissions-Policy-Report-Only
`
HTTP 头字段可用于响应(服务器到客户端),以告知客户端不强制执行的权限策略,而是用于在其中声明的策略如果将要被违反时触发报告(假如该策略处于激活状态)。
`Permissions-Policy-Report-Only
`
是结构化头部,其值必须为字典。
该字典的语义定义见 第5.2节 结构化头部序列化。
处理步骤定义见 第9.2节 从字典和来源构建策略。
9. 算法
9.1. 处理响应策略
-
令 header name 为 "
Permissions-Policy-Report-Only
"(如果 report-only 为 True),否则为 "Permissions-Policy
"。 -
令 parsed header 为执行 获取结构化字段值,参数为 header name 和 "dictionary",从 response 的header list。
-
如果 parsed header 为 null,返回一个空有序映射。
-
令 policy 为执行 从字典和来源构建策略(参数为 parsed header 和 origin)的结果。
-
返回 policy。
9.2. 从字典和来源构建策略
-
令 declarations 为一个空有序映射。
-
令 reporting-config 为一个空有序映射。
-
对于每个 feature-name → (value, params) 属于 dictionary:
-
令 feature 为由 feature-name 标识的策略控制的特性。
-
如果 params["report-to"] 存在且为字符串,则令 reporting-config[feature] = params["report-to"]。
-
令 allowlist 为一个新的允许名单。
-
如果 value 是 token
*
,或 value 是包含 token*
的列表,则令 allowlist 为特殊值*
。 -
否则:
-
如果 value 是 token
self
,令 allowlist 的 self-origin 为 origin。 -
否则若 value 是列表,则对每个element属于value:
-
如果 element 是 token
self
,令 allowlist 的 self-origin 为 origin。
-
-
-
令 declarations[feature] = allowlist。
-
返回 «declarations, reporting-config»。
9.3. 解析策略指令
-
令 directive 为一个空有序映射。
-
对于每个 serialized-declaration,由严格按分隔符U+003B(;)分割 value得到:
-
令 tokens 为按 ASCII 空白分割 serialized-declaration的结果。
-
如果 tokens 是空列表,则继续。
-
令 feature-name 为 tokens 的第一个元素。
-
令 feature 为由 feature-name 标识的策略控制的特性。
-
令 targetlist 为 tokens 的剩余元素(如有)。
-
令 allowlist 为一个新的允许名单。
-
如果 targetlist 中有任何元素为字符串 "
*
",则令 allowlist 为特殊值*
。 -
否则:
-
如果 targetlist 为空且有 target origin,令 allowlist 的 src-origin 为 target origin。
-
对每个 element 属于 targetlist:
-
如果 element 与 "
'self'
" ASCII 不区分大小写匹配:-
令 allowlist 的 self-origin 为 container origin。
-
继续下一个 element。
-
-
如果有 target origin 且 element 与 "
'src'
" ASCII 不区分大小写匹配:-
令 allowlist 的 src-origin 为 target origin。
-
继续下一个 element。
-
-
令 result 为执行URL 解析器处理 element 的结果。
-
如果 result 不是失败:
-
-
-
令 directive[feature] = allowlist。
-
-
返回 directive
9.4. 处理权限策略属性
9.5. 为可导航对象创建权限策略
9.6. 根据响应为可导航对象创建权限策略
9.7. 在容器中为来源定义特性的继承策略
Document
的来源(origin),以及一个可选布尔值(report-only,默认值为
False),本算法返回 feature 的继承策略值。
-
如果 container 为 null,返回 "
Enabled
"。 -
如果运行 获取指定来源的特性值,参数为 feature、container 的节点文档、container 的节点文档的来源和 report-only 的结果为 "
Disabled
",返回 "Disabled
"。 -
如果运行 获取指定来源的特性值,参数为 feature、container 的节点文档、origin 和 report-only 的结果为 "
Disabled
",返回 "Disabled
"。 -
令 container policy 为运行 处理权限策略属性 的结果,参数为 container。
-
如果 feature 存在于 container policy:
-
如果 feature 的默认允许名单为
*
,返回 "Enabled
"。 -
如果 feature 的默认允许名单为
'self'
,且 origin 与 container 的节点文档的来源为同源,返回 "Enabled
"。 -
否则返回 "
Disabled
"。
9.8. 获取指定来源的特性值
9.9. 检查权限策略
9.10. 文档中指定来源的特性是否启用?
Document
对象(document)、一个来源(origin)、一个可选布尔值(report,默认值为
True),如果该特性应被视为禁用则返回 "Disabled
",否则返回 "Enabled
"。若 report 为
True,则当特性在 document 的权限策略或仅报告权限策略中未启用时,会生成并队列报告。
注意: report 默认值 True 意味着多数权限策略检查在特性未启用时会生成违规报告。这是预期结果,因为大多数检查都是对实际特性使用进行的。如果只是查询特性状态而非实际尝试使用,应将 report 设为 False。
-
令 policy 为 document 的权限策略。
-
令 report-only policy 为 document 的仅报告权限策略。
-
令 result 为调用检查权限策略,参数为 policy、 feature、origin 和 document 的来源。
-
令 report-only result 为调用检查权限策略,参数为 report-only policy、feature、origin 和 document 的来源。
-
如果 report 为 True:
-
令 settings 为 document 的环境设置对象。
-
如果 result 为 "
Disabled
":-
令 endpoint 为调用获取特性的报告端点,参数为 feature 和 policy 的结果。
-
调用 为 settings 生成权限策略违规报告,参数为 feature、settings、"
Enforce
" 和 endpoint。
-
-
否则,如果 report-only result 为 "
Disabled
":-
令 report-only endpoint 为调用获取特性的报告端点,参数为 feature 和 report-only policy 的结果。
-
调用 为 settings 生成权限策略违规报告,参数为 feature、settings、"
Report
" 和 report-only endpoint。
-
-
-
返回 result
9.11. 获取特性的报告端点
9.12. 检查容器中的权限策略潜在违规
-
令 document 为 container 的节点文档。
-
令 settings 为 document 的环境设置对象。
-
-
如果运行 在容器中为来源定义特性的继承策略, 参数为 feature、container 和 container 的声明来源 的结果为 "
Disabled
":-
调用 为 settings 生成潜在权限策略违规报告, 参数为 feature、settings、"
Enforce
"、endpoint、 allowAttribute、srcAttribute。
-
否则,如果运行 在容器中为来源定义特性的继承策略, 参数为 feature、container、container 的声明来源和 True 的结果为 "
Disabled
":-
令 report-only endpoint 为调用 获取特性的报告端点,参数为 feature 和 document 的仅报告权限策略。
-
调用 为 settings 生成潜在权限策略违规报告, 参数为 feature、settings、"
Report
"、report-only endpoint、 allowAttribute、srcAttribute。
-
-
9.13. 为 settings 生成权限策略违规报告
-
令 body 为一个新的
PermissionsPolicyViolationReportBody
, 初始化如下:- featureId
-
feature 的字符串表示。
- sourceFile
-
null
- lineNumber
-
null
- columnNumber
-
null
- disposition
-
disposition
-
如果用户代理当前正在执行脚本,且能从 settings 提取源文件 URL、行号和列号,则相应设置 body 的 sourceFile、 lineNumber 和 columnNumber。
-
执行 生成并队列报告,参数为 body、 "permissions-policy-violation"、endpoint 和 settings。
9.14. 为 settings 生成潜在权限策略违规报告
-
令 body 为一个新的
PermissionsPolicyViolationReportBody
, 初始化如下:- featureId
-
feature 的字符串表示。
- sourceFile
-
null
- lineNumber
-
null
- columnNumber
-
null
- disposition
-
disposition
- allowAttribute
-
allowAttribute
- srcAttribute
-
srcAttribute
-
如果用户代理当前正在执行脚本,且能从 settings 提取源文件 URL、行号和列号,则相应设置 body 的 sourceFile、 lineNumber 和 columnNumber。
-
执行 生成并队列报告,参数为 body、 "potential-permissions-policy-violation"、endpoint 和 settings。
9.15. 请求是否允许使用特性?
true
,否则返回 false
。
-
令 client 为 request 的client。
-
如果 client 为 null,返回
false
。 -
如果 client 的全局对象不是
Window
, 返回false
。非 Window 上下文(WorkerGlobalScope
或WorkletGlobalScope
的权限策略正在 issue #207 中讨论。待定后,更新本算法以允许这些上下文中的 fetch 使用策略控制的特性。 在此之前,这些上下文中所有策略控制的特性(如向第三方发送 Client Hints)均不允许。 -
设置 document 为 client 的全局对象的 关联
Document
。 -
令 origin 为 request 的来源。
-
令 result 为运行 文档中指定来源的特性是否启用?, 参数为 feature、document、origin。
-
如果 result 为 "
Enabled
",返回true
。 -
否则返回
false
。
10. 对其他规范的变更
10.1. 对 HTML 规范的变更
每个Document
都有一个仅报告权限策略,
即一个权限策略,初始为空。
在 7.5.1 共享文档创建基础设施,第3步后插入如下步骤:
-
令 reportOnlyPermissionsPolicy 为调用 根据响应为可导航对象创建权限策略, 参数为 navigationParams 的 navigable 的 container、navigationParams 的 origin、navigationParams 的 response 和 True 的结果。
并在同一节第10步,设置新 Document
的
仅报告权限策略为
reportOnlyPermissionsPolicy。
在 iframe 加载事件步骤,第6步后插入如下步骤:
-
调用 检查容器中的权限策略潜在违规, 参数为 element、element 的 allow 属性、element 的 src 属性。
11. IANA 注意事项
应更新永久消息头字段注册表,内容如下 [RFC3864]:
- 头字段名称
- Permissions-Policy
- 适用协议
- http
- 状态
- standard
- 作者/变更控制方
- W3C
- 规范文档
- https://www.w3.org/TR/permissions-policy/
12. 隐私与安全
本规范标准化了一种机制,允许嵌入页面为被嵌入页面设置并强制执行策略。类似于 iframe 的
sandbox
,无需被嵌入页面的明确许可即可实现,这意味着通过在另一个文档中以合适的容器策略嵌入,已发布网站的现有特性行为可能被改变。
因此,最大的隐私和安全关注点包括:
- 跨域子框架行为暴露给嵌入者
- 由嵌入者控制的子框架出现意外行为变更
在一定程度上,这些问题在 Web 平台中已存在,本规范至少试图不使其变得更糟。
安全和隐私问题还可能由各特性设计导致,因此集成本规范时需谨慎。本节尝试对哪些行为可能引发此类问题提供指导。
12.1. 跨域行为暴露
特性设计应确保在框架文档中违反策略时,其他框架的文档无法观察到。例如,假设某特性在策略禁用时被使用,会在嵌入文档中触发事件,则嵌入者可借此获知嵌入文档的状态。如果该特性仅在用户登录时被使用,嵌入者可为该框架禁用该特性,再监听事件,以判断用户是否已登录。
自省 API 设计只显示嵌入文档可推断出的子框架策略信息。该可观察策略不受框架文档通过 HTTP 头传递的影响,也不会因框架自身导航(即便切换到不同来源、应用不同策略)而改变。只有通过设置
src
属性进行导航,<iframe>
元素的可观察策略才会更新。
12.2. 意外行为变更
权限策略机制赋予文档在子框架加载时控制哪些特性可用的能力。如果某特性代表 Web 平台的现有、长期行为,这可能意味着 Web 上已发布内容并未预期特定 API 会失败。
举个实际(但人为)的例子,假设有文档用同步 XMLHttpRequest 检查用户是否有足够权限访问页面:
<!DOCTYPE html> <h1>欢迎来到 SecureCorp!</h1> <script> var req = new XMLHttpRequest(); req.open("GET", "/api/security_check.json", false); req.send(); if (req.response == "untrusted user") { // 用户未登录,重定向到安全页面 location.href = "/security_check_failed.html"; } </script> <!-- 页面继续,假设用户已登录 -->
如果该文档被页面嵌入且禁用了 "sync-xhr
" 特性,则 XMLHttpRequest.open()
调用会失败,安全检查就会被绕过。
注意,此类强制行为在 Web 上原本就可能发生:有些特性只允许在顶级文档使用,在任何 iframe 都不允许,iframe 沙箱也可用类似方式嵌入不具备某些依赖特性的框架。
一般来说,此问题有两种缓解方式:
- 易受攻击页面可通过
X-Frame-Options
HTTP 头不允许被攻击者框架化。 - 网站应使用特性检测判断 API 或行为可用后再使用,并处理 API 返回的所有已文档化错误或抛出的异常。
- 如无法特性检测,新 Web 内容可通过
policy
对象检查当前强制的权限策略,并据此调整行为或界面。
集成特性到权限策略时,作者可决定文档在特性被禁用时何时及如何失败。应尽量利用已有失败模式,以提高现有内容已正确处理此类失败的概率。
12.3. 嵌入策略暴露
已采取措施限制页面能推断的跨域嵌入页面行为信息。但在某些场景下,被嵌入页面可通过检查嵌入者强制的策略推断嵌入者信息。
这类似于现有的 document.fullscreenEnabled
属性,嵌入文档可由此推断嵌入者是否赋予其使用全屏 API
的能力。如果只有在特定情形(如用户登录嵌入站点时)才赋予权限,则被嵌入站点可获知嵌入者的状态。