CSP:script-src

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

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

语法

可以为 script-src 策略允许一个或多个来源

http
Content-Security-Policy: script-src <source>;
Content-Security-Policy: script-src <source> <source>;

来源

<source> 可以是 CSP 源值 中列出的任何一个值。

请注意,这套相同的值可以用于所有 获取指令(以及 其他一些指令)。

示例

允许来自可信域的资源

鉴于此 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"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"></script>

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

html
<script
  src="https://example.com/example-framework.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC sha256-not-in-csp"
  crossorigin="anonymous"></script>

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

html
<script
  src="https://example.com/example-framework.js"
  integrity="invalid-or-unsupported-hash sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"></script>

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

不安全的内联脚本

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

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

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

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

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

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

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

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

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 标头并且 'unsafe-eval' 未在 script-src 指令中指定,则以下方法将被阻止,并且不会有任何效果

不安全的 WebAssembly 执行

'wasm-unsafe-eval' 源表达式控制 WebAssembly 执行。如果页面具有 CSP 标头并且 'wasm-unsafe-eval' 未在 script-src 指令中指定,则 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">),您需要使用 script-src 指令以及 'inline-speculation-rules' 源和哈希-source 或 nonce-source。例如

http
Content-Security-Policy: script-src 'inline-speculation-rules' 'sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC'

规范

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

浏览器兼容性

BCD 表仅在浏览器中加载

另请参见