连接允许列表

社区组报告草案,

此版本:
https://wicg.github.io/connection-allowlists/
问题跟踪:
GitHub
规范内嵌
编辑:
Noam Rosenthal (Google)
Mike West (Google)

摘要

Connection-Allowlist 机制提供了一种简明的策略语言和交付机制, 用于对上下文与其他服务器通信的能力施加一组约束。其目标是 让开发者能够以精准适配问题的方式,整体缓解显式外泄通道。

本文档状态

本规范由 Web 平台孵化器 社区组发布。 它不是 W3C 标准,也不在 W3C 标准轨道上。 请注意,根据 W3C 社区贡献者许可协议 (CLA), 适用有限的退出权以及其他条件。 了解更多关于 W3C 社区组和商务组的信息。

1. 引言

开发者希望控制加载到其页面上下文中的资源,以及其页面可以向其发出请求的 端点。这种控制出于若干目的而必要, 包括限制用户数据可通过用户代理流动的方式(缓解 外泄攻击),以及确保对站点架构和依赖项的控制。

内容安全策略满足了其中一部分需求,但其方式比最关键用例所需的更细粒度, 并且语法和文法也因 CSP 用于部署的其他保护措施而变得复杂。 [CSP]

`Connection-Allowlist` 从 CSP 中退后一步,专注于单一用例:控制 页面可通过 Fetch 和其他 Web 平台 API(WebRTC、Web Transport、FedCM、Web Payments、DNS Prefetch 等)发起的显式请求, 其方式旨在直观而全面。

NOTE: '\' line wrapping per RFC 8792

Connection-Allowlist: (response-origin "https://cdn.example" "https://*.example.:tld" \
                       "https://api.example:*"); report-to=ReportingAPIEndpoint

此标头随用户导航到的文档一起交付时,会将该 文档限制为仅允许向匹配列表中指定 URL 模式 [URLPATTERN] 的端点发出请求和连接:交付该文档的源、 https://cdn.example、倒数第二个 DNS 标签为 example 的任何主机的任何子域、 任意端口上的 https://api.example,等等。

尝试连接到不匹配允许列表的端点将被阻止,并通过 在 report-to 参数中指定的 Reporting API [REPORTING] 端点进行报告(并 通过单独的 Reporting-Endpoints 标头定义)。

1.1. 威胁模型

本提案有意保持小而聚焦,面向客户端攻击 和/或配置错误中一个具体但有用的细分领域:

1.2. 与内容安全策略的重叠

本提案与内容安全策略对给定上下文内资源使用施加限制的方式有很多共同点, 尤其是 fetch 指令。不过,出于以下几个原因,探索它似乎 是合理的:

  1. CSP 的模型过于细粒度:希望缓解数据从敏感上下文流出的风险的开发者 需要一种保护措施,能够穷尽覆盖所有可能发出 请求或建立连接的方式。CSP 将请求分类为可被 单独控制的类型,这不是处理该问题的正确方式,因为数据通过 Web 字体请求泄漏与通过图片 或脚本请求泄漏一样糟糕。区分这些请求类型会以根本无关的问题 使设计合理防御的过程复杂化。

  2. CSP 的语法又不够细粒度:CSP 支持的 host-source 文法导致 响应中交付的标头非常冗长。一个独立策略提供了 转向 URLPattern 语法的机会;这种语法可以通过提供更现代、 更灵活且标准化的匹配语法,解决人们对 CSP 方式提出的一些抱怨。

  3. CSP 的覆盖范围不完整:虽然 CSP 很好地覆盖了通过 Fetch 运行的 HTTP 请求,但它并没有穷尽覆盖 Web 平台 API 允许建立连接的无数方式。DNS 预取和 WebRTC 是很好的起点, 但还有许多其他机制一直难以明确它们究竟如何适配 CSP 的 威胁模型。通过创建一个聚焦范围较窄并向开发者作出明确承诺的新策略, 这些讨论将拥有可辩护的答案,并向规范作者提供清晰的授权。

2. 连接允许列表

连接 允许列表表示给定上下文 被允许连接到的一组 URL 模式。 它是一个包含以下 结构体

3. 连接允许列表标头

Connection-Allowlist 响应 标头包含 一组序列化的 URL 模式字符串,这些字符串定义上下文被允许 连接到的端点集合。该允许列表会针对给定上下文执行,阻止不匹配 所声明模式的出站连接。Connection-Allowlist-Report-Only 响应 标头是只报告变体,以相同方式解析,但只 发送违规 报告,而不阻止出站连接。

这些 Connection Allowlist 标头是 结构化标头,其值是一个由 列表组成的 内层 列表。服务器可以交付包含 任意数量项的列表,但只会使用第一个项。列表中的任何额外项 都会被忽略。

内层列表可以包含序列化为 字符串的 URL Patterns,或 token response-origin,它表示 一个匹配 响应URL的模式。意外的值将被忽略。

内层列表可以有任意 参数

所有其他参数都将被忽略。

3.1. 解析

解析响应的 Connection Allowlists,给定一个 response (response):
  1. allowlists 为空 列表

  2. header 为从 response标头列表中, 以 列表形式 获取结构化字段值 名为 `Connection-Allowlist` 的结果。

  3. 给定 headerresponseURL,以及 enforce解析 Connection Allowlist 标头。如果 结果不是 null,则将其插入 allowlists

  4. header 为从 response标头列表中, 以 列表形式 获取结构化字段值 名为 `Connection-Allowlist-Report-Only` 的结果。

  5. 给定 headerresponseURL,以及 report解析 Connection Allowlist 标头。如果 结果不是 null,则将其插入 allowlists

  6. 返回 allowlists

解析 Connection Allowlist 标头,给定 一个 结构化标头 列表 (list)、一个 URL (response-url),以及一个 disposition (disposition):
  1. 如果 list大小为 0,返回 null

  2. 如果 list[0] 不是 内层列表,返回 null

  3. allowlist 为一个 Connection Allowlist,其 dispositiondisposition

  4. list[0] 中的每个 item 执行

    1. serialized patternnull

    2. 如果 itemtoken response-origin

      1. serialized pattern 设置为 response-urlASCII 序列化

    3. 如果 item字符串,则将 serialized pattern 设置为 item

    4. 如果 serialized patternnull,则继续

    5. URL pattern 为执行从 HTTP 结构化字段值构建 URL 模式的结果,给定 serialized pattern, 并以 null 作为基准 URL。

      如果此步骤抛出错误,则继续

    6. URL pattern 追加allowlistallowlist

  5. list[0] 的 参数中的每个 keyvalue 执行

    1. 如果 keyreport-tovalue 是一个 token,则将 allowlistreporting endpoint 设置为 value

    2. 如果 keyredirectsvalue 是一个 token

      1. 如果 value 是 "block",则将 allowlistredirects 设置为 block

      2. 否则,将 allowlistredirects 设置为 allow

    3. 如果 keywebrtcvalue 是一个 token

      1. 如果 value 是 "block",则将 allowlistwebrtc 设置为 block

      2. 否则,将 allowlistwebrtc 设置为 allow

  6. 返回 allowlist

注: 我们会在 解析算法中跳过任何无效输入。我们完全可以在解析上更加严厉, 但那可能会限制我们未来的灵活性。

3.2. 匹配

根据正在建立的连接类型,我们可能有一个 request 可用, 也可能只有一个 URL,甚至可能更少。例如 dns-prefetch 只能针对主机进行匹配。下面的算法说明了连接允许列表 检查在这些场景中的工作方式:

将 URL 匹配到 Connection Allowlist, 给定一个 URL (url) 和一个 connection allowlist (connection allowlist),执行 以下步骤, 它们返回 successfailure
  1. 如果 url 是本地的,返回 success

  2. connection allowlistallowlist 中的每个 pattern 执行

    1. 如果给定 patternurlURL 模式匹配不返回 null,则返回 success

  3. 返回 failure

将主机匹配到 Connection Allowlist, 给定一个 host (host) 和一个 connection allowlist (connection allowlist),执行 以下 步骤,它们返回 successfailure
  1. connection allowlistallowlist 中的每个 pattern 执行

    1. input 为一个新的 URLPatternInit 字典,其 hostname 被 设置为 patternhostname component

    2. host-only pattern 为给定 input、以 null 作为基准 URL,以及以一个空 map 作为选项来创建 URL 模式的结果。

    3. synthetic url 为将 "https://" 与 host 拼接后 作为 URL 解析的结果。

    4. 如果给定 host-only patternsynthetic urlURL 模式匹配不 返回 null,则返回 success

  2. 返回 failure

注: 通过创建一个只包含 hostname component 的新模式,并为 host 合成一个 URL, 如果允许列表中的 _任何_ 模式可能允许使用任意协议、任意端口、任意路径等 向该主机发出请求,我们就能返回匹配。

should url be blocked by Connection Allowlists 算法接受一个 URL (url)、一个 environment (environment),以及一个由 connection allowlists 组成的 列表 (connection allowlists)。它返回 allowedblocked
  1. connection allowlists 中的每个 connection allowlist 执行

    1. 如果 url matches connection allowlist,则继续

    2. 给定 urlenvironmentconnection allowlist报告违规

    3. 如果 connection allowlistdispositionenforce, 则返回 blocked

  2. 返回 allowed

should request be blocked by Connection Allowlists 算法 接受一个 request (request),并返回 allowedblocked
  1. allowlistsrequestpolicy containerconnection allowlists

  2. allowlists 中的每个 allowlist 执行

    1. 如果 requestURL list大小 大于 1:

      1. 如果 allowlistredirectsallow,则 继续

      2. 给定 requesturlrequestclient,以及 allowlist报告违规

        注: 当重定向被 阻止时,我们有意报告 requesturl,而不是其 current url,以避免泄漏 关于重定向目标的不必要信息。

      3. 如果 allowlistdispositionenforce, 则返回 blocked

      4. 继续

    2. 如果 requesturl matches allowlist,则 继续

    3. 给定 requesturlrequestclient,以及 allowlist报告违规

    4. 如果 allowlistdispositionenforce, 则返回 blocked

  3. 返回 allowed

should host be blocked by Connection Allowlists 算法接受 一个 host (host)、一个 environment (environment),以及一个由 connection allowlists 组成的 列表 (connection allowlists)。它返回 allowedblocked
  1. connection allowlists 中的每个 connection allowlist 执行

    1. 如果 host host-matches connection allowlist,则继续

    2. 给定 hostenvironmentconnection allowlist报告违规

    3. 如果 connection allowlistdispositionenforce, 则返回 blocked

  2. 返回 allowed

should WebRTC be blocked by Connection Allowlists 算法接受 一个 environment settings object (environment),并 返回 allowedblocked
  1. allowlistsenvironmentpolicy containerconnection allowlists

  2. allowlists 中的每个 allowlist 执行

    1. 如果 allowlistwebrtcallow,则继续

    2. 给定 "webrtc"、environmentallowlist报告违规

    3. 如果 allowlistdispositionenforce, 则返回 blocked

  3. 返回 allowed

3.3. 报告

与其他策略机制一样,Connection Allowlists 会将每个违规报告给 允许列表标头中指定的 Reporting API 端点。违规由以下字典 类型表示:

enum ConnectionAllowlistDisposition { "enforce", "report" };

dictionary ConnectionAllowlistViolationReport : ReportBody {
  USVString url;
  USVString connection;
  sequence<DOMString> allowlist;
  ConnectionAllowlistDisposition disposition;
};

ConnectionAllowlistViolationReportconnection 是违反允许列表的连接的 序列化 URL

ConnectionAllowlistViolationReportallowlist 是被违反的 allowlist

ConnectionAllowlistViolationReportdisposition 是该 allowlistdisposition

报告违规,给定一个 URL字符串 "webrtc" (resource URL)、一个 environment (environment),以及一个 connection allowlist (allowlist):
  1. 如果 allowlistreporting endpointnull,则返回。

  2. violation 为一个新的 ConnectionAllowlistViolationReport, 初始化如下:

url

environmentcreation URL,并剥离以供报告使用

connection

如果 resource URL 是一个 URL,则为 resource URL,并剥离以供报告使用

否则,为 resource URL

allowlist

一个新列表,包含对 allowlistallowlist 中每个模式进行序列化的结果

disposition

allowlistdisposition

  1. 给定 environment 作为上下文、"connection-allowlist" 作为 类型、allowlistreporting endpoint 作为 目标,并以 violation 作为数据,生成并排队一个报告

4. 嵌入式强制执行

文档通常会嵌入由其他服务器交付的内容,并希望确保嵌入的 内容至少受到其所要求的同等严格约束。 `Connection-Allowlist` 标头允许 服务器约束其自身的连接,但无法让嵌入方控制应用于其所嵌入文档的 连接允许列表。 本节定义了一种选择加入 机制,该机制以 [csp-embedded-enforcement] 为模型,使 嵌入方能够要求被框架嵌入的文档采用特定的 连接 允许列表

嵌入方通过 connectionAllowlist 内容属性,声明其要求框架采用的 连接允许列表。用户代理通过 `Sec-Required-Connection-Allowlist` 请求标头,将该 要求传达给被框架嵌入的文档。 被框架嵌入的文档可以通过断言一个 `Connection-Allowlist` 来选择加入,该允许列表 满足该要求;也可以通过返回一个 `Allow-Connection-Allowlist-From` 响应标头来选择加入,该标头指定嵌入方的。从本地方案 (例如 about:srcdocdata:)交付的文档会隐式选择加入,因为它们会继承其 嵌入方的 策略容器。未选择加入的框架会被阻止。

当框架选择加入时,所要求的连接允许列表会被添加到被框架嵌入的Document策略容器中,与文档为 自身断言的任何允许列表并存,并且该要求会通过所要求的连接允许列表由框架的后代继承。

嵌入方将某个部件限制为只能与 https://good.example 和该部件自身的 源通信:
<iframe connectionAllowlist='("https://good.example" response-origin)'
        src="https://widget.example/"></iframe>

用户代理会随导航请求一同发送该要求:

GET / HTTP/1.1
Host: widget.example
Sec-Required-Connection-Allowlist: ("https://good.example" response-origin)

该部件可以通过确认嵌入方的源来选择加入……

Allow-Connection-Allowlist-From: https://embedder.example

……也可以通过断言一个连接允许列表来选择加入,该允许列表满足 该要求:

Connection-Allowlist: ("https://good.example" response-origin)

无论采用哪种方式,框架都会加载,并且生成的Document 会 被限制为只能连接 https://good.example 和其自身的。如果该部件既未返回任何一个标头(并且也不是 从本地方案交付的),则该框架会被阻止。

4.1. connectionAllowlist 属性

partial interface HTMLIFrameElement {
  [CEReactions] attribute DOMString connectionAllowlist;
};

connectionAllowlist 内容属性 给出嵌入方要求由 iframe 框架嵌入的Document 所采用的连接 允许列表。其 值使用与 `Connection-Allowlist` 标头相同的语法:由内部 列表组成的结构化标头 列表(参见§ 3 连接允许列表标头)。

connectionAllowlist IDL 属性必须 反映 connectionAllowlist 内容属性。

注:与服务器断言的 `Connection-Allowlist` 不同,后者由文档应用于自身,而 connectionAllowlist 属性由嵌入方设置,并应用于另一个文档。 为了 避免允许嵌入方在跨源内容不知情或不愿接受的情况下静默施加策略,被框架嵌入的 文档必须选择加入;参见§ 4.4 获取并强制执行 要求

4.2. 嵌入式强制执行标头

Sec-Required-Connection-Allowlist 请求标头传达 嵌入方要求被框架嵌入文档采用的连接 允许列表。其值是一个使用 `Connection-Allowlist` 语法的结构化标头列表。由于 其名称带有 Sec- 前缀,因此它是禁止的请求标头,所以它只能由用户代理设置, 脚本无法设置或修改它。

Allow-Connection-Allowlist-From 响应标头允许 文档选择加入,让嵌入方对其强制执行所要求的连接允许列表。它 与 Allow-CSP-From 共享相同的语法和比较方式, 并按照 Fetch 匹配 Access-Control-Allow-Origin 的方式,精确匹配嵌入方的

Allow-Connection-Allowlist-From = [=origin-or-null=] / [=wildcard=]
如果以下 步骤返回 true,则称一个响应response允许来自导航请求request)的连接允许列表:
  1. origin 为从 response标头列表获取 `Allow-Connection-Allowlist-From` 的结果。

  2. 如果 origin`*`,则返回 true。

  3. 如果使用 request 对请求源进行字节序列化的结果是 origin, 则返回 true; 否则返回 false。

注:这与 Allow-CSP-FromCORS 检查相对应:该标头会与嵌入方的 序列化请求源(或通配符)逐字节比较; 它完全不会被 解析(既不会被解析为URL,也不会被解析为)。

4.3. 比较允许列表

如果对于 a 中的每个 patternb包含一个与 pattern 相等的URL 模式结构体, 则称允许列表(a另一个 允许列表b)的子集。

结构体的相等性 尚未得到明确定义。此处,如果两个URL 模式 是从同一个序列化 字符串创建的,则它们相等。(另请参见 whatwg/infra#710。)[whatwg/infra 议题 #664]

注:这是一个(非严格)子集关系:a 中的每个 URL 模式都必须出现在 b 中, 但 ab 可以相等。因此,断言与要求完全相同内容的响应 会满足该要求。

注:上述比较仅要求 响应断言的URL 模式存在于 要求中,而不会对这些模式进行任何语义分析,以确定它们是否在 逻辑上被包含。这是有意为之:鉴于URL 模式的语法, 判断一个模式是否完全包含 另一个模式是一个困难的问题,而保守的集合成员关系判断足以满足 开发者目前的用例。

注:由于被比较的允许列表会相对于 同一个URL进行解析, 因此response-origin 令牌 在二者中会以相同方式解析。

如果以下所有条件均为 true,则称一个连接 允许列表candidate满足另一个连接 允许列表requirement):

注:空的 candidate允许列表不允许任何端点,并且(因为它是每个允许列表的 子集)因此 会满足任何要求,前提是它同时满足该要求的重定向和 WebRTC 处置。

注:满足” 表达了本节始终使用的“至少同样严格”关系: 允许列表比较(是其子集)处理URL 模式, 而重定向webrtc 处置 则作为单独的条件处理。

4.4. 获取并强制执行要求

我们向 策略容器结构体添加一个所要求的连接允许列表项目,该项目为 null字符串(采用 `Connection-Allowlist` 标头语法表示的序列化要求),其初始值为 null。它表示 某个上下文对其嵌入的文档(和 worker)施加的要求。该要求会由本地方案文档和 worker 直接继承,因为策略容器会被复制到 这些上下文中,因此受约束的上下文无法通过嵌入限制更宽松的 子上下文来逃避其约束。

注:该要求被存储为序列化的字符串, 而不是已解析的连接允许列表,这样 当该要求沿框架树向下继承时,response-origin 令牌 就可以分别相对于每个被框架嵌入的 响应URL 进行解析。 只解析一次(在嵌入方处)会将 response-origin 固定为嵌入方的,并 将其错误地应用于后代。这与 [csp-embedded-enforcement] 相对应,后者同样以序列化形式 将其要求存储在策略容器上,并且仅在应用 时才进行解析。

注:将要求存储在策略容器上(而不是存储在Document 上) 遵循 [csp-embedded-enforcement] 对类似策略容器项目的处理方式, 并且正是这种做法使同一 机制也能够约束 worker。

要为一个子可导航对象navigable确定所要求的连接 允许列表
  1. containernavigable容器

  2. parent requiredcontainer节点文档策略容器所要求的连接 允许列表

  3. 如果 container 是一个 iframe 元素,该元素具有一个值(attribute value)不为空字符串的 connectionAllowlist 内容属性,并且给定 parent requiredattribute value 是一个有效的 connectionAllowlist 属性值,则 返回 attribute value

  4. 返回 parent required

给定要求 parent required,如果以下所有条件均为 true,则称一个字符串value)是一个有效的 connectionAllowlist 属性值

注:框架可以收紧,但绝不能放宽 从其父级继承的要求: 仅当 connectionAllowlist 属性至少与父级的 要求同样严格时,才会采用该属性;否则会原样继承父级的要求。这与 [csp-embedded-enforcement] 的有效性 要求相对应,即 iframecsp 属性必须被 嵌入方自身的要求所包含。

对于上述比较,当解析 a 所产生的连接 允许列表满足以相同方式解析 b 所产生的 连接 允许列表时,称一个字符串a至少与另一个字符串b) 同样严格;其中,解析 a 时,会将其解析为一个结构化标头列表,然后在给定该列表的情况下解析 Connection Allowlist 标头;在这两种情况下, response-origin令牌会被视为 由字符串“response-origin”构建的字面URL 模式,而不是相对于 URL 进行解析。

注:此比较在导航时执行, 而不会将 response-origin 相对于 任何URL进行解析。由于 嵌入方的要求和框架自身的要求随后都会相对于同一个 每框架响应URL进行解析, 因此在此处将该令牌视为与其自身相等是合理的,并且这样 可以避免依赖可能被跨源重定向更改的URL。该比较是保守的:如果框架的属性在语法上并不至少与其父级的 要求同样严格,则该框架只会原样继承该要求。

要在给定一个字符串value)、一个URLresponse-url)和一个 处置disposition)的情况下,解析序列化的连接 允许列表 要求
  1. list 为将 value 解析为结构化标头列表的结果。

  2. 如果 list 为失败,则返回 null

  3. 返回在给定 listresponse-urldisposition 的情况下,解析 Connection Allowlist 标头的结果。

要确定导航请求request)的响应response)对于一个 子可导航对象是否应被 Connection Allowlist 嵌入式强制执行阻止, 给定一个字符串nullrequirement),返回 允许阻止
  1. 如果 requirementnull,则返回允许

  2. required 为在给定 requirementresponseURLenforce 的情况下,解析 序列化的连接允许列表 要求的结果。

  3. 如果 requirednull,则返回允许

    注:格式错误的要求会被忽略, 而不会阻止框架。

  4. 如果 response允许来自 request 的连接允许列表,则返回允许

  5. header 为从 response标头列表获取结构化字段值的结果,该字段 名为 `Connection-Allowlist`, 类型为“list”。

  6. asserted 为在给定 headerresponseURLenforce 的情况下,解析 Connection Allowlist 标头的结果。

  7. 如果 asserted 不为 null,并且 asserted满足 required,则返回 允许

    注:格式错误的 `Connection-Allowlist` 会被解析为 null,因此不会被视为 选择加入。

  8. 返回阻止

注:本地方案文档 (例如 about:srcdocdata:)没有 响应,也不会经过此检查;它们会直接继承 嵌入方的策略容器 (包括其中存储的要求)。参见§ 5.2 与 HTML 的集成

5. 猴子补丁

5.1. 与 Fetch 的集成

我们将在 Fetch § 4.1 主 fetch 中添加一项阻止检查, 与用于相同目的的其他检查并列,以处理请求

在主 Fetch 中,我们将按如下方式调整步骤 7:
  1. 如果请求是否应因不良端口而被阻止、获取请求是否应作为混合内容而被阻止、请求是否应被内容安全策略阻止、 请求是否应被连接允许列表阻止 或请求是否应被完整性策略 策略阻止返回已阻止,则将 response 设置为网络错误。

Fetch 还在较低层级定义了用于为不基于请求的 API 建立连接的算法。我们将接入解析 源获取连接,以处理 DNS 预取、Web Transport 等:

解析源中,我们将更新签名,以接受一个可选的 环境设置对象 environment (默认为 null)。

我们将调用上述仅主机匹配算法,以确定是否有任何模式可能 允许连接到给定主机。如果没有,则解析失败。

  1. 如果 environment 不为 null:
    1. allowlistsenvironment策略容器连接允许列表

    2. 如果对 origin主机environmentallowlists 执行主机是否应被 连接允许列表阻止返回已阻止, 则返回失败

获取连接中,我们将更新签名,以接受一个 可选的环境设置对象Document environment(默认为 null):

我们将在当前步骤 2 之前添加一项检查:

  1. 如果 environment 不为 null:
    1. allowlistsenvironment策略容器连接允许列表

    2. 如果对 urlenvironmentallowlists 执行URL 是否应被 连接允许列表阻止返回已阻止, 则返回失败

对 Fetch 的更改将 要求我们向低层算法的调用点传递额外信息,以确定应使用的允许列表以及用于 报告的上下文。或许更好的做法是让这些调用点自行执行检查。 我认为集中处理这些逻辑会更容易成功,但采用 分步处理的方式可能更简单。

5.2. 与 HTML 的集成

为了将上述内容集成到 HTML 中,我们将在策略容器 结构中添加一个新的 连接允许列表项,其中包含一个由连接允许列表组成的列表。通过向从获取响应创建策略 容器算法添加一个步骤来填充该项:

  1. 使用 responseresult 解析 Integrity-Policy 标头。

  2. result连接允许列表设置为 给定 response解析响应的 Connection Allowlist的结果。
  3. 返回 result

注:早期提示集成不需要进一步 更改,因为获取早期提示链接时已经使用了早期响应的 策略容器

为了支持§ 4 嵌入式强制执行,我们遵循 [csp-embedded-enforcement] 为其 必需 CSP 所使用的模型,将嵌入器的要求从嵌入元素传递至 目标快照参数导航参数,再传递到框架内 Document策略容器。具体而言,按如下方式修补 HTML 和 Fetch:

  1. 策略容器 结构 添加一个必需连接允许列表 项(定义于§ 4.4 获取并强制执行 要求)。

  2. 目标快照参数结构添加一个必需连接允许列表项, 该项为 null字符串。HTML 的 创建目标快照参数快照 算法将其设置为给定目标可导航对象时 确定必需 连接允许列表的结果。

  3. 导航参数结构添加一个对应项,并由 导航通过获取创建导航参数以及 从 srcdoc 资源创建导航参数 将其设置为目标快照参数中的对应项。

  4. 通过获取创建导航参数 在创建请求后,当目标快照参数中的对应项不为 null 时,将请求的标头列表中的 `Sec-Required-Connection-Allowlist` 标头设置为该项。

  5. 从获取 响应创建策略容器接受该要求作为附加 参数,并在填充 result连接允许列表后,运行下面的 应用必需连接 允许列表步骤。

注:目标快照参数中已经携带的沙盒标志一样,该要求会在导航时从 iframe 容器创建快照,并在该可导航对象每次 导航中生效,包括框架内 Document 自身发起的导航。因此,该约束会绑定同一可导航对象后续的导航,框架内内容无法通过自行导航到其他位置来规避它。 对 connectionAllowlist 内容属性的更改 会在可导航对象的下一次导航中生效,这与 sandbox 属性 的行为一致。(请注意,这与 referrerpolicy 不同,后者仅影响 容器自身发起的导航。)

给定一个策略容器result)、一个字符串nullrequirement),以及一个 响应response),要 应用必需连接允许列表
  1. 如果 requirementnull,则返回。

  2. required 为给定 requirementresponseURL 以及 强制执行时, 解析 序列化连接允许列表 要求的结果。

  3. 如果 requirednull,则返回。

  4. 如果 result连接允许列表中不存在满足以下条件的 连接允许列表:其 处置强制执行满足 required,则将 required 追加result连接允许列表中。

  5. result必需连接 允许列表设置为 requirement

注:嵌入器的连接允许列表会作为一个 附加条目添加到 result连接允许列表中,与响应为自身声明的任何条目 (包括 `Connection-Allowlist-Report-Only`) 并列。由于该列表中的每个允许列表 都会对文档的传出请求强制执行,因此嵌入器的要求和 文档自身的声明都会生效。按照 [csp-embedded-enforcement],如果响应已经声明了一个 满足该要求的允许列表, 则不会追加该要求,因为该 声明已经满足要求,额外条目没有必要。

注:将未解析的要求存储在 result策略容器上,正是将其传播给 后代的方式:每个后代都会根据自身的响应重新解析该要求(及其 response-origin 词元)。 因此,即使框架自身强制执行的 允许列表比该要求更严格,它仍有义务对其子级强制执行该策略。对于由 本地 方案(例如 about:srcdocdata:)创建的 Document策略容器会 从嵌入器继承,因此该要求也会随之继承。

阻止决定在 Fetch 中作出:握手失败的导航响应会被替换 为网络错误。为以子可导航对象为目标的导航请求request)取得响应后, 如果给定 request 和导航的必需连接允许列表时,确定该响应 是否应被 Connection Allowlist 嵌入式强制执行阻止的结果为已阻止,则用户代理返回 一个 网络错误

围栏框架以及其他 其请求不受嵌入器的 策略容器管辖的上下文,无法受到此机制的约束。当 嵌入器要求此类上下文使用连接允许列表时,必须阻止该上下文,而不能允许其在不受约束的情况下加载。 请参阅§ 6.2 嵌入式强制执行

此集成 有意与内容 安全策略:嵌入式强制执行 § 2.4 与 HTML 集成保持对应。这两种 机制的区别仅在于所携带的策略类型以及“至少同样严格”的比较; 理想情况下,共享的基础框架(目标快照参数/导航参数项、 请求标头钩子以及策略容器应用)应被提取到 HTML(或共享的 嵌入式策略强制执行规范)中,并以策略类型作为参数。这两个 规范采用单一机制进行对齐的工作将作为后续事项跟踪。

5.3. DNS 预取

在针对 dns-prefetch 链接类型的 获取并处理链接资源步骤中, 我们会将链接元素的节点文档传递给解析 源

在 HTML 针对 dns-prefetch 链接类型的 获取并处理链接资源步骤中, 步骤 4 更新如下:
  1. 用户代理应在给定 partitionKeyurl 以及 el相关设置对象 时,解析源

5.4. 预连接

预连接算法中,我们会将链接选项的环境传递给获取连接

在 HTML 的预连接算法中,步骤 5 更新如下:
  1. 用户代理应在给定 partitionKeyurluseCredentials 以及 options环境 时,获取连接

5.5. 与 WebRTC 集成

为了约束 WebRTC 连接,[webrtc] 可以在确定候选项是否在管理上被禁止时,调用 WebRTC 是否应被 Connection Allowlist 阻止 算法。

5.6. 与 Service Worker 集成

除了应用 Service Worker 自身策略容器的默认行为之外, Service Worker 在使用 WindowClient API 调用导航时,还需要应用自身的连接允许列表。

navigate()openWindow(url) 算法都必须按如下方式修补:

  1. 如果对 urlthis相关设置对象,以及 this相关设置对象策略容器连接允许列表 执行URL 是否应被 Connection Allowlist 阻止返回已阻止, 则返回一个以 "SecurityError" DOMException 拒绝的 Promise

navigate() 将当前文档作为导航的 sourceDocument 传递。这看起来有些像是一个 疏漏。请参阅讨论

6. 安全与隐私考量

6.1. 同源上下文

§ 1.1 威胁模型中描述的威胁模型有意限定在较窄的范围内, 开发者需要 仔细考虑如何将此处描述的允许列表机制分层纳入其防御体系。 最值得注意的是,该机制特定于上下文,而非适用于整个源。这为具有脚本访问权限的攻击者 留下了大量机会,使其可以通过找到限制较少的同源 上下文来绕过某个上下文的允许列表。与 HTML 的策略容器集成解决了其中一些 可能性,但其他可能性很可能仍然存在。例如,攻击者 可能能够沿框架树向上访问限制较少的父级,或者通过 window.open() 打开一个保留 opener 关系的新窗口。因此,将文档的源加入允许列表 (通过response-origin 或 显式指定) 本身并不是一个完整的解决方案。

在某些场景中,开发者可以通过 sandbox 属性或内容安全策略的 sandbox 指令,将采用允许列表的上下文与其正常源隔离开来,从而避免此风险。在这些情况下,不会有任何文档同源, 边界也将更容易维持。

开发者还可以使用§ 4 嵌入式强制执行中描述的嵌入式强制执行机制, 要求其框架嵌入的文档采用连接允许列表,而不是 依赖每个被框架嵌入的 文档自行约束。

6.2. 嵌入式强制执行

§ 4 嵌入式强制执行允许嵌入方要求被框架嵌入的文档采用连接 允许列表, 从而解决议题 #1。以下几项 特性可防止其成为新的攻击面:

请求不受嵌入方策略容器控制的上下文(例如 围栏框架)无法被此机制约束。当 嵌入方要求此类上下文采用连接允许列表时,该上下文必须被阻止,而不能允许其在 不受约束的情况下加载。

6.3. Service Worker

Service Worker会使允许列表相关情况变得复杂,正如 其他同源上下文一样。 因为它们具有一个与其管理的每个文档都不同的策略容器, 所以它们 完全可能响应由允许列表与 Service Worker 的允许列表不同的文档所发起的消息或请求。 此提案遵循其他策略的设计,允许 存在这些能力差异。

如果开发者希望约束 Service Worker 发出请求的能力,可以在交付 worker 脚本时一并交付允许列表,但需要确保该允许列表是其可能服务的任何文档的 允许列表的超集。

6.4. DNS

连接允许列表旨在降低通过 DNS 查询泄露数据的风险,它会修改 Fetch 的 解析源算法,使其在发送 DNS 请求之前检查允许列表。这不仅会处理因使用发送请求的元素和 API 而产生的隐式查询 (img 标签、fetch() 等),还会处理由 dns-prefetch 等机制触发的显式查询。

尽管如此,允许列表依赖基于 URL 的匹配来确定给定端点是否 可接受。它不能防御 DNS 操纵,也不会限制请求中涉及的 DNS 服务器 (包括 DNS 解析的递归性质可能与多个服务器 通信),也不会限制 CNAME 等结构导致对 允许列表之外域名进行额外查询。同样,允许列表无法保证 DNS 指向的服务器就是你所预期的服务器。

开发者应依赖经过身份验证的 连接来降低 DNS 劫持和/或重绑定的风险:仅允许安全协议将使控制 DNS 的攻击者更难将流量转移到任意端点,因为 TLS 握手会要求 持有包含相关名称的证书。

我们是否应将 允许列表的模式限制为表示安全协议的模式?或者对于非安全源完全不支持 该标头?

6.5. postMessage(...)

此提案完全关注网络连接,这可能会令那些 期望通过 postMessage(message, options)MessageChannelBroadcastChannel 等显式通信通道进行的通信 也会被涵盖的开发者感到意外。将模型扩展为同时包含这些通道可能是合理的,因为它们都符合 一种可以与允许列表进行有意义比较的基于源的模型。

6.6. 重定向

默认情况下,连接允许列表会阻止所有重定向。这是一种保守立场, 旨在防止通过开放重定向或其他服务器端重定向机制泄露数据。 如果对文档强制执行允许列表,则任何产生重定向的请求都会被阻止, 除非允许列表显式选择允许重定向。

redirects 参数允许 开发者控制 此行为。

如果设置为block(默认值),则任何 重定向链长度大于 1 的请求 都会被阻止。

如果设置为allow,则只会对 初始请求强制执行允许列表。如果初始请求与允许列表匹配,则任何后续重定向 无论其位置如何都会被允许。此模式会将数据安全责任 转移给服务器:一旦请求获准离开客户端,服务器就有责任 确保不会将用户数据重定向到不受信任的位置。

此方法承认不同应用具有不同的安全要求。 高度敏感的应用可以选择阻止所有重定向,而其他应用则可以依赖其 受信任端点正确处理重定向。

考虑一个具有以下标头的文档:
Connection-Allowlist: ("https://api.example")

https://api.example/data 发出的请求返回一个重定向至 https://api.example/new-data302 Found 时,该请求将被阻止,因为默认情况下 会阻止重定向。

如果标头改为:

Connection-Allowlist: ("https://api.example");redirects=allow

https://api.example/data 发出的同一请求将被允许,并且随后 重定向 至 https://api.example/new-data(甚至 https://attacker.com/)也将被 允许

最后,为了实现向前兼容,未知令牌将被视为 allow

Connection-Allowlist: ("https://api.example");redirects=some-future-policy

在此情况下,redirects 参数存在,但其值 some-future-policy 未知。 用户代理会将其视为 allow,并且重定向将被允许。 这使我们 将来能够引入其他行为,而不会破坏现有 站点。

6.7. WebRTC

默认情况下,连接允许列表会阻止所有 WebRTC 连接。这是一种保守立场, 旨在降低通过 WebRTC 独特的联网 特性泄露数据的风险,因为仅使用 URL 模式可能难以对这些特性加以约束。

webrtc 参数允许开发者 控制 此行为。

如果设置为block(默认值),则任何 建立 WebRTC 连接的尝试 都会被阻止。

如果设置为allow,则 WebRTC 连接 将被 允许。

考虑一个具有以下标头的文档:
Connection-Allowlist: ("https://api.example")

任何建立 WebRTC 连接的尝试都会被阻止,因为默认情况下 WebRTC 会被 阻止。

如果标头改为:

Connection-Allowlist: ("https://api.example"); webrtc=allow

WebRTC 连接将被允许

7. 实现考量

7.1. WebSocket

请务必记住,WebSocket 连接由 httphttps 模式涵盖,而不是 由指定 wswss 方案的模式涵盖。当我们建立 WebSocket 连接时,步骤 1 会分别将这些 WebSocket 特有的方案重写为 httphttps。这 意味着 包含“ws://socket.example”之类模式的允许列表不会产生预期效果, 因为资源请求永远不会匹配该模式。

一致性

文档 约定

一致性要求通过 描述性断言 与 RFC 2119 术语的组合来表达。 规范性部分中的关键词 “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、 “MAY” 和 “OPTIONAL” 应按 RFC 2119 中的说明解释。 但是,为了可读性, 本规范中这些词并不总是以全大写字母出现。

本规范中的所有文本均为规范性内容, 明确标记为非规范性的章节、示例和注释除外。[RFC2119]

本规范中的示例会以 “for example” 一词引入, 或通过 class="example" 与规范性文本分隔开来, 如下所示:

这是一个资料性示例的例子。

资料性注释以 “Note” 一词开头, 并通过 class="note" 与规范性文本分隔开来, 如下所示:

Note,这是一个资料性注释。

索引

由本 规范定义的术语

由 引用定义的术语

参考文献

规范性参考文献

[CSP]
Mike West; Antonio Sartori. 内容安全策略 第 3 级。URL:https://w3c.github.io/webappsec-csp/
[CSP-EMBEDDED-ENFORCEMENT]
Mike West; Antonio Sartori. 内容安全策略: 嵌入式强制执行。URL:https://w3c.github.io/webappsec-cspee/
[DOM]
Anne van Kesteren. DOM 标准。现行标准。 URL:https://dom.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 标准。现行 标准。URL:https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; 等。HTML 标准。 现行标准。URL:https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准。现行标准。URL:https://infra.spec.whatwg.org/
[REPORTING]
Douglas Creager; Ian Clelland; Mike West. Reporting API。URL:https://w3c.github.io/reporting/
[RFC2119]
S. Bradner. 用于 RFC 中 指示要求级别的关键词。1997 年 3 月。最佳当前实践。URL:https://datatracker.ietf.org/doc/html/rfc2119
[RFC9651]
M. Nottingham; P-H. Kamp. HTTP 的结构化字段值 。2024 年 9 月。提议标准。URL:https://www.rfc-editor.org/info/rfc9651/
[SERVICE-WORKERS]
Monica CHINTALA; Yoshisato Yanagisawa. Service Worker 每夜版。URL:https://w3c.github.io/ServiceWorker/
[URL]
Anne van Kesteren. URL 标准。现行标准。 URL:https://url.spec.whatwg.org/
[URLPATTERN]
Ben Kelly; Jeremy Roman; 宍戸俊哉 (Shunya Shishido). URL 模式标准。现行标准。URL:https://urlpattern.spec.whatwg.org/
[WEB-BLUETOOTH]
Jeffrey Yasskin. Web 蓝牙。 URL:https://webbluetoothcg.github.io/web-bluetooth/
[WEB-SMART-CARD]
Web 智能卡 API。非官方提案 草案。URL:https://wicg.github.io/web-smart-card/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准。现行 标准。URL:https://webidl.spec.whatwg.org/
[WEBRTC]
Cullen Jennings; 等。WebRTC:浏览器中的实时通信 。URL:https://w3c.github.io/webrtc-pc/
[WEBSOCKETS]
Adam Rice。WebSockets 标准。现行 标准。URL:https://websockets.spec.whatwg.org/
[XHR]
Anne van Kesteren. XMLHttpRequest 标准。现行 标准。URL:https://xhr.spec.whatwg.org/

IDL 索引

enum ConnectionAllowlistDisposition { "enforce", "report" };

dictionary ConnectionAllowlistViolationReport : ReportBody {
  USVString url;
  USVString connection;
  sequence<DOMString> allowlist;
  ConnectionAllowlistDisposition disposition;
};

partial interface HTMLIFrameElement {
  [CEReactions] attribute DOMString connectionAllowlist;
};

问题索引

结构体的相等性尚未得到明确定义。此处,如果两个URL 模式是从同一个序列化 字符串创建的,则它们相等。(另请参见 whatwg/infra#710。)[whatwg/infra 议题 #664]
对 Fetch 的更改将要求我们向低层级 算法的调用位置传递额外信息,以标识应使用的允许列表以及用于 报告的上下文。也许改为要求这些调用位置自行执行检查会更好。 我认为集中逻辑更有可能成功,但采用 分步处理的方法可能更简单。
围栏框架及其他其请求不受嵌入方 策略 容器控制的上下文无法被此机制约束。当 嵌入方要求此类上下文采用连接允许列表时,该上下文必须被阻止,而不能允许其在 不受约束的情况下加载。参见§ 6.2 嵌入式强制执行
此集成有意与 内容安全策略:嵌入式 强制执行 § 2.4 与 HTML 的集成保持一致。这两种 机制仅在所携带的策略类型和“至少同样严格”的比较方式上有所不同; 理想情况下,共享的框架结构(目标 快照参数导航 参数项目、 请求标头挂钩和策略容器应用)应被提取到 HTML(或共享的 嵌入式策略强制执行规范)中,并根据策略类型进行参数化。使这两项 规范统一采用单一机制已作为后续工作进行跟踪。
navigate() 会将当前文档作为导航的 sourceDocument 传递。这似乎有些像一个 疏漏。参见讨论
我们是否应将允许列表的模式限制为表示安全协议的模式?或者对于 非安全源完全不支持该标头?