Content-Security-Policy: script-src 指令

Baseline 广泛可用 *

此功能已相当成熟,可在多种设备和浏览器版本上运行。自 ⁨2016 年 8 月⁩ 起,所有浏览器均已提供此功能。

* 此特性的某些部分可能存在不同级别的支持。

HTTP Content-Security-Policy (CSP) 的 script-src 指令指定了 JavaScript 的有效来源。这不仅包括直接加载到 <script> 元素中的 URL,还包括像内联脚本事件处理程序(onclick)和可以触发脚本执行的 XSLT 样式表

CSP 版本 1
指令类型 获取指令
default-src 回退 是的。如果此指令缺失,用户代理将查找 default-src 指令。

语法

http
Content-Security-Policy: script-src 'none';
Content-Security-Policy: script-src <source-expression-list>;

此指令可以具有以下值之一

'none'

不允许加载此类型的任何资源。单引号是强制性的。

<source-expression-list>

一个空格分隔的源表达式值列表。如果此类型的资源与任何给定的源表达式匹配,则可以加载。对于此指令,获取指令语法中列出的任何源表达式值都适用。

示例

允许来自可信域的资源

给定此 CSP 头部,仅允许来自 https://example.com 的脚本

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

以下脚本将被阻止,不会加载或执行

html
<script src="https://not-example.com/js/library.js"></script>

请注意,内联事件处理程序也会被阻止

html
<button id="btn" onclick="doSomething()"></button>

您应该将它们替换为 addEventListener 调用

js
document.getElementById("btn").addEventListener("click", doSomething);

如果您无法替换内联事件处理程序,您可以使用 'unsafe-hashes' 源表达式来允许它们。更多信息请参阅不安全的哈希值

使用哈希值允许外部脚本

如上节所示,允许受信任的域是一种粗略的方法,用于指定代码可以安全加载的位置。这是一种务实的方法,特别是当您的网站使用大量资源并且您确信受信任的网站不会受到损害时。

另一种方法是使用文件哈希值指定允许的脚本。使用此方法,如果 <script> 元素中外部文件的 integrity 属性中的所有有效哈希值都与 CSP 头部中的允许值匹配,则该文件才能加载和执行。子资源完整性功能还会检查下载的文件是否具有指示的哈希值,从而确保其未被修改。这比信任一个域更安全,因为即使从受损的网站加载,文件也只会在未修改的情况下使用。然而,它更细粒度,并且要求在关联脚本更改时更新 CSP 和脚本元素中的哈希值。

下面的 CSP 头部演示了这种方法。它允许 SHA384 哈希为 oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC 或 SHA256 哈希为 fictional_value 的脚本。

http
Content-Security-Policy: script-src 'sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC' 'sha256-fictional_value'

下面的 example-framework.js 脚本应该加载,因为其 integrity 属性中的哈希值也存在于 CSP 中(前提是文件下载后确实具有该哈希值!)

html
<script
  src="https://example.com/example-framework.js"
  crossorigin="anonymous"></script>

integrity 属性可以有多个值,每个值都提供使用不同算法计算的文件哈希值。为了加载外部脚本,CSP 要求属性中的所有有效哈希值也必须在 CSP script-src 声明中。因此,下面的脚本不会加载,因为第二个哈希值不在上面的 CSP 头部中。

html
<script
  src="https://example.com/example-framework.js"
  crossorigin="anonymous"></script>

此规则仅适用于有效哈希值。浏览器不识别的哈希值将被忽略,因此下面的脚本应该加载

html
<script
  src="https://example.com/example-framework.js"
  crossorigin="anonymous"></script>

子资源完整性包含有关计算哈希值和使用 integrity 属性的更多信息。

不安全的内联脚本

注意:禁止内联样式和内联脚本是 CSP 提供的最大安全优势之一。如果您绝对必须使用它们,有几种机制可以允许它们。哈希值适用于内联脚本和样式,但不适用于事件处理程序。有关更多信息,请参阅不安全的哈希值

要允许内联脚本和样式,可以指定 'unsafe-inline'、nonce-source 或与内联块匹配的 hash-source。以下内容安全策略将允许所有内联 <script> 元素

http
Content-Security-Policy: script-src 'unsafe-inline';

以下 <script> 元素将被策略允许

html
<script>
  const inline = 1;
  // …
</script>

允许所有内联脚本被认为是安全风险,因此建议改用 nonce-source 或 hash-source。要使用 nonce-source 允许内联脚本和样式,您需要生成一个随机 nonce 值(使用加密安全的随机令牌生成器)并将其包含在策略中。值得注意的是,此 nonce 值需要动态生成,因为它必须对每个 HTTP 请求都是唯一的

http
Content-Security-Policy: script-src 'nonce-2726c7f26c'

然后,您需要将相同的 nonce 包含在 <script> 元素中

html
<script nonce="2726c7f26c">
  const inline = 1;
  // …
</script>

或者,您可以从内联脚本创建哈希值。CSP 支持 sha256、sha384 和 sha512。

http
Content-Security-Policy: script-src 'sha256-B2yPHKaXnvFWtRChIbabYmUBFZdVfKKXHbWtWidDVF8='

生成哈希值时,请勿包含 <script> 标签,并注意大小写和空格(包括前导或尾随空格)很重要。

html
<script>
  const inline = 1;
</script>

不安全的哈希值

使用哈希值(如 script-src 'sha256-{HASHED_INLINE_SCRIPT}')的内联资源策略通过哈希值允许脚本和样式,但不允许事件处理程序

html
<!-- Allowed by CSP: script-src 'sha256-{HASHED_INLINE_SCRIPT}' -->
<script>
  const inline = 1;
</script>

<!-- CSP: script-src 'sha256-{HASHED_EVENT_HANDLER}'
      will not allow this event handler -->
<button onclick="myScript()">Submit</button>

如果代码无法更新为等效的 addEventListener 调用,则可以使用 'unsafe-hashes' 源表达式来代替允许 'unsafe-inline'。给定一个包含以下内联事件处理程序的 HTML 页面

html
<!-- I want to use addEventListener, but I can't :( -->
<button onclick="myScript()">Submit</button>

以下 CSP 头部将允许脚本执行

http
Content-Security-Policy:  script-src 'unsafe-hashes' 'sha256-{HASHED_EVENT_HANDLER}'

不安全的 eval 表达式

'unsafe-eval' 源表达式控制几种从字符串创建代码的脚本执行方法。如果页面具有 CSP 头部并且 script-src 指令中未指定 'unsafe-eval',则以下方法将被阻止并且不会产生任何效果

不安全的 WebAssembly 执行

'wasm-unsafe-eval' 源表达式控制 WebAssembly 的执行。如果页面具有 CSP 头部并且 script-src 指令中未指定 'wasm-unsafe-eval',则 WebAssembly 将被阻止在该页面上加载和执行。

'wasm-unsafe-eval' 源表达式比 'unsafe-eval' 更具体,后者允许 WebAssembly 的编译(和实例化)以及例如在 JavaScript 中使用 eval 操作。如果使用 'unsafe-eval' 源关键字,则它会覆盖 CSP 策略中任何出现的 'wasm-unsafe-eval'

http
Content-Security-Policy: script-src 'wasm-unsafe-eval'

strict-dynamic

'strict-dynamic' 源表达式指定明确授予标记中存在的脚本的信任(通过附带 nonce 或哈希)应传播到该根脚本加载的所有脚本。同时,任何允许列表或源表达式,如 'self''unsafe-inline',都将被忽略。

例如,像 script-src 'strict-dynamic' 'nonce-R4nd0m' https://allowlisted.example.com/ 这样的策略将允许加载带有 <script nonce="R4nd0m" src="https://example.com/loader.js"> 的根脚本,并将该信任传播到 loader.js 加载的任何脚本,但禁止从 https://allowlisted.example.com/ 加载脚本,除非附带 nonce 或从受信任的脚本加载。

http
Content-Security-Policy: script-src 'strict-dynamic' 'nonce-someNonce'

或者

http
Content-Security-Policy: script-src 'strict-dynamic' 'sha256-base64EncodedHash'

可以以向后兼容的方式部署 strict-dynamic,而无需用户代理嗅探。该策略

http
Content-Security-Policy: script-src 'unsafe-inline' https: 'nonce-abcdefg' 'strict-dynamic'

在支持 CSP1 的浏览器中将像 'unsafe-inline' https: 一样,在支持 CSP2 的浏览器中像 https: 'nonce-abcdefg' 一样,在支持 CSP3 的浏览器中像 'nonce-abcdefg' 'strict-dynamic' 一样。

允许推测规则

要在脚本元素中包含推测规则(另请参阅 <script type="speculationrules">),您需要使用带有 'inline-speculation-rules' 源、哈希源或 nonce 源的 script-src 指令。例如

http
Content-Security-Policy: script-src 'inline-speculation-rules'

规范

规范
内容安全策略级别 3
# directive-script-src

浏览器兼容性

另见