内容安全策略
使用 WebExtension API 开发的扩展默认应用了内容安全策略 (CSP)。这限制了它们可以从中加载代码(例如 <script>)的来源,并禁止潜在的不安全做法,例如使用 eval()
。本文简要解释了什么是 CSP,默认策略是什么以及它对扩展意味着什么,以及扩展如何更改默认 CSP。
内容安全策略 (CSP) 是一种机制,有助于防止网站无意中执行恶意内容。网站使用服务器发送的 HTTP 标头指定 CSP。CSP 主要关注指定各种类型内容(例如脚本或嵌入插件)的合法来源。例如,网站可以使用它来指定浏览器只应执行从网站本身提供的 JavaScript,而不是来自任何其他来源。CSP 还可以指示浏览器禁止潜在的不安全做法,例如使用 eval()
。
与网站类似,扩展可以从不同的来源加载内容。例如,浏览器操作的弹出窗口被指定为 HTML 文档,它可以像普通网页一样包含来自不同来源的 JavaScript 和 CSS。
<!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 中)。
例如,考虑扩展文档中的类似以下内容的行
<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。这意味着以下内容不允许
eval("console.log('some output');");
setTimeout("alert('Hello World!');", 500);
const f = new Function("console.log('foo');");
内联 JavaScript
在默认 CSP 下,不执行内联 JavaScript。这禁止了直接放置在 <script>
标记中的 JavaScript 和内联事件处理程序,这意味着以下内容不允许
<script>
console.log("foo");
</script>
<div onclick="console.log('click')">Click me!</div>
如果您当前正在使用类似 <body onload="main()">
的代码在页面加载时运行脚本,请改为侦听 DOMContentLoaded 或 load。
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)。