1. 简介
本文档定义了文档策略,它是一个框架,用于 将可配置特性设计为 Web 平台的一部分,并允许 Web 开发者将这些特性配置为其站点部署的一部分。
2. 示例 #
需要新的示例。暂时请参见解释文档。
3. 其他及相关机制
文档策略在作用范围上类似于一些现有的文档 配置机制,尽管它与每一种机制都有显著差异。
3.1. 与 Permissions Policy 的关系
Permissions Policy [PERMISSIONS-POLICY] 是另一种允许 作者在文档中配置特性的机制,其作用范围类似,尽管 它使用了不同的继承机制,这使其更适合 某些类型的特性,这些特性不同于适合由 文档策略控制的特性。
从历史上看,文档策略是对一系列 向 Permissions Policy(当时名为 Feature Policy) 提议新增特性的回应,这些特性要么不太适合现有的“feature”模型,要么 需要向 Permissions Policy 规范添加大量额外复杂性。 这包括带参数的特性、可选继承到子框架中的特性, 以及在弹出窗口中与其他顶级浏览上下文中 继承方式不同的特性。
这些特性现在被提议由文档策略覆盖,而 Permissions Policy 则用于以委托为主要 关注点的特性。Permissions Policy 特性是布尔值(要么启用,要么 禁用),如果在父框架中被禁用,则永远不能在子框架中重新启用, 并且通常遵循“在顶级浏览 上下文及其同源子级中可用;必须委托给跨源 框架”的模型。
相比之下,由文档策略控制的特性可以接受参数,并且 这些参数在不同框架中可以具有不相关的值(在父 框架中约束某个特性并不一定会约束其子 框架)。
3.2. 与 Content Security Policy 的关系
Content-Security-Policy [CSP] 也会配置 文档中的“features”, 尽管它主要关注页面中资源的来源, 而不是控制这些资源在加载后可以做什么。
CSP 还通过 sandbox 指令提供了另一种机制, 用于在文档上设置沙箱标志。如果沙箱标志被移动 到文档策略中,那么这可能是冗余的,因为这两个标头可能 编码相同的信息。
CSP-Embedded-Enforcement 引入了一种模型,用于强制子文档 遵守某项策略,并在 Fetch 期间将不符合要求的文档作为 网络错误拒绝。文档策略针对 必需策略机制采用了该模型。
3.3. 与 Sandboxing 的关系
Iframe 沙箱化是另一种用于控制 文档中特性的机制,并且其行为方式与文档策略的 必需策略非常相似:禁用某个特性可以被强加到 一个框架上,并影响加载到该框架中的所有内容。
由 iframe sandbox 属性控制的特性可以 非常自然地用文档策略表达。
iframe 沙箱化与文档策略之间的一个关键区别是, 当在框架上使用 'sandbox' 属性时,默认应用所有 沙箱特性,并且必须逐一重新启用它们。这使得 很难用新特性扩展沙箱化模型,因为任何新增内容都会 立即影响所有现有的沙箱化内容。此外,没有 机制让源服务器知道其内容将被沙箱化, 因此很难添加新的沙箱特性,这些特性可能会改变 沙箱化文档中的控制流,因为这可能会在现有内容中引入新的安全 漏洞。
4. 框架
4.1. 配置点
配置 点是 Web 平台 API 或行为, 可以通过文档策略启用、禁用或配置。 配置点应在描述底层 API 或行为的规范中定义, 尽管本文档附带了一个正在使用的已定义 配置点注册表。
一个配置 点具有一个名称,该名称是一个 token。
一个配置 点具有一个类型,它是以下之一:
-
boolean, -
integer, -
float,或 -
enum。
4.2. 策略
策略 配置是一个元组,由一个值(它是配置点的 范围中的元素)和一个报告端点组成,该端点是一个字符串, 并且可以为 null。
一个浏览上下文具有一个必需文档策略, 它是一个文档 策略。一个具有 null opener 浏览上下文的浏览上下文具有一个空的必需文档策略。
5. 必需策略序列化
-
在此说明必需策略如何作为结构化 标头被序列化。
-
确保存在一种规范形式(用于兼容性测试)。
6. 报告
部署文档策略的站点可能希望知道其页面上设置的任何策略
是否被违反。例如,一个站点设置了要求所有图像
匹配其容器大小的策略,可能希望在新的开发者或 CMS
将过大的图像插入内容时收到警报。
同样,部署了限制使用 document.write API 的策略的站点,
可能希望在某个使用它的脚本被导入时收到报告。
本节定义了一种使用 Reporting API 报告此类违规的机制。 [REPORTING]
站点也可能希望在强制执行策略之前, 在真实世界场景中测试该策略。本节还定义了一种“Report-only”模式, 在该模式下,用户代理可以监视本会构成策略违规的情况并 对其进行报告,而不强制执行该策略。这允许站点所有者努力将 真实世界中的违规次数降低到可接受水平,然后再实际 部署该策略。
报告只能来自配置策略的页面。 无法从违反必需 策略的嵌套页面接收报告。
“违规”按特性定义,但应始终反映 Web 开发者的操作,而不是直接反映用户的操作。
这意味着并非所有策略都可以进行报告。有一类 特性,其设置无法以任何有意义的方式被标记或脚本操作“违反”。 例如,一个假设的特性禁用了表单字段中的文本 输入,可以由用户代理强制执行,但 如果用户试图在这些字段中键入内容,从而需要执行强制措施, 这并不代表对该策略的违规,也不应 被报告。
6.1. 配置文档内报告
6.1.1. “report-to” 参数
任何指令都可以包含一个名为 report-to 的参数,该参数命名一个
报告端点,该特性的违规报告将
发送到该端点。
示例:
Document-Policy: something=1.0;report-to=endpoint1, something-else=?0;report-to=endpoint2
6.1.2. 设置默认报告端点
如果许多或所有特性的违规都应发送到同一个端点,
那么定义一个单一的默认端点可能更容易。
这可以通过特殊 token * 上的参数来定义。如果提供了默认端点,
则除非另有指定,所有违规
报告都将发送到该命名端点。如果某个特性也使用
report-to 参数指定了自己的端点,那么报告将转到该
端点。(报告不会发送到两个端点。)
示例:
Document-Policy: something=1.0, something-else=?0, *;report-to=endpoint
6.1.3. 禁用某个特性的报告
如果已经指定了默认端点,那么可能需要
禁用特定特性的报告。可以通过将特殊端点名称 none
指定为 report-to 参数的值来完成。
这将覆盖默认端点,并禁用该
特性的报告。
示例:
Document-Policy: something=1.0;report-to=none, something-else=?0,
*;report-to=endpoiont
6.2. 仅报告模式
文档策略可以是“report-only”策略。仅报告策略通过
Document-Policy-Report-Only 标头指定。违反
仅报告策略会像强制执行策略那样生成报告,
但不会导致用户代理采取任何其他操作。
Document-Policy-Report-Only
report-to 指令参数应与此
标头中的指令一起使用,否则它们完全不会产生任何效果。
示例:
Document-Policy-Report-Only: something=1.0;report-to=endpoint,
something-else=?0;report-to=endpoint2
7. 交付
7.1. 作为结构化标头的策略
策略在 HTTP 标头和 HTML 属性中表示为 sh-dictionary 结构的序列化。每个字典成员都是一个文档策略 指令。
文档 策略指令是序列化文档 策略的一个元素,并由一个指令名称(它是一个 sh-token) 以及相关参数组成。
指令名称可以是以下之一:
7.1.1. 参数
任何文档策略指令都可以包含一个名为
report-to 的参数,其值必须是字符串。
如果一个文档策略指令的指令名称命名了一个
配置
点,且其类型为 boolean,则没有必需参数。
如果一个文档策略指令的指令名称命名了一个
配置
点,且其类型为 integer,则有一个必需参数,其
值必须是该配置点的范围内的整数。
如果一个文档策略指令的指令名称命名了一个
配置
点,且其类型为 float,则有一个必需参数,其
值必须是该配置点的范围内的小数。
如果一个文档策略指令的指令名称命名了一个
配置
点,且其类型为 enum,则有一个必需参数,其
值必须为 'true',
且其名称必须是该配置点的范围中的 token。
示例:
-
boolean-feature -
boolean-feature=?0 -
integer-feature=2 -
float-feature=-0.2 -
enum-feature=state
7.2. HTTP 标头
7.2.1. Document-Policy
`Document-Policy` HTTP
标头可用于响应(服务器到客户端)中,以传达客户端应
强制执行的文档策略。
Document-Policy 标头是一个 Structured Header。其值
必须是一个字典。其 ABNF 为:
Document-Policy = sh-dictionary
如果任何字典成员名称没有命名受支持的配置点 或特殊值 "*",则该字典成员将被 处理步骤忽略。
7.2.2. Document-Policy-Report-Only
`Document-Policy-Report-Only`
HTTP 标头可用于响应(服务器到客户端)中,以为文档配置
仅报告文档策略。
Document-Policy-Report-Only 标头是一个 Structured Header。
其值必须是一个字典。它与 Document-Policy
标头具有完全相同的语法。
7.2.3. Require-Document-Policy
`Require-Document-Policy`
HTTP 标头字段是一个响应标头,用于向
客户端传达要应用于所有嵌套
内容的最低必需文档策略。
Require-Document-Policy 标头是一个 Structured Header 字典,
其语法与 Document-Policy 标头完全相同。
7.2.4. Sec-Required-Document-Policy
`Sec-Required-Document-Policy`
HTTP 标头字段是一个请求标头,用于向
服务器传达必须随请求返回的文档一起
发送的文档
策略。
该标头的值是一个或多个文档策略指令的 § 5 必需策略序列化
7.3.
iframe
元素的 policy 属性
iframe
元素具有一个 "policy" 属性,其中包含一个必需
策略指令(SH 格式)。
8. 集成
如果一个框架具有必需策略,那么对于任何传出的文档请求, 该策略必须在请求标头中通告,以告知服务器 用户代理将应用于该文档的策略。这允许 服务器更改返回的表示,以符合该 策略。
在存在必需策略请求标头的情况下,响应 必须包含兼容的文档策略标头,否则 fetch 将失败。
8.1. 与 HTML 的集成
以下更改应合入 [HTML]:
-
iframe元素应添加以下 IDL:
[CEReactions] attribute DOMString policy;
-
iframe policy 属性应定义如下:
-
在 HTML § 3.1.1 The Document object 中,添加以下行:
-
在创建新的浏览上下文 算法中:
-
在步骤 5 之后添加以下步骤:
-
将 browsingContext 的必需文档 策略设置为给定 browsingContext 为浏览上下文创建必需策略的结果。
-
-
将步骤 9(现在重新编号为 10)改为:
-
-
在process a navigate fetch 算法中:
-
在initialise the document object 算法中:
-
在步骤 3 之后添加以下步骤:
-
令 documentPolicy 为从 response 为 browsingContext 创建文档策略的结果。
-
令 nestedContextRequiredDocumentPolicy 为 从 response 为 browsingContext 创建 嵌套上下文文档策略的结果。
-
-
将步骤 6(现在重新编号为 8)改为:
-
令 document 为一个新的 Document,其 type 为 type, content type 为 contentType, origin 为 origin,permissions policy 为 permissionsPolicy,active sandboxing flag set 为 finalSandboxFlags,document policy 为 documentPolicy, 并且 nested context required document policy 为 nestedContextRequiredDocumentPolicy。
-
-
8.2. 与 Fetch 的集成
以下更改应合入 [FETCH]:
-
在 Fetch Standard § 2.2.5 Requests 中,添加以下内容:
-
在 Fetch Standard § 4.6 HTTP-network-or-cache fetch 中,在步骤 15 之后插入 以下内容:
-
如果 httpRequest 具有必需文档策略, 则
-
令 serializedRequiredPolicy 为对 httpRequest 的 必需文档 策略调用Serialize Required Policy的结果。
-
将
Sec-Required-Document-Policy/serializedRequiredPolicy 附加到 httpRequest 的标头列表。
-
-
-
在 Fetch Standard § 4.1 Main fetch 中,将以下算法添加到 步骤 11 的算法列表中:
9. 算法
9.1. 策略是否兼容?
-
对于 requiredPolicy 中的每个 configuration point → value:
-
如果 declaredPolicy[configuration point] 不存在,则 返回 false。
-
如果 value 比 declaredPolicy[configuration point] 更严格, 则返回 false。
-
-
返回 true。
9.2. 解析文档策略
-
如果 header 为 null,则返回 null。
-
令 policy 为一个新的有序映射。
-
令 defaultEndpoint 为一个新的字符串,设置为 null。
-
对于 header 中的每个 name->(value,parameters),
-
令 currentEndpoint 为一个新的字符串,设置为 null。
-
如果 parameters["report-to"] 存在并且是字符串,则:
-
将 currentEndpoint 设置为 parameters["report-to"] 的值。
-
-
如果 name 是字符串 "
*",则:-
将 defaultEndpoint 设置为 currentEndpoint。
-
-
否则,如果 name 是受支持配置点的名称, 则:
-
令 configuration point 为名称为 name 的受支持配置 点。
-
如果 policy[configuration point] 存在,则 继续处理下一个 element。
-
如果 configuration point 的类型为 boolean,则:
-
如果 configuration point 的类型为 enum,则:
-
如果 configuration point 的类型为 integer,则:
-
如果 configuration point 的类型为 float,则:
-
-
-
对于 policy 中的每个 configuration point → config,
-
返回 policy。
9.3. 序列化必需策略
-
令 dict 为一个新的有序映射。
-
令 features 为 requiredPolicy 的键。
-
按每个元素的名称以 ASCII 顺序对 features 排序。
-
对于 features 中的每个 feature:
-
令 value 为 requiredPolicy[feature]。
-
将 dict[feature] 设置为 value。
-
-
返回 dict 的序列化。
9.4. 为 浏览上下文创建必需策略
-
如果 browsingContext 是一个嵌套浏览上下文,则
-
令 requiredPolicy 为 browsingContext 的容器文档的嵌套上下文 必需文档 策略的克隆。
-
如果 browsingContext 的浏览上下文容器 具有 "policy" 属性,则
-
令 containerPolicy 为解析该属性的结果
-
对于 containerPolicy 中的每个 feature -> value:
-
如果 requiredPolicy[feature] 不 存在,或者 value 比 requiredPolicy[feature] 更严格,则将 requiredPolicy[feature] 设置为 value。
-
-
-
-
否则,令 requiredPolicy 为一个新的有序映射。
-
返回 requiredPolicy。
9.5. 从响应创建 文档策略
-
令 requiredPolicy 为给定 browsingContext 运行为浏览上下文创建必需策略的结果。
-
令 header 为对 response 的标头列表使用标头名称
Document-Policy和 类型 "dictionary" 调用获取 结构化字段值的结果。 -
令 declaredPolicy 为在 header 上执行解析文档 策略的结果。
-
如果 declaredPolicy 与 requiredPolicy 兼容, 则返回 declaredPolicy。
-
抛出异常。
9.6. 从响应创建嵌套上下文必需 文档策略
-
令 requiredPolicy 为 browsingContext 的必需文档策略的克隆。
-
令 header 为对 response 的标头列表使用标头名称
Required-Document-Policy和 类型 "dictionary" 调用获取 结构化字段值的结果。 -
令 declaredNestedPolicy 为在 header 上执行解析文档 策略的结果。
-
对于 declaredNestedPolicy 中的每个 feature -> value:
-
如果 requiredPolicy[feature] 不存在,或者 value 比 requiredPolicy[feature] 更严格,则将 requiredPolicy[feature] 设置为 value。
-
-
返回 requiredPolicy。
9.7. 对请求的 响应是否应因文档策略而被阻止?
9.8. 获取文档中特性的策略值
Document
对象(document),此
算法返回 document 的文档
策略中 feature 的值。
-
令 policy 为 document 的Document Policy。
-
如果 policy[feature] 存在,则返回其值。
-
返回 feature 的默认值。
9.9. 确定 值与特性的策略是否兼容
Document
对象
(document),此算法返回一个由以下内容组成的元组:
-
一个操作,它是 "compatible" 或 "incompatible",取决于 value 是否与 document 的文档策略兼容,
-
一个报告端点名称;如果 value 同时与 document 的文档 策略及其仅报告 文档策略兼容,或者未为 feature 配置报告, 则该名称为 null; 否则它将是应向其发送违规报告的报告端点的名称。
注意,如果强制执行策略比仅报告策略更严格, 则不会检查仅报告策略。
-
令 policy 为 document 的Document Policy。
-
令 policyConfig 为 policy[feature](如果存在), 否则为一个由 feature 的默认值和 null 组成的元组。
-
令 policyValue 和 reporting endpoint 为 policyConfig 的元素
-
如果 policyValue 比 value 更严格,则返回一个由 "incompatible" 和 reporting endpoint 组成的元组。
-
令 report-only policy 为 document 的仅报告文档 策略,
-
令 report-only policyConfig 为 report-only policy[feature](如果 存在),否则为一个由 feature 的默认值和 null 组成的元组。
-
将 policyValue 和 reporting endpoint 设置为 report-only policyConfig 的元素
-
如果 policyValue 比 value 更严格,则返回一个由 "compatible" 和 reporting endpoint 组成的元组。
-
返回 ("compatible", null)。
9.10. 确定值是否 与特性的策略兼容,或进行报告
Document
对象
(document),如果 value 与
document 的文档策略兼容,则此算法返回 "compatible",
否则返回 "incompatible"。如果已配置报告,它还会
排队一个报告。
-
令 (action, reporting endpoint) 为使用 value、feature 和 document 调用determine-compatibility的结果。
-
如果 reporting endpoint 不为 null,
-
令 body 为一个新的 ECMAScript 对象,具有以下属性: [ECMA-262]
- featureId
-
feature 的字符串表示。
- sourceFile
-
null
- lineNumber
-
null
- columnNumber
-
null
- disposition
-
如果 action 为 "incompatible",则为 "enforce",否则为 "report"。
-
如果用户代理当前正在执行脚本,并且可以从设置中提取 源文件的 URL、行号和列号,则 相应地设置 body 的 sourceFile、lineNumber 和 columnNumber。
-
令 settings 为 document 的环境设置 对象。
-
以 body、"document-policy-violation"、reporting endpoint 和 settings 执行Reporting API § 2.3 Queue data as type for destination。
-
-
返回 action。
9.11. 确定值是否与特性的策略 兼容
Document
对象
(document),如果 value 与
document 的文档策略兼容,则此算法返回 "compatible",
否则返回 "incompatible"。
-
令 (action, reporting endpoint) 为使用 value、feature 和 document 调用determine-compatibility的结果。
-
返回 action。
10. IANA 注意事项
永久消息标头字段注册表应使用以下 注册项进行更新 [RFC3864]:
- 标头字段名称
- Document-Policy
- 适用协议
- http
- 状态
- standard
- 作者/变更控制方
- W3C
- 规范文档
- Document Policy API
- 标头字段名称
- Require-Document-Policy
- 适用协议
- http
- 状态
- standard
- 作者/变更控制方
- W3C
- 规范文档
- Document Policy API
- 标头字段名称
- Sec-Required-Document-Policy
- 适用协议
- http
- 状态
- standard
- 作者/变更控制方
- W3C
- 规范文档
- Document Policy API
11. 隐私与安全
本规范标准化了一种机制,允许嵌入页面设置一个
将在被嵌入页面上强制执行的策略。不过,必需策略需要
明确确认,这不同于现有的 iframe
sandbox
机制。这意味着在没有这些站点配合的情况下,
现有特性的行为不能在已发布的网站中被改变。
使用此模型时,需要牢记一些隐私和安全 注意事项:
-
将跨源子框架中的行为暴露给其嵌入方。
-
通过策略将嵌入方状态暴露给被嵌入文档。
-
盲目接受必需策略导致意外的行为变化。
在一定程度上,这些问题已经存在于 Web 平台中,而本 规范试图至少不让它们变得不必要地更糟。
单个配置点的设计也可能导致安全和隐私问题, 因此在与本规范集成时必须谨慎。 本节试图就哪些类型的行为可能导致此类问题 提供一些指导。
11.1. 跨源行为的暴露
配置点应设计为使得被框架化文档中对策略的 违规不会被其他框架中的文档观察到。 例如,一个假设的特性在被策略禁用时使用会导致 嵌入文档中触发事件,这可能被用于 提取被嵌入文档状态的信息。例如, 如果已知该特性只在用户登录站点时使用, 则嵌入方可以为该框架禁用该特性,然后监听 产生的事件,以确定用户是否已登录。
此外,必须注意不要让 跨源资源内容的信息(通常对文档不可用)因策略而变得 可见。例如,图像内容可能包含私人 信息,而细粒度策略可能允许攻击者通过仔细调整策略的 配置参数来推断图像内容的 某些信息。作用于子资源内容的策略 应排除不可读资源,或采取措施限制 可从资源中推断出的信息量。
11.2. 必需策略的通告
作为对上述行为变化问题的缓解,带有必需策略的 框架中对嵌入内容的请求将随附一个 HTTP 标头,其中详细说明策略要求。该标头对源 服务器可见,其内容可能会泄露有关嵌入方页面的细节。 嵌入方在选择要求其 嵌入内容使用某项策略时,应意识到这一点。
11.3. 盲目接受必需策略
由于遵守嵌入方要求的策略是被
加载的必要条件,站点所有者可能会倾向于配置 Web 服务器,
直接在响应的
Document-Policy 标头中回显
Sec-Required-Document-Policy 请求标头。虽然这可以确保文档的策略
始终与请求兼容,但它可能使被嵌入文档面临
这样的风险:嵌入方可以通过禁用或
改变现有 API 的行为来改变其中的控制流。随着内容
编写之后新的配置点被添加到文档策略模型中,这一点尤其成立。
很难让一个文档针对所有可能的
新行为变化做到面向未来。
预期会被嵌入到带有必需文档策略的上下文中的站点, 可以通过将其策略设置为它们知道自己能够支持的实际最严格策略, 或者仅对它们了解并理解潜在行为变化范围的 配置点回显传入策略,来缓解这一问题。