内容安全策略

使用 WebExtension API 开发的扩展默认应用了内容安全策略 (CSP)。这限制了它们可以从中加载代码(例如 <script>)的来源,并禁止潜在的不安全做法,例如使用 eval()。本文简要解释了什么是 CSP,默认策略是什么以及它对扩展意味着什么,以及扩展如何更改默认 CSP。

内容安全策略 (CSP) 是一种机制,有助于防止网站无意中执行恶意内容。网站使用服务器发送的 HTTP 标头指定 CSP。CSP 主要关注指定各种类型内容(例如脚本或嵌入插件)的合法来源。例如,网站可以使用它来指定浏览器只应执行从网站本身提供的 JavaScript,而不是来自任何其他来源。CSP 还可以指示浏览器禁止潜在的不安全做法,例如使用 eval()

与网站类似,扩展可以从不同的来源加载内容。例如,浏览器操作的弹出窗口被指定为 HTML 文档,它可以像普通网页一样包含来自不同来源的 JavaScript 和 CSS。

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
  </head>
  <body>
    <!--Some HTML content here-->
    <!--
      Include a third-party script.
      See also https://mdn.org.cn/en-US/docs/Web/Security/Subresource_Integrity.
    -->
    <script
      src="https://code.jquery.com/jquery-2.2.4.js"
      integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI="
      crossorigin="anonymous"></script>

    <!-- Include my popup's own script-->
    <script src="popup.js"></script>
  </body>
</html>

与网站相比,扩展可以访问其他特权 API,因此如果它们受到恶意代码的破坏,风险更大。出于这个原因

  • 默认情况下会对扩展应用相当严格的内容安全策略。请参阅 默认内容安全策略
  • 扩展的作者可以使用 content_security_policy 清单 json 键更改默认策略,但对允许的策略有限制。请参阅 content_security_policy

默认内容安全策略

使用清单 V2 的扩展的默认内容安全策略为

"script-src 'self'; object-src 'self';"

而对于使用清单 V3 的扩展,默认内容安全策略为

"script-src 'self'; upgrade-insecure-requests;"

这些策略适用于尚未使用 content_security_policy 清单 json 键明确设置其自身内容安全策略的任何扩展。它具有以下后果

脚本和对象资源的位置

在默认 CSP 下,您只能加载对扩展本地的代码。CSP 将 script-src 限制为仅安全来源,其中包括 <script> 资源、ES6 模块Web 工作线程。在支持过时的 插件 的浏览器中,object-src 指令也受到限制。有关扩展中 object-src 的更多信息,请参阅 WECG 问题 从 CSP 中删除 object-src(至少在 MV3 中)

例如,考虑扩展文档中的类似以下内容的行

html
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>

这不会加载请求的资源:它会静默失败,并且您期望从资源中存在的任何对象都找不到。这主要有两个解决方案

  • 下载资源,将其打包到您的扩展中,并引用此版本的资源。
  • 使用 content_security_policy 键或在清单 V3 中使用 content_scripts 属性允许您需要的远程来源。

注意:如果修改后的 CSP 允许远程脚本注入,则您的扩展在审核期间会被 addons.mozilla.org (AMO) 拒绝。有关更多信息,请参阅有关 安全最佳实践 的详细信息。

eval() 及其同类

在默认 CSP 下,扩展不能将字符串评估为 JavaScript。这意味着以下内容不允许

js
eval("console.log('some output');");
js
setTimeout("alert('Hello World!');", 500);
js
const f = new Function("console.log('foo');");

内联 JavaScript

在默认 CSP 下,不执行内联 JavaScript。这禁止了直接放置在 <script> 标记中的 JavaScript 和内联事件处理程序,这意味着以下内容不允许

html
<script>
  console.log("foo");
</script>
html
<div onclick="console.log('click')">Click me!</div>

如果您当前正在使用类似 <body onload="main()"> 的代码在页面加载时运行脚本,请改为侦听 DOMContentLoadedload

WebAssembly

希望使用 WebAssembly 的扩展需要在 script-src 指令中指定 'wasm-unsafe-eval'

从 Firefox 102 和 Chrome 103 开始,可以在 content_security_policy 清单 json 键中包含 'wasm-unsafe-eval' 以启用扩展中的 WebAssembly 使用。

Firefox 中的清单 V2 扩展可以使用 WebAssembly,而无需在其 CSP 中使用 'wasm-unsafe-eval' 以实现向后兼容性。但是,此行为并非保证,请参阅 Firefox 错误 1770909。因此,鼓励使用 WebAssembly 的扩展在其 CSP 中声明 'wasm-unsafe-eval'

对于 Chrome,扩展在版本 101 或更低版本中无法使用 WebAssembly。在 102 中,扩展可以使用 WebAssembly(与 Firefox 101 及更低版本的行为相同)。从版本 103 开始,如果扩展在清单键中的 content_security_policy 中包含 'wasm-unsafe-eval',则可以使用 WebAssembly。

在清单 V3 中升级不安全的网络请求

扩展在与外部服务器通信时应使用 https:wss:。为了鼓励将其作为标准行为,默认的清单 V3 CSP 包含 upgrade-insecure-requests 指令。此指令会自动将网络请求升级到 http: 以使用 https:

尽管请求会自动升级,但仍然建议在扩展的源代码中尽可能使用https: URL。特别是,manifest.json 文件的 host_permissions 部分中的条目应以https://*://开头,而不是仅使用http://

需要发出http:ws:请求的清单 V3 扩展可以通过使用content_security_policy清单 JSON 密钥覆盖默认 CSP 来选择退出此行为,该策略中排除了upgrade-insecure-requests指令。但是,为了符合附加组件策略的安全要求,所有用户数据必须通过安全方式传输。

内容脚本的 CSP

在清单 V2 中,内容脚本没有 CSP。从清单 V3 开始,内容脚本与扩展共享默认 CSP。目前无法为内容脚本指定单独的 CSP(来源)。

CSP 控制内容脚本加载的范围因浏览器而异。在 Firefox 中,扩展 CSP 会限制 JavaScript 功能(例如 eval)。通常,大多数基于 DOM 的 API 都会受到网页 CSP 的约束。在 Chrome 中,许多 DOM API 受扩展 CSP 而不是网页的 CSP 控制(crbug 896041)。