内容安全策略:嵌入式强制执行

W3C 工作草案,

关于本文档的更多详细信息
此版本:
https://www.w3.org/TR/2026/WD-csp-embedded-enforcement-20260507/
最新发布版本:
https://www.w3.org/TR/csp-embedded-enforcement/
编辑草案:
https://w3c.github.io/webappsec-cspee/
先前版本:
历史记录:
https://www.w3.org/standards/history/csp-embedded-enforcement/
反馈:
public-webappsec@w3.org 主题行使用“[csp-embedded-enforcement] … 消息主题 …” (归档)
Github
编辑:
(Google Inc.)
(Google Inc.)
参与:
提交 issue(未解决的 issue)
测试:
web-platform-tests content-security-policy/embedded-enforcement/(持续进行的 工作)

摘要

本文档定义了一种机制,网页可以通过该机制向一个框架施加 CSP 要求, 当且仅当被嵌入的文档同意对自身强制执行一组特定限制时,才嵌入该文档。

本文档的状态

本节描述本文档在其发布时的状态。 当前 W3C 出版物列表以及本技术报告的最新修订版 可在 W3C 技术报告索引中找到。

本文档由 Web Application Security Working Group 作为工作草案发布,并使用 推荐标准 轨道。本文档旨在成为 W3C 推荐标准。

(已归档的)公共邮件列表 public-webappsec@w3.org (参见说明) 是讨论本规范的首选方式。 发送电子邮件时, 请在主题中加入文本“csp-embedded-enforcement”, 最好采用如下形式: “[csp-embedded-enforcement] …评论摘要…”

作为工作草案发布并不意味着 W3C 及其会员的认可。本文档是草案文档,可能随时被 更新、替换或 由其他文档废止。除作为进行中的工作外,不应引用本文档。

本文档由 Web Application Security Working Group 制作。

本文档由一个依据 W3C 专利政策运作的小组制作。 W3C 维护着一份与该小组交付成果相关的任何 专利披露的公开列表; 该页面还包含披露专利的说明。 如果某个人实际知晓其认为包含必要权利要求的专利, 则必须依照 W3C 专利政策第 6 节披露该信息。

本文档受 2025 年 8 月 18 日 W3C 流程文档管辖。

1. 引言

本节不是规范性的。

内容安全策略是抵御跨站脚本攻击的一种出色防御手段,它允许 开发者加固自己的站点,以防恶意脚本、样式以及其他 资源类型的注入。不过,它并不能让开发者将限制应用到通过 iframe 加载进来的第三方内容。 允许 CSP 直接应用于这些第三方 上下文会很危险;CSP 对资源加载提供了相当细粒度的控制,并且很 可能通过拒绝某个本来安全的页面访问 特定脚本,而把漏洞引入该页面。我们在过去的特性中见过这类问题,例如 X-XSS-Protection, 因此必须小心,避免以新的形式重新引入这些问题。

尽管如此,能够对小组件、广告 以及其他类型的第三方内容施加限制会非常有用。本文档提出了一种机制,该机制依赖于 被嵌入内容的显式选择加入,这应当使小组件能够 与其嵌入方协作,协商出一组合理的限制。

简而言之,嵌入方通过在 iframe 元素上设置一个属性来提出一项内容安全策略。该策略会随被框入内容的 HTTP 请求一起,在 HTTP 请求标头 (`Sec-Required-CSP`) 中传输。 如果被嵌入内容可以接受该策略,它可以 通过在 `Content-Security-Policy` 或 `Allow-CSP-From` 标头中连同 响应返回它来强制执行该策略。

如果响应包含的策略至少与嵌入方请求的策略一样严格, 或接受嵌入方提供的策略,则用户代理将渲染被嵌入内容。如果 不存在这样的断言,响应将被阻止。

1.1. 示例

MegaCorp Inc. 希望确保在其各种出版物上运行的广告 被锁定为只包含来自已审计为安全的受信任源的脚本。它们可以 通过使用带有 iframe 元素,并为其设置 csp 属性来包含广告:
<iframe src="https://advertisements-r-us.example.com/ad1.cfm"
        csp="script-src https://trusted-cdn.example.com/">
</iframe>

这将生成一个发送到 advertisements-r-us.example.com 的请求,该请求带有 `Sec-Required-CSP` 标头,如下所示:

GET / HTTP/1.1
Host: advertisements-r-us.example.com
...
Sec-Required-CSP: script-src https://trusted-cdn.example.com/
...

广告服务器解析此请求标头,判断它可以接受,并向响应添加一个 标头,通知用户代理它将遵守其嵌入方(https://example.com)施加的限制:

HTTP/1.1 200 OK
...
Allow-CSP-From: https://example.com
上例中的广告服务器也可以通过发出自己的 `Content-Security-Policy` 标头来接受这些限制,该标头中的策略至少与 嵌入方要求的策略一样强。例如,它可能希望确保无论 嵌入方允许什么,都不会加载任何插件。它可以通过发出一个包含嵌入方 限制、并在其基础上添加更多限制的策略来做到这一点:
HTTP/1.1 200 OK
...
Content-Security-Policy: script-src https://trusted-cdn.example.com/; object-src 'none'

由于响应所断言的策略允许的请求严格少于请求所要求的策略, 该框架会成功加载。

请注意,服务器也可以交付两个策略,一个精确镜像 嵌入方的限制,另一个进一步收紧这些限制:

HTTP/1.1 200 OK
...
Content-Security-Policy: script-src https://trusted-cdn.example.com/, object-src 'none'

`Content-Security-Policy` 标头值中的 "," 会将字符串拆分为两个 序列化策略,每个策略都会被强制执行。用户代理验证随响应 交付的某个策略与要求相匹配,并且由于额外的策略只会使 页面上的有效策略更加严格,因此允许框架 成功加载。

2. 框架

在较高层面上,本文档描述了一种机制,通过该机制,被嵌入方可以选择加入由其嵌入方 指定的一组限制。该机制涉及几个步骤:

  1. 嵌入方通过 csp 属性,在 iframe 元素上指定一个必需策略。这在 § 2.1 <iframe> 的 csp 属性中有更详细的描述。

  2. 该属性的值将作为 `Sec-Required-CSP` 请求标头,随任何目标为 iframe 的 子可导航对象的 导航请求一起发送。此标头在 § 2.2 Sec-Required-CSP HTTP 请求标头中有更详细的描述。

  3. 服务器可以检查 `Sec-Required-CSP` 标头,以确定它是否希望 接受所需策略。如果是,它可以通过在响应中发送一个 `Content-Security-Policy` 标头来隐式选择加入,该标头包含至少与 所需策略一样强的策略;或者通过在 响应中发送 `Allow-CSP-From` 标头来显式选择加入,从而允许嵌入源设置它希望的任何策略。显式 机制很直接,描述见 § 2.3 Allow-CSP-From HTTP 响应标头。隐式机制 相当复杂,并构成了整个 § 3 隐式策略 接受节。

    如果服务器不希望接受所需策略,它可以返回一个显式错误,或者 简单地返回通常的数据,而不带有匹配的 `Content-Security-Policy` 标头或 `Allow-CSP-From` 标头。在这种情况下,用户代理将阻止该响应。此 与 HTML 的 navigate 算法的集成描述见 § 2.4 与 HTML 集成,并且 阻止机制在 § 4.1 response 对 request 是否被 requiredCSP 阻止?中详细说明。

2.1. <iframe> 的 csp 属性

iframe 元素具有一个 csp 属性,它指定 被嵌入文档必须同意对自身强制执行的 策略。例如,以下 HTML 会加载 https://embedee.example.com/,并确保 object-src 'none' 对其强制执行:

<iframe src="https://embedee.example.com/" csp="object-src 'none'">
</iframe>

对于给定 元素(element)的 csp 属性,如果以下所有陈述均为 真,则一个字符串 (value)是其有效属性值:

  1. value 不是空字符串。

  2. value 的长度小于或等于 4096。

    注:我们对 csp 属性的值强制执行最大长度,以保护服务器 免受可能令人困惑的输入影响。参见下文 § 5.4 标头长度。

  3. value 匹配 [CSP] 中定义的 serialized-policy ABNF 语法。

  4. 以下陈述之一为真:

    1. element 的节点文档的策略容器的required CSP 为 null。

    2. 将 value 作为 "enforce" 解析的结果,被 element 的节点文档的策略容器的 required CSP 包含。

  5. 将 value 作为 "enforce" 解析的结果具有一个 指令集,且不包含以下任何 指令:

以下字符串是 csp 属性的有效值,因为它们是有效的 CSP 语法:
  • script-src 'none'

  • script-src 'self'; object-src 'none'; sandbox

  • not-a-directive https://whatever.not-a-tld

注:我们认为最后一项有效,即使 它并未表达有意义的策略, 这是为了保持与未来 CSP 语法的前向兼容性。

另一方面,以下内容不匹配 CSP 语法,因此不会被视为有效的 属性值:

  • script-src *\nInjected-Header: XSS!

  • 💩

注:我们需要谨慎处理 csp 属性中允许的值,因为其 内容最终会作为 HTTP 请求标头被反射出去。这个问题在 中有更详细的讨论。

iframe 的 csp 属性有一个对应的 IDL 属性,由以下 WebIDL 语法定义 [WEBIDL]:

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

csp IDL 属性必须反映该元素的 csp 属性。

将此上游到所有 HTML。

2.2. Sec-Required-CSP HTTP 请求标头

为了确保被嵌入资源可以决定是否愿意遵守 嵌入方的要求,在 iframe 的 csp 属性中表达的策略,会通过 "Sec-Required-CSP" HTTP 请求标头 随受影响的导航 请求一起传递。该标头的值由以下 ABNF 表示 [RFC5234]:

Sec-Required-CSP = serialized-policy

用户代理不得发送超过一个名为 "Sec-Required-CSP" 的 HTTP 响应标头字段, 且任何这样的标头不得包含超过一个 serialized-policy。

服务器必须只处理接收到的第一个此类标头中的第一项策略。如 中所讨论,服务器还应仔细考虑简单地 将策略反射回客户端的影响。如果服务器希望简单地接受嵌入方的 要求,则 `Allow-CSP-From` 标头是更安全的选择。

此标头作为 HTML 的 navigate 算法的一部分设置(参见 § 2.4 与 HTML 集成,了解调用以下算法的钩子的详细信息):

要为给定 请求(request)和序列化 CSP-或-null(requirement)设置 Sec-Required-CSP 标头,运行以下 步骤:
  1. 如果 request 不是导航请求,则返回。

  2. 如果 requirement 为 null,则返回。

  3. 断言:requirement 是一个序列化 CSP,匹配 [CSP] 中定义的 serialized-policy 语法。

  4. 将名为 "`Sec-Required-CSP`", 值为 requirement 的标头 追加到 request 的标头列表。

2.3. Allow-CSP-From HTTP 响应标头

被嵌入方可以通过响应 "Allow-CSP-From" HTTP 响应标头,选择加入接受由嵌入方指定的策略。该 标头的值由以下 ABNF 表示 [RFC5234]:

Allow-CSP-From = origin-or-null / wildcard

2.4. 与 HTML 集成

  1. iframe 元素具有 csp 属性,定义见 § 2.1 <iframe> 的 csp 属性。

  2. 向策略容器 结构体添加一个 required CSP 项,该项是一个 序列化 CSP 或 null,且初始为 null。

  3. 向目标快照参数 结构体添加一个 required CSP 项,该项是一个 序列化 CSP 或 null。

  4. 更新 HTML 的快照化目标快照参数 算法,将新的 required CSP 项设置为给定 targetNavigable 时确定 required CSP 的结果。

  5. 向导航参数 结构体添加一个 required CSP 项,该项是一个序列化 CSP 或 null。

  6. 更新 navigate 算法,将步骤 18.7.7 中创建的 导航参数 结构体的 required CSP 设置为 targetSnapshotParams 的required CSP。

  7. 在 request 创建之后,向 HTML 的通过获取创建导航参数 算法添加以下步骤:

    1. 为 request 和 targetSnapshotParams 的required CSP 设置 Sec-Required-CSP 标头。

  8. 更新通过获取创建导航参数,以将返回的 导航参数的required CSP 设置为 targetSnapshotParams 的 required CSP。

  9. 更新从 srcdoc 资源创建导航参数,以将返回的导航参数的 required CSP 设置为 targetSnapshotParams 的required CSP。

  10. 向 HTML 的从获取响应创建策略容器算法添加一个可选的 requiredCSP(一个序列化 CSP 或 null,默认为 null)作为 参数,并添加以下步骤:

    1. 如果 requiredCSP 不为 null:

      1. 令 required policy 为将 requiredCSP 作为 "enforce" 解析的结果。

      2. 令 response policies 为解析 response 的内容安全策略的结果。

      3. 如果在 required policy、response 的url 的源、response policies 以及 response 的url 的源上执行 § 3.2.1 CSP 列表包含时返回 "Does Not Subsume":

        1. 将 required policy 追加到 result 的 CSP 列表。

        注:如果响应的 策略已经包含所需策略,我们不会将 所需策略追加到策略容器。这确保了如果嵌入方 要求 一个特定 nonce(例如 nonce-abc),而被嵌入方提供自己的 兼容 nonce (例如 nonce-xyz),用户代理只会强制执行被嵌入方的 nonce。 如果我们 同时追加两者,则该文档实际上会阻止所有脚本,因为没有脚本 能同时 满足两个 nonce。

      4. 将 result 的required CSP 设置为 requiredCSP。

  11. 更新通过获取创建导航参数,以将 targetSnapshotParams 的required CSP 传递给 从获取响应创建策略容器。

  12. 向 HTML 的 navigate 算法中会导致 导航被阻止的条件列表添加以下内容(例如,在 X-Frame-Options 检查之后):

2.4.1. Required CSP

要为给定可导航对象(navigable)确定 required CSP, 运行以下步骤:
  1. 如果 navigable 不是子可导航对象,则返回 null。

  2. 如果 navigable 的容器具有一个 csp 属性,且该属性具有一个 有效属性值 (value),则返回 value。

  3. 返回 navigable 的容器文档的策略容器的 required CSP。

将此上游。

3. 隐式策略接受

被嵌入方可以通过在响应中一并返回 `Allow-CSP-From` 标头,来显式接受其嵌入方指定的策略要求。该要求也可以 通过交付一个 `Content-Security-Policy` 标头来隐式接受,该标头包含一个策略(或一组策略), 其净效果至少与嵌入方要求的策略一样严格。

不过,“至少一样严格”并不是非常精确。简单情况很直接:如果 嵌入方要求 object-src https://cdn.example.com,被嵌入方可以用 object-src 'none' 响应。由于前者会阻止的每一种可能资源 也会被后者阻止 (因为它完全不允许任何对象),我们不会阻止该嵌入。CSP 的 语法复杂性使得在更复杂的 情况下进行推理有些困难。例如,给定 script-src 'unsafe-inline' http: 'sha256-abc...def',它可能 看起来 script-src 'unsafe-inline' 会是所需策略的一个子集。然而, hash-source 表达式的存在意味着 'unsafe-inline' 在 所需策略中会被忽略,因此后一策略实际上会允许比前一策略更多的内容,尽管 表面上看并非如此。

这里,我们将把“至少一样严格”这一概念称为“包含”。如果一个 内容安全策略对象(A) 允许 B 允许的所有内容,则称其 包含另一个 (B)。在这种情况下, A 包含 B, 或者 B 被 A包含。

不过,我们并不总是在比较单个策略。当 CSP 列表中存在多个策略时, 它们会产生一种组合效果,该效果在 “多个策略的效果”中描述。这里, 我们将把一个 CSP 列表的组合效果称为它们的交集。详细内容在下文 § 3.1 交集中说明。

在定义了交集之后,我们可以说,A 包含一个 CSP 列表,当且仅当 A 包含该列表的交集。

3.1. 交集

3.1.1. CSP 列表交集

对于一个源 (origin),一个 CSP 列表(list)的 交集是一个单一的内容安全策略对象,表示它们的 净效果,由以下算法生成:

注:并不总是能将多个策略的交集表示为 单个策略。例如,考虑 script-src 'unsafe-inline' 和 script-src 'nonce-abc': 前者只允许内联脚本,后者只允许带有特定令牌的内联或外部化脚本。 其净效果(仅允许带有特定令牌的内联脚本)无法 用单个策略创建。目前,处理这类策略暂且留给 读者练习。

我们不应让 读者做这个练习。我们还应提供关于如何 处理无法表示为单个策略的交集的指导(例如,通过维护一个 策略列表)。

  1. 令 result 为一个内容安全策略对象,其具有一个空的 指令集,以及 "enforce" 的 处置方式。

  2. 对于 list 中的每个 policy:

    1. 如果 policy 的处置方式为 "report", 则继续。

    2. 将 result 设置为 result 和 policy 针对 origin 的交集。

  3. 返回 result。

对以下 序列化 CSP列表中每一项进行解析所创建的策略的交集:
«
    "default-src 'self' http://example.com http://example.net; connect-src 'none';",
    "connect-src http://example.com/; script-src http://example.com/",
    "style-src 'self'; script-src http://example.com/ http://example.net",
»

是通过解析以下序列化 CSP所创建的策略:

"default-src 'self' http://example.com http://example.net; connect-src 'none'; script-src http://example.com/; style-src 'self'"

初始列表中指定的每个策略都包含该 交集。

3.1.2. 策略交集

对于一个源(origin),两个 内容安全策略对象(A 和 B)的 交集是一个单一的 内容安全策略对象,表示它们的 组合效果,由以下 算法生成:

  1. 断言:A 和 B 都具有 "enforce" 的处置方式。

  2. 如果 A 的指令集为空,则返回 B。

  3. 如果 B 的指令集为空,则返回 A。

  4. 令 policy 为一个新的内容安全策略对象,其具有一个空的 指令集,以及 "enforce" 的 处置方式。

  5. 令 directive names 为空集合。

  6. 对于 A 中的每个 directive:

    1. 将 directive 的名称追加到 directive names。

  7. 对于 B 中的每个 directive:

    1. 将 directive 的名称追加到 directive names。

  8. 对于 directive names 中的每个 directive name:

    1. 如果 directive name 为 "report-uri"、"report-to",则继续。

    2. 令 directive A 为 directive name 和 A 的有效 指令值。

    3. 令 directive B 为 directive name 和 B 的有效 指令值。

    4. 断言:directive A 和 directive B 不会同时为 null,并且二者的 值要么都是源 列表,要么二者的值都不是 源列表。

    5. 如果 directive A 或 directive B 中任一项的值不是 源列表,则继续。

      我们 需要扩展此定义,以处理不是源列表的内容。 此外,我们应当更精确一些,也许可以定义一个类似“源列表 指令”的术语,以便针对 directive name 进行检查。

    6. 如果 directive A 为 null:

      1. 令 directive 为一个新的指令,具有以下属性:

        名称

        directive name

        值

        directive B 的值

      2. 将一个 directive追加到 policy 的 指令 集。

      3. 继续。

    7. 如果 directive B 为 null:

      1. 令 directive 为一个新的指令,具有以下属性:

        名称

        directive name

        值

        directive A 的值

      2. 将一个 directive追加到 policy 的 指令 集。

      3. 继续。

    8. 令 directive value 为 directive A 的 值、directive B 的值、directive name 和 origin 的交集。

    9. 令 directive 为一个新的指令, 具有以下属性:

      名称

      directive name

      值

      directive value

    10. 将 directive追加到 policy 的指令集。

  9. 返回 policy。

对以下序列化 CSP进行解析所获得策略的交集:
"default-src 'self' http://example.com http://example.net; connect-src 'none';"

and

"connect-src http://example.com/; script-src http://example.com/"

是通过解析以下序列化 CSP所获得的策略:

"default-src 'self' http://example.com http://example.net; connect-src 'none'; script-src http://example.com/;"

给定的两个策略都包含该交集。例如, 该 交集的 "script-src http://example.com/" 被第一个策略的 "default-src 'self' http://example.com http://example.net" 和第二个策略的 "script-src http://example.com/"包含。

3.1.3. 源列表交集

对于一个 指令名称(name)和一个源(origin),两个源列表的 交集是一个源列表, 表示它们的净效果。如果不存在这样的源列表 (例如, https://example.com/ 在 A 中,而 https://not-example.com 在 B 中),则该交集将是 列表 « 'none' »。

  1. 令 effective A 为 A、 name 和 origin 的有效源列表。

  2. 令 effective B 为 B、 name 和 origin 的有效源列表。

  3. 如果 effective A 或 effective B 中任一项为 « 'none' »,则返回 « 'none' »。

  4. 如果 effective A 为空,则返回 effective B。

  5. 如果 effective B 为空,则返回 effective A。

  6. 令 schemes 为空集合。

  7. 令 intersection 为空源列表。

  8. 对于 effective B 中的每个 expression B:

    1. 如果 expression B 匹配 scheme-source 语法,并且 expression B 包含在 effective A 中,则将 expression B追加到 schemes。

      注:获取上面的有效源列表意味着 匹配 scheme-source 语法的令牌已经 被规范化,使得 "http:"/"ws:" 永远不会在没有 "https:"/"ws:" 同时出现的情况下出现。

  9. 对于 schemes 中的每个 expression:

    1. 如果 expression 不匹配 "https:",或者 schemes 不 包含 "http:":

      1. 如果 expression 不匹配 "wss:",或者 schemes 不包含 "ws:",则将 expression追加到 intersection。

  10. 对于 effective A 中的每个 expression A:

    1. 如果 expression A 匹配 scheme-source 语法,并且 schemes 包含 expression A,则继续。

    2. 对于 effective B 中的每个 expression B:

      1. 如果 expression A 和 expression B 中至少一个不 匹配 scheme-source 或 host-source 语法:

        1. 如果 expression A 匹配 keyword-source 语法,并且是 expression B 的 ASCII 大小写不敏感匹配,则将 expression A追加 到 intersection。

        2. 如果 expression A 匹配 nonce-source 或 hash-source 语法,并且是 expression B, 则将 expression A追加到 intersection。

        3. 继续到下一个 expression B。

      2. 如果 expression B 的scheme-part匹配 schemes 中的某个元素,则继续到下一个 expression B。

      3. 如果 expression A 和 expression B 的交集 不是 null,则将结果追加到 intersection。

  11. 返回 intersection。

在这些情况下,intersection 是 A 和 B 的一个交集。
A = wss: http://example.com
B = https: wss: 'none'
intersection = wss: https://example.com

表达式 "wss:" 出现在两个策略中,因此它出现在它们的交集中。 类似地,"http://example.com" 出现在交集中,因为它是唯一同时被 "http://example.com" 和 "https:" 包含的表达式。请注意,"'none'"" 会被忽略,因为它不是 B 中唯一的令牌。

A = http://sub.a.com http://*.b.com
B = https://sub.a.com:* http://*.c.com
intersection = https://sub.a.com

只有两个源是相似的:A 中的 "http://sub.a.com" 与 B 中的 "https://sub.a.com:*" 相似, 因此两个源列表的交集是 "https://sub.a.com"。

A = 'unsafe-inline' http://example.com:443/page1/html 'nonce-abc'
B = 'unsafe-inline' https://example.com:443/ 'strict-dynamic' 'nonce-abc'
intersection = 'nonce-abc'

由于 "strict-dynamic" 只认可 nonce-source 和 hash-source 表达式,B 实际上是 "'strict-dynamic' 'nonce-abc'"。 这就是交集为 "'nonce-abc'" 的原因。

3.1.4. 源表达式交集

如果一个 源表达式包含另外两个 表达式中更具限制性的部分,则称其为这两个表达式的交集,这两个 表达式分别匹配 scheme-source 或 host-source 语法 A 和 B,且它包含两者中限制更严格的 scheme-part、 host-part、port-part 和 path-part。

在这些情况下,Intersect 是 A 和 B 的一个交集。
A = https:
B = http:
Intersect = https:
// http: 允许 http: 和 https:,因此 https: 是交集。
A = http://*.example.com
B = https://sub.example.com:*
Intersect = https://sub.example.com:443
// A 未指定端口,因此只允许默认端口。
A = http://example.com:80/page1/html
B = https://example.com:443/
Intersect = null
// A 被显式锁定到端口 80,无法匹配 B 同样显式的端口 443。
A = https:
B = http://example.com
Intersect = https://example.com.
A = https://sub.example.com:*
B = http://*.example.com/page.html
Intersect = https://sub.example.com/page.html
3.1.4.1. scheme-source 和 host-source 交集
给定两个 源表达式,它们匹配 scheme-source 或 host-source 语法(A 和 B), 如果满足条件,则返回它们的交集:A 与 源表达式相似 于 B。否则, 返回 null。
  1. 如果 A 不与 源表达式相似 于 B, 返回 null。

  2. 令 source 为空字符串。

  3. 令 scheme A 为 A 的 scheme-part(如果存在),否则为 null。

  4. 令 scheme B 为 B 的 scheme-part(如果存在),否则为 null。

  5. 令 more secure scheme B 在 scheme A 不与 scheme-part 匹配 scheme B 时为 true,否则为 false。

  6. 如果 scheme A 不为 source,则将 scheme A 和 ":" 追加到 null 且 more secure scheme B 为 false。否则,如果 scheme B 不为 null,则将 scheme B 和 ":" 追加到 source, scheme B 不为 null。

  7. 如果 A 和 B 都匹配 scheme-source 语法,则返回 source。

  8. 如果 source 不为空,则向其追加 "//"。

  9. 令 host A 为 A 的 host-part(如果存在),否则为 null。

  10. 令 host B 为 B 的 host-part(如果存在),否则为 null。

  11. 如果 host A 不为 null:

    1. 如果 host B 为 null,则将 host A 追加到 source。继续执行主 算法的下一步。

    2. 如果 A 不匹配 scheme-source 语法 并且没有 通配符主机,则将 host A 追加到 source。

    3. 否则,将 host B 追加到 source。

  12. 如果 host A 为 null,则将 host B 追加到 source。

  13. 令 port A 为 A 的 port-part(如果存在),否则为 null。

  14. 令 port B 为 B 的 port-part(如果存在),否则为 null。

  15. 如果 port A 为 null,则在 port B 不为 null 时将 ":" 和它追加到 source。

  16. 如果 port A 不为 null:

    1. 如果 port B 为 null,则将 ":" 和 port A 追加到 source。继续执行 主算法的下一步。

    2. 如果 A 没有 通配符端口,并且 more secure scheme B 为 false,则将 ":" 和 port A 追加到 source。

    3. 否则,将 ":" 和 port B 追加到 source。

  17. 令 path A 为 A 的 path-part(如果存在),否则为 null。

  18. 令 path B 为 B 的 path-part(如果存在),否则为 null。

  19. 如果 path A 为 null,则在 path B 不为 null 时将其追加到 source, 如果它不为 null。

  20. 如果 path A 不为 null:

    1. 如果 path B 为 null,则返回将 path A 追加到 source 的结果。

    2. 如果 path A path-part 匹配 path B,则将 path A 追加到 source。

    3. 否则,将 path B 追加到 source。

  21. 返回 source。

3.1.5. 交集辅助项

3.1.5.1. 有效指令值
给定一个字符串(name)和一个内容安全策略对象(policy), name 和 policy 的有效指令值是运行以下步骤所得到的值:
  1. 对 name 进行 switch,并执行相关联的步骤:

    "child-src"
    "connect-src"
    "font-src"
    "img-src"
    "manifest-src"
    "media-src"
    "object-src"
    "script-src"
    "style-src"
    1. 如果 policy 的指令 集包含一个指令,其 名称为 name,则返回该指令的值。

      1. 如果 policy 的指令 集包含一个指令,其 名称为 "default-src",则返回该指令的 值。

      2. 返回 null。

    "script-src-elem"
    "script-src-attr"
    1. 如果 policy 的指令 集包含一个指令,其 名称为 name,则返回该指令的值。

      1. 如果 policy 的指令 集包含一个指令,其 名称为 "script-src",则返回该指令的 值。

      2. 如果 policy 的指令 集包含一个指令,其 名称为 "default-src",则返回该指令的 值。

      3. 返回 null。

    "style-src-elem"
    "style-src-attr"
    1. 如果 policy 的指令 集包含一个指令,其 名称为 name,则返回该 指令的值。

      1. 如果 policy 的指令 集包含一个指令,其 名称为 "style-src",则返回该指令的 值。

      2. 如果 policy 的指令 集包含一个指令,其 名称为 "default-src",则返回该指令的 值。

      3. 返回 null。

    "frame-src"
    1. 如果 policy 的指令 集包含一个指令,其 名称为 name,则返回该 指令的值。

      1. 如果 policy 的指令 集包含一个指令,其 名称为 "child-src",则返回该指令的 值。

      2. 如果 policy 的指令 集包含一个指令,其 名称为 "default-src",则返回该指令的 值。

      3. 返回 null。

    "worker-src"
    1. 如果 policy 的指令 集包含一个指令,其 名称为 name,则返回该 指令的值。

      1. 如果 policy 的指令 集包含一个指令,其 名称为 "child-src",则返回该指令的 值。

      2. 如果 policy 的指令 集包含一个指令,其 名称为 "script-src",则返回该指令的 值。

      3. 如果 policy 的指令 集包含一个指令,其 名称为 "default-src",则返回该指令的 值。

      4. 返回 null。

    "base-uri"
    "block-all-mixed-content"
    "default-src"
    "frame-ancestors"
    "form-action"
    "plugin-types"
    "report-uri"
    "require-sri-for"
    "sandbox"
    "upgrade-insecure-requests"
    1. 如果 policy 的指令 集包含一个指令,其 名称为 name,则返回该 指令的值。

      1. 返回 null。

  2. 返回 null。

3.1.5.2. 有效源列表
给定一个 源列表(list)、一个 字符串(name)和 一个 源 (origin),list、name 和 origin 的有效源列表是 list 的简化形式,它会展开诸如 'self' 和 * 这样的复杂令牌,并移除无效、被取代或无效的 令牌(例如,在存在 nonce 时的 'unsafe-inline')。 运行以下步骤 所得到的结果通常会比 list 更冗长,但会 显著更易于比较:
  1. 如果 list 为 空或为 « 'none' »,则返回 « 'none' »。

  2. 令 result 为一个空的 源 列表。

  3. 对于 list 中的每个 expression:

    1. 如果 expression 是 "'self'":

      1. 将给定 origin 执行 追加§ 4.2.1 将 'self' 重写为 origin 的 host-source 表达式。所得的结果追加到 result。

      2. 继续。

    2. 如果 expression 匹配 keyword-source 语法, 且 name 不是 "script-src" 或 "style-src",则继续。

    3. 如果以下任一 条件为真,则继续:

    4. 如果 expression 是 U+002A ASTERISK 字符(*):

      1. 对于 « "ftp:", "http:", "https:", "ws:", "wss:" » 中的每个 scheme:

        1. 将 scheme 追加到 result。

      2. 将 origin 的 方案与 ":" 的串接结果追加到 result。

      3. 继续。

    5. 如果 expression 匹配 scheme-source 语法:

      1. 如果 expression 是 "http:",则将 "https:" 追加到 result。

      2. 如果 expression 是 "ws:",则将 "wss:" 追加到 result。

    6. 如果 expression 匹配 host-source 语法:

      1. 如果 expression 的 scheme-part 为 "http",则追加 以下内容的结果: 将 "https://"、expression 的 host-part、 expression 的 port-part,以及 expression 的 path-part 连接后,追加到 result。

      2. 如果 expression 的 scheme-part 为 "ws",则追加 以下结果: 将 "wss://"、expression 的 host-part、 expression 的 port-part,以及 expression 的 path-part 连接后追加到 result。

    7. 将 expression 追加到 result。

  4. 如果 result 为 空或为 « 'strict-dynamic' »,则返回 « 'none' »。

  5. 返回 result。

对于源为 https://example.test/ 的任何指令:

https: wss: 'none' 'self'
有效源列表为 "http: wss: https://example.test/"。请注意,"'none'" 不是 有效源列表的一部分,因为当它不是唯一的源时不起作用。

对于 "style-src":

http://example.com 'strict-dynamic' 'nonce-abc'
有效源列表为 "http://example.com 'nonce-abc'",因为 "'strict-dynamic'" 在 非 "script-src" 指令中会被忽略。

对于 "script-src":

http://example.com 'strict-dynamic' 'nonce-abc'
有效源列表为 "'strict-dynamic' 'nonce-abc'",因为在 "script-src" 情况下的 "'strict-dynamic'" 不遵循主机和方案源表达式。
3.1.5.3. 源表达式相似性

如果一个源表达式(A)是 B,或者如果它们语法的相关部分 匹配(例如,在 scheme-source 表达式的情况下, 各自的scheme-part 必须在一个方向或另一个方向上 scheme-part 匹配,则称该源表达式 源表达式 相似于另一个 源表达式(B)。

注:此属性是对称的。也就是说,如果 A 与 B源表达式相似,那么 B 也将与 A源表达式相似。

如果一个源表达式的源表达式的host-part的第一个 字符是 U+002A ASTERISK 字符(*),则它具有通配主机。

如果一个 源表达式具有通配符端口,则 该 port-part(属于该 源 表达式)是一个 U+002A ASTERISK 字符(*)。

  1. 如果 A 的语法不匹配 B 的语法,则返回 "Not Similar"。

  2. 如果 A 匹配 keyword-source、nonce-source 或 hash-source 语法:

    1. 如果 A 是 B,则返回 "Similar"。

    2. 返回 "Not Similar"。

  3. 令 scheme A 为 A 的scheme-part(如果存在),否则为 null。

  4. 令 scheme B 为 B 的scheme-part(如果存在),否则为 null。

  5. 如果 scheme A 不与 scheme Bscheme-part 匹配,且 scheme B 也不与 scheme Ascheme-part 匹配,则返回 "Not Similar"。

  6. 如果 A 或 B 匹配 scheme-source 语法,则返回 "Similar"。

  7. 令 host A 为 A 的host-part(如果存在),否则为 null。

  8. 令 host B 为 B 的host-part(如果存在),否则为 null。

  9. 令 port A 为 A 的port-part(如果存在),否则为 null。

  10. 令 port B 为 B 的port-part(如果存在),否则为 null。

  11. 令 path A 为 A 的path-part(如果存在),否则为 null。

  12. 令 path B 为 B 的path-part(如果存在),否则为 null。

  13. 如果以下任一项为真,则返回 "Not Similar":

    1. A 和 B 都具有通配主机,但 host A 与 host B 不是 ASCII 大小写不敏感匹配。

    2. A 和 B 中至多一个具有通配主机,host A 不与 host Bhost-part 匹配,且 host B 也不与 host Ahost-part 匹配。

    3. A 和 B 都不具有通配端口,port A 不与 port Bport-part 匹配, 且 port B 也不与 port Aport-part 匹配。

    4. path A 不与 path Bpath-part 匹配, 且 path B 也不与 path Apath-part 匹配。

  14. 返回 "Similar"。

A = 'nonce-ch4hvvbHDpv7xCSvXCs3BrNggHdTzxUA'
B = 'nonce-ch4hvvbHDpv7xCSvXCs3BrNggHdTzxUA'

由于 A 和 B 都匹配 nonce-source 语法,且 A 是 B,因此 A 与 B 相似。

A = https://inner.example.com/foo/
B = http://*.example.com/foo/bar/

由于 A 具有通配主机,它会匹配任意子域;在此情况下 该子域是 "inner",因此 A 与 B 相似。

A = http://*.example.com
B = https://inner.example.com:*

尽管 A 和 B 的端口不同,A 和 B 仍然 相似,因为 "http" 同时匹配 "http" 及其更安全的变体 "https"。

A = http://example.com:80/page1/html
B = https://example.com:443/

由于 A 和 B 显式指定了不同端口,A 与 B 不相似。

A = 'sha256-abc123'
B = 'sha512-cde456'

尽管 A 和 B 都匹配 hash-source 语法,A 并不 匹配 B,因为哈希值不匹配。

A = http://example.com:80
B = http://example.com:334

在这种情况下,A 和 B 的端口不匹配,因此这两个源 不相似。

A = http://example.com/page.html
B = http://example.com/index.html

这两个源不相似,因为它们的路径不匹配。

将剩余的 交集算法移入本节。

3.2. 包含

3.2.1. CSP 列表包含

给定一个内容安全策略对象 subsuming policy,其具有一个源 (subsuming origin),以及一个由列表组成的内容安全策略对象对象 policy list, 其具有一个源(origin),如果 subsuming policy 包含 policy list,则此算法返回 "Subsumes",否则返回 "Does Not Subsume"。
  1. 如果 subsuming policy 为 null,则返回 "Subsumes"。

  2. 如果 subsuming policy 的处置方式为 "report",则返回 "Subsumes"。

  3. 如果 subsuming policy 的指令集为空, 则返回 "Subsumes"。

  4. 如果 policy list 为 空或为 null,则返回 "Does Not Subsume"。

  5. 令 effective policy 为给定 policy list 和 origin 执行 § 3.1.1 CSP 列表交集的结果。

  6. 返回给定 subsuming policy、 subsuming origin、effective policy 和 origin 执行 § 3.2.2 策略包含的结果。

3.2.2. 策略包含

给定一个内容安全策略对象 A,其具有一个 源(origin A),以及一个 内容安全策略对象 B,其具有 一个源(origin B),如果 A 包含 B,则此算法 返回 "Subsumes",否则返回 "Does Not Subsume"。
  1. 如果 A 的指令集为空,则返回 "Subsumes"。

  2. 对于 A 的指令集中的每个 directive A:

    1. 令 directive name 为 directive A 的名称。

    2. 如果 directive name 是 "default-src"、 "report-uri"、"report-to", 则继续。

    3. 令 effective directive A 为 directive name 和 A 的有效指令值。

    4. 令 effective directive B 为 directive name 和 B 的有效指令值。

    5. 如果 effective directive A 为 null,则继续。

    6. 如果 effective directive B 为 null,则返回 "Does Not Subsume"。

    7. 如果 directive A 的名称是 "frame-ancestors":

      1. 如果 effective directive B 是 « "'none'" »,则继续。

      2. 如果 effective directive A 是 « "'none'" »,则返回 "Does Not Subsume"。

      3. 对于 effective directive B 中的每个 expression B:

        1. 令 found match 为 false。

        2. 对于 effective directive A 中的每个 expression A:

          1. 如果给定 expression A 和 expression B 执行 § 3.2.4 源表达式 包含返回 "Subsumes",则将 found match 设为 true。跳出此内层循环。

        3. 如果 found match 为 false,则返回 "Does Not Subsume"。

    8. 如果 directive A 的名称是 "plugin-types":

      1. 对于 effective directive B 中的每个 type B:

        1. 如果 effective directive A 不包含 type B, 则返回 "Does Not Subsume"。

    9. 如果 directive A 的名称是 "sandbox":

      1. 令 flags A 为给定 effective directive A 解析沙盒指令的结果。

      2. 令 flags B 为给定 effective directive B 解析沙盒指令的结果。

      3. 对于 flags A 中的每个 flag:

        1. 如果 flags B 不包含 flag,则返回 "Does Not Subsume"。

      注:如果 $B$ 更具限制性,则策略 $A$ 包含 $B$。 对于沙盒标志,这意味着 $A$ 允许的每项权限也必须被 $B$ 允许。如果 $B$ 省略了 $A$ 包含的某个标志,则对于该特定权限而言,$B$ 并不至少与 $A$ 一样严格。

    10. 如果 directive A 的名称是 "disown-opener",则继续。

    11. 否则:

      1. 如果给定 effective directive A、origin A、directive name、effective directive B、 origin B 和 directive name 执行 § 3.2.3 源列表 包含的结果是 "Does Not Subsume",则返回 "Does Not Subsume"。

  3. 返回 "Subsumes"。

3.2.3. 源列表包含

给定一个源列表 A,其具有一个源(origin A)和一个字符串(directive A), 以及一个源列表 B,其具有一个源(origin B)和一个字符串(directive B),如果 A 包含 B,则此 算法返回 "Subsumes",否则返回 "Does Not Subsume"。

如果一个给定源表达式被某指令的 值包含,则称该 指令包含该源表达式。

  1. 如果 directive A 与 directive B 不是ASCII 大小写不敏感匹配,则返回 "Does Not Subsume"。

  2. 如果 A 为空或 B 为 none,则返回 "Subsumes"。

  3. 如果 B 为空或 A 为 none,则返回 "Does Not Subsume"。

  4. 如果 directive B 是 "script-src",且 B 包含一个 keyword-source 表达式 "strict-dynamic",但 A 不包含它, 则返回 "Does Not Subsume"。

  5. 如果 directive B 是 "script-src" 或 "style-src":

    1. 如果 B 包含一个 keyword-source 表达式 "unsafe-eval", 但 A 不包含它,则返回 "Does Not Subsume"。

    2. 如果 B 包含一个 keyword-source 表达式 "unsafe-hashed-attributes",但 A 不包含它,则返回 "Does Not Subsume"。

    3. 如果 directive B 是 "script-src",则令 type B 为 "script",否则为 "style"。 类似地,如果 directive A 是 "script-src",则令 type A 为 "script",否则为 "style"。

    4. 如果给定 B 和 type B,内容安全策略 3 § 6.7.3.2 源列表是否允许 type 的所有内联行为?返回 "Allows", 但给定 A 和 type A 时返回 "Does Not Allow",则返回 "Does Not Subsume"。

  6. 令 list A 和 list B 为空列表。

  7. 对于 A 中的每个 expression A:

    1. 如果 expression A 是 "self",则将给定 origin A 由 § 4.2.1 将 'self' 重写为针对 origin 的 host-source 表达式。返回的一个 host-source追加到 list A。

    2. 如果 expression A 匹配 U+002A ASTERISK 字符(*), 则将以下 scheme-source 表达式追加到 list A: "ftp:"、"http:"、"https:"、 "ws:"、"wss:",以及 origin A 的scheme。

      1. 如果 directive A 是 "img-src" 或 "media-src",则将一个 scheme-source 表达式 "data:" 追加到 list A。

      2. 如果 directive A 是 "media-src",则将一个scheme-source 表达式 "blob:" 追加到 list A。

      3. 继续到下一个 expression A。

    3. 如果 expression A 不匹配 keyword-source 语法, 则将 expression A 追加到 list A。

  8. 对于 B 中的每个 expression B:

    1. 如果 expression B 是 "self",则将给定 origin B 由 § 4.2.1 将 'self' 重写为针对 origin 的 host-source 表达式。返回的一个 host-source追加到 list B。

    2. 如果 expression B 匹配 U+002A ASTERISK 字符(*), 则将以下 scheme-source 表达式追加到 list B: "ftp:"、"http:"、"https:"、 "ws:"、"wss:",以及 origin B 的scheme。

      1. 如果 directive B 是 "img-src" 或 "media-src",则将一个 scheme-source 表达式 "data:" 追加到 list B。

      2. 如果 directive B 是 "media-src",则将一个scheme-source 表达式 "blob:" 追加到 list B。

      3. 继续到下一个 expression B。

    3. 如果 expression B 不匹配 keyword-source 语法, 则将 expression B 追加到 list B。

  9. 如果 list B 为空,则返回 "Subsumes"。

  10. 如果 list A 为空,则返回 "Does Not Subsume"。

  11. 对于 list B 中的每个 expression B:

    1. 如果 expression B 匹配 hash-source 语法,或 nonce-source 语法,除非 directive A 是 "script-src" 或 "style-src",否则继续到下一个表达式。

    2. 令 found match 为 false。

    3. 对于 list A 中的每个 expression A:

      1. 如果给定 expression A 和 expression B 执行 § 3.2.4 源表达式 包含返回 "Subsumes",则将 found match 设为 true。 跳出此内层循环。

    4. 如果 found match 为 false,则返回 "Does Not Subsume"。

  12. 返回 "Subsumes"。

令 directive A 和 directive B 为 "script-src"。考虑以下 示例:
A = "http://example.com 'sha256-xzi4zkCjuC8'"
B = "http://example.com"

由于 B 不允许 hash-source 表达式,但它的值 可在 A 中找到,因此 A 包含 B。不过,B 包含 A 并不成立。

A = "https://example.com 'sha256-xzi4zkCjuC8'"
B = "http://example.com"

在这种情况下,A 不包含 B,因为 "https://example.com" 不包含 "http://example.com"。

A = "http://example.com 'sha256-xzi4zkCjuC8'"
B = "http://example.com 'unsafe-inline'"

由于 B 允许所有内联行为,但 A 不允许,因此 A 不包含 B。

A = "http://example.com 'sha256-xzi4zkCjuC8' 'strict-dynamic'"
B = "http://example.com 'unsafe-inline' 'strict-dynamic'"

A 和 B 均不允许所有内联行为。在这种 情况下,A 包含 B。

3.2.4. 源表达式包含

给定两个源表达式 A 和 B,如果 A 包含 B,则此算法 返回 "Subsumes",否则返回 "Does Not Subsume"。
  1. 断言:A 和 B 均不匹配 keyword-source 语法。

  2. 如果 A 和 B 都匹配 host-source 或 scheme-source 语法:

    1. 如果给定 A 的 scheme-part(如果 A 不包含 scheme-part 则为 null)和 B 的scheme-part(如果 B 不包含 scheme-part 则为 null),内容安全策略 3 § 6.7.2.9 scheme-part 匹配返回 "Does Not Match",则返回 "Does Not Subsume"。

    2. 如果 A 或 B 匹配 scheme-source 语法:

      1. 如果 A 匹配 scheme-source 语法,则返回 "Subsumes"。 否则,返回 "Does Not Subsume"。

    3. 如果 B 具有 wildcard host:

      1. 如果 A 不具有 wildcard host,则返回 "Does not Subsume"。

      2. 令 remaining host B 为从 B 的 host-part中移除前导 ("*.") 的结果。

      3. 如果给定 A 的 host-part 和 remaining host B,内容安全 策略 3 § 6.7.2.10 host-part 匹配返回 "Does Not Match",则返回 "Does Not Subsume"。

    4. 如果 B 不具有 wildcard host,且 给定 A 的host-part 和 B 的host-part,内容安全策略 3 § 6.7.2.10 host-part 匹配返回 "Does Not Match",则返回 "Does Not Subsume"。

    5. 如果 B 具有 wildcard port,但 A 不具有 wildcard port,则返回 "Does Not Subsume"。

    6. 如果 B 不具有 wildcard port,且 给定 A 的port-part(如果 A 不包含 port-part 则为 null)和 B 的port-part(如果 B 不包含 port-part 则为 null),内容安全策略 3 § 6.7.2.11 port-part 匹配返回 "Does Not Match",则返回 "Does Not Subsume"。

    7. 如果给定 A 的path-part (如果 A 不包含 path-part 则为 null)和 B 的 path-part(如果 B 不包含 path-part 则为 null),内容安全策略 3 § 6.7.2.12 path-part 匹配返回 "Does Not Match",则返回 "Does Not Subsume"。

    8. 返回 "Subsumes"。

  3. 如果 A 和 B 都匹配 hash-source 语法:

    1. 如果 A 是 B,则返回 "Subsumes"。否则,返回 "Does Not Subsume"。

  4. 如果 A 和 B 都匹配 nonce-source 语法:

    1. 返回 "Subsumes"。

    注:Nonce 源匹配与值无关,以防止恶意嵌入方通过 § 6.1 策略泄漏中描述的攻击暴力破解 nonce 值。

  5. 返回 "Does Not Subsume"。

应更新针对 nonce 和哈希的包含关系,以考虑更宽松的源 (例如与 'unsafe-inline' 组合的 'self' 或 '*')在逻辑上包含它们的情况。

4. 算法

4.1. response 对 request 是否被 requiredCSP 阻止?

给定一个响应(response)、一个请求 (request)和一个序列化 CSP-或-null (requiredCSP),此算法视情况返回 "Allowed" 或 "Blocked":

  1. 如果 requiredCSP 为 null,则返回 "Allowed"。

  2. 令 required policy 为将 requiredCSP 作为 "enforce" 解析的结果。

  3. 如果在 response 和 request 上执行 § 4.2 response 是否允许来自 request 的策略进行全面强制执行? 算法返回 "Allowed",则返回 "Allowed"。

  4. 如果在 required policy、response 的url 的源、解析 response 的内容安全 策略的结果,以及 response 的url 的源上执行 § 3.2.1 CSP 列表包含算法时返回 "Subsumes",则返回 "Allowed"。

  5. 返回 "Blocked"。

4.2. response 是否允许来自 request 的策略进行全面强制执行?

给定一个响应(response)和一个请求 (request),如果前者允许后者强制执行任意策略,则此算法返回 "Allowed", 否则返回 "Not Allowed":

  1. 如果 response 的url 的scheme是本地 scheme,则返回 "Allowed"。

    注:本地 scheme 响应已经从嵌入方继承其策略,因此我们 允许嵌入方通过此嵌入机制收紧该策略。

  2. 如果 response 的标头列表具有一个名为 `Allow-CSP-From` 的标头(header):

    1. 如果 header 的值是 "*",则返回 "Allowed"。

    2. 如果 request 的源经过序列化并 UTF-8 编码后是 header 的值,则返回 "Allowed"。

  3. 返回 "Not Allowed"。

4.2.1. 将 'self' 重写为针对 origin 的 host-source 表达式。

给定一个源(origin),此算法返回一个host-source 表达式,其 效果与该源的 'self' 相同:

  1. 如果 origin 是不透明源,则返回空字符串。

  2. 返回 origin 的ASCII 序列化。

5. 安全考量

5.1. 威胁模型

本提案旨在让文档能够控制其嵌入的子框架中所使用的内容。由于框架通常 本身就被视为安全边界,并有意限制跨源访问,因此我们应确保避免削弱该边界。

因此,我们的目标是:

本提案无意取代现有隔离机制,例如 CSP 的 frame-ancestors 或 X-Frame-Options,也不会为被嵌入方提供 超出 iframe 元素已有含义之外的任何保护。

5.2. 策略强制执行

被嵌入文档应谨慎评估所提出的内容安全策略,而不是 简单反射嵌入方建议的任何策略。这样做可能使聪明的攻击者能够 选择性禁用网站代码中对其自身保护至关重要的部分。

特别是,不期望被嵌入的文档应继续对任何此类 请求作出响应,返回包含适当 frame-ancestors 指令的内容安全策略。

5.3. 标头反射

服务器应谨慎对待盲目地将 `Sec-Required-CSP` 标头反射到 `Content-Security-Policy` 响应标头中,因为所施加的策略可能以意想不到的方式限制最终 上下文,或者比服务器原本会应用的策略更弱。

相反,鼓励开发者在接受传入策略之前先评估它们,方法是为受信任源 交付 `Allow-CSP-From` 标头。这确保了页面 希望应用的策略会被应用,同时在其上叠加所需策略。由于多个策略 只会收紧限制,这将确保服务器的策略仍然是可靠的 基线保护。

5.4. 标头长度

此特性允许嵌入方控制 跨源嵌入文档请求的 `Sec-Required-CSP` HTTP 标头值。如果服务器对 HTTP 标头长度强制执行限制,这可能导致网络错误。攻击者可以滥用这一点来强制缓存 失效,参见 https://xsleaks.dev/docs/attacks/cache-probing/#cache-probing-with-error-events。 因此,我们将有效 csp 属性的最大长度限制为 4 KB。

6. 隐私考量

6.1. 策略泄漏

该强制执行机制允许恶意嵌入方通过暴力尝试页面策略的约束来跨源读取 该页面的策略。如果策略包含秘密令牌或用户名,这可能泄漏关于页面或加载 该页面的用户的有趣数据。

同样,这里的最佳防御是通过适当的 frame-ancestors 指令控制允许嵌入给定资源的上下文。

6.2. 数据外泄

此特性允许嵌入方通过 `Sec-Required-CSP` HTTP 标头向第三方端点发送信息。这似乎不会暴露任何不能 通过 HTTP 请求本身(通过 GET 参数等)隧道传输的信息,并且嵌入方仍可通过使用 适当 child-src 指令强制执行内容安全策略,来控制 此类请求可以发送到哪些端点。

7. 编写考量

7.1. 要求 'self'

处理required CSP 时,关键字 'self' 指的是正被加载到子可导航对象中的 URL 的源,而不是 要求该策略的文档的源。

MegaCorp Inc. 在其位于 https://example.com/page.html 的页面上要求一个包含 'self' 的策略:
<iframe src="https://advertisements-r-us.example.com/ad1.cfm"
        csp="script-src 'self'">
</iframe>

如果返回的 CSP 是:

Content-Security-Policy: script-src 'self'

那么这个 iframe 元素将会被加载。

然而,如果返回的 CSP 是:

Content-Security-Policy: script-src "https://example.com/"

那么这个 iframe 元素将不会被加载。

8. IANA 考量

永久消息标头字段注册表应使用以下注册信息更新 `Sec-Required-CSP` 标头:[RFC3864]

标头字段名称

Sec-Required-CSP

适用协议

http

状态

standard

作者/变更控制者

W3C

规范文档

本规范(参见 § 2.2 Sec-Required-CSP HTTP 请求 标头)

同样,注册表也应使用以下注册信息更新 `Allow-CSP-From` 标头:[RFC3864]

标头字段名称

Allow-CSP-From

适用协议

http

状态

standard

作者/变更控制者

W3C

规范文档

本规范(参见 § 2.3 Allow-CSP-From HTTP 响应 标头)

一致性

文档 约定

一致性要求通过描述性断言 与 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,这是一个资料性注释。

一致性 算法

作为算法一部分以祈使句表述的要求 (例如 "strip any leading space characters" 或 "return false and abort these steps") 应按照引入该算法时使用的关键词 ("must"、"should"、"may" 等) 的含义来解释。

以算法或具体步骤表述的一致性要求 可以以任何方式实现, 只要最终结果等价即可。 特别是,本规范中定义的算法 旨在易于理解, 而不是旨在具备高性能。 鼓励实现者进行优化。

索引

由本 规范定义的术语

由引用 定义的术语

参考文献

规范性参考文献

[CSP]
Mike West; Antonio Sartori. 内容安全策略 Level 3. 2026 年 5 月 5 日. WD. URL: https://www.w3.org/TR/CSP3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS 值与单位 模块 Level 4. 2024 年 3 月 12 日. WD. URL: https://www.w3.org/TR/css-values-4/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[ENCODING]
Anne van Kesteren. Encoding 标准. 现行标准. URL: https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 标准. 现行标准. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 现行标准. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. 用于 RFC 中表示 要求级别的关键词. 1997 年 3 月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC3864]
G. Klyne; M. Nottingham; J. Mogul. 消息标头字段 注册程序. 2004 年 9 月. 最佳当前实践. URL: https://www.rfc-editor.org/rfc/rfc3864
[RFC5234]
D. Crocker, Ed.; P. Overell. 用于语法 规范的增强 BNF:ABNF. 2008 年 1 月. 互联网标准. URL: https://www.rfc-editor.org/rfc/rfc5234
[URL]
Anne van Kesteren. URL 标准. 现行标准. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行标准. URL: https://webidl.spec.whatwg.org/

IDL 索引

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

Issue 索引

将此上游到所有 HTML。↵
将此上游。↵
我们不应让读者做这个练习。我们还应提供关于如何 处理无法表示为单个策略的交集的指导(例如,通过维护一个 策略列表)。↵
我们需要扩展此定义,以处理不是源列表的内容。 此外,我们应当更精确一些,也许可以定义一个类似“源列表 指令”的术语,以便针对 directive name 进行检查。↵
将剩余的交集算法移入本节。↵
应更新针对 nonce 和哈希的包含关系,以考虑更宽松的源 (例如与 'unsafe-inline' 组合的 'self' 或 '*')在逻辑上包含它们的情况。↵
⚠MDN

HTMLIFrameElement/csp

In only one current engine.

FirefoxNoneSafariNoneChrome61+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?