Skip to main content

进程沙箱

🌐 Process Sandboxing

Chromium 的一个关键安全功能是进程可以在沙箱中执行。沙箱通过限制对大多数系统资源的访问来减少恶意代码可能造成的危害——沙箱进程只能自由使用 CPU 周期和内存。为了执行需要额外权限的操作,沙箱进程使用专用通信通道将任务委托给权限更高的进程。

🌐 One key security feature in Chromium is that processes can be executed within a sandbox. The sandbox limits the harm that malicious code can cause by limiting access to most system resources — sandboxed processes can only freely use CPU cycles and memory. In order to perform operations requiring additional privilege, sandboxed processes use dedicated communication channels to delegate tasks to more privileged processes.

在 Chromium 中,沙箱机制被应用于除了主进程之外的大多数进程。这包括渲染进程,以及音频服务、GPU 服务和网络服务等辅助进程。

🌐 In Chromium, sandboxing is applied to most processes other than the main process. This includes renderer processes, as well as utility processes such as the audio service, the GPU service and the network service.

有关更多信息,请参阅 Chromium 的 沙盒设计文档

🌐 See Chromium's Sandbox design document for more information.

从 Electron 20 开始,渲染进程将启用沙箱,无需任何额外配置。

🌐 Starting from Electron 20, the sandbox is enabled for renderer processes without any further configuration.

沙箱与 Node.js 集成相关。通过设置 nodeIntegration: true 为渲染进程_启用 Node.js 集成_会_禁用该进程的沙箱_。

🌐 Sandboxing is tied to Node.js integration. Enabling Node.js integration for a renderer process by setting nodeIntegration: true disables the sandbox for the process.

如果你想为某个进程禁用沙箱,请参见为单个进程禁用沙箱部分。

🌐 If you want to disable the sandbox for a process, see the Disabling the sandbox for a single process section.

Electron 中的沙箱行为

🌐 Sandbox behavior in Electron

Electron 中的沙箱进程在大多数情况下的行为与 Chromium 的沙箱进程类似,但由于 Electron 与 Node.js 交互,它还需要考虑一些额外的概念。

🌐 Sandboxed processes in Electron behave mostly in the same way as Chromium's do, but Electron has a few additional concepts to consider because it interfaces with Node.js.

渲染器进程

🌐 Renderer processes

当 Electron 中的渲染器进程被沙箱化时,它们的行为与普通的 Chrome 渲染器相同。沙箱化的渲染器不会初始化 Node.js 环境。

🌐 When renderer processes in Electron are sandboxed, they behave in the same way as a regular Chrome renderer would. A sandboxed renderer won't have a Node.js environment initialized.

因此,当沙箱启用时,渲染器进程只能通过进程间通信(IPC)将特权任务(例如与文件系统交互、对系统进行更改或生成子进程)委托给主进程来执行。

🌐 Therefore, when the sandbox is enabled, renderer processes can only perform privileged tasks (such as interacting with the filesystem, making changes to the system, or spawning subprocesses) by delegating these tasks to the main process via inter-process communication (IPC).

note

有关进程间通信的更多信息,请查看我们的 IPC 指南

🌐 For more info on inter-process communication, check out our IPC guide.

预加载脚本

🌐 Preload scripts

为了允许渲染进程与主进程通信,附加到沙箱渲染器的预加载脚本仍然可以使用经过填充的 Node.js API 子集。暴露了一个类似于 Node 的 require 模块的 require 函数,但它只能导入 Electron 和 Node 内置模块的子集:

🌐 In order to allow renderer processes to communicate with the main process, preload scripts attached to sandboxed renderers will still have a polyfilled subset of Node.js APIs available. A require function similar to Node's require module is exposed, but can only import a subset of Electron and Node's built-in modules:

  • electron(以下渲染器进程模块:contextBridgecrashReporteripcRenderernativeImagewebFramewebUtils
  • events
  • timers
  • url

节点: 导入 也受支持:

此外,预加载脚本还将某些 Node.js 基础类型填充为全局变量:

🌐 In addition, the preload script also polyfills certain Node.js primitives as globals:

由于 require 函数是功能有限的 polyfill,你将无法使用 CommonJS 模块 将你的预加载脚本拆分为多个文件。如果你需要拆分预加载代码,请使用如 webpack封装 之类的打包工具。

🌐 Because the require function is a polyfill with limited functionality, you will not be able to use CommonJS modules to separate your preload script into multiple files. If you need to split your preload code, use a bundler such as webpack or Parcel.

请注意,由于提供给 preload 脚本的环境权限远高于沙箱化渲染器的环境,如果未启用 contextIsolation,仍有可能将特权 API 泄露给在渲染器进程中运行的不受信任的代码。

🌐 Note that because the environment presented to the preload script is substantially more privileged than that of a sandboxed renderer, it is still possible to leak privileged APIs to untrusted code running in the renderer process unless contextIsolation is enabled.

配置沙箱

🌐 Configuring the sandbox

对于大多数应用来说,沙箱是最佳选择。在某些与沙箱不兼容的使用场景下(例如,在渲染器中使用本地节点模块),可以为特定进程禁用沙箱。这会带来安全风险,尤其是在未沙箱化的进程中存在任何不受信任的代码或内容时。

🌐 For most apps, sandboxing is the best choice. In certain use cases that are incompatible with the sandbox (for instance, when using native node modules in the renderer), it is possible to disable the sandbox for specific processes. This comes with security risks, especially if any untrusted code or content is present in the unsandboxed process.

禁用单个进程的沙箱

🌐 Disabling the sandbox for a single process

在 Electron 中,可以通过 BrowserWindow 构造函数中的 sandbox: false 选项按每个进程禁用渲染器沙箱。

🌐 In Electron, renderer sandboxing can be disabled on a per-process basis with the sandbox: false preference in the BrowserWindow constructor.

main.js
app.whenReady().then(() => {
const win = new BrowserWindow({
webPreferences: {
sandbox: false
}
})
win.loadURL('https://google.com')
})

只要渲染器中启用了Node.js集成,沙盒功能也会被禁用。 这可以通过带有“nodeIntegration: true”标志的BrowserWindow构造函数实现 或者为“webview”提供相应的HTML布尔属性。

🌐 Sandboxing is also disabled whenever Node.js integration is enabled in the renderer. This can be done through the BrowserWindow constructor with the nodeIntegration: true flag or by providing the respective HTML boolean attribute for a webview.

main.js
app.whenReady().then(() => {
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
})
win.loadURL('https://google.com')
})
index.html (Renderer Process)
<webview nodeIntegration src="page.html"></webview>

全局启用沙箱

🌐 Enabling the sandbox globally

如果你想强制对所有渲染器进行沙箱隔离,你也可以使用 app.enableSandbox API。请注意,这个 API 必须在应用的 ready 事件之前调用。

🌐 If you want to force sandboxing for all renderers, you can also use the app.enableSandbox API. Note that this API has to be called before the app's ready event.

main.js
app.enableSandbox()
app.whenReady().then(() => {
// any sandbox:false calls are overridden since `app.enableSandbox()` was called.
const win = new BrowserWindow()
win.loadURL('https://google.com')
})

禁用 Chromium 的沙箱(仅测试)

🌐 Disabling Chromium's sandbox (testing only)

你也可以通过 --no-sandbox 命令行标志完全禁用 Chromium 的沙盒,这将会禁用所有进程(包括辅助进程)的沙盒。我们强烈建议你仅在测试目的下使用此标志,并且绝不要在生产环境中使用。

🌐 You can also disable Chromium's sandbox entirely with the --no-sandbox CLI flag, which will disable the sandbox for all processes (including utility processes). We highly recommend that you only use this flag for testing purposes, and never in production.

请注意,sandbox: true 选项仍然会禁用渲染器的 Node.js 环境。

🌐 Note that the sandbox: true option will still disable the renderer's Node.js environment.

关于渲染不受信任内容的注意事项

🌐 A note on rendering untrusted content

在 Electron 中渲染不受信任的内容仍然是某种程度上的未知字段,虽然一些应用已经取得了成功(例如 比克浏览器)。我们的目标是在沙箱内容的安全性方面尽可能接近 Chrome,但由于一些根本性问题,我们最终总会落后:

🌐 Rendering untrusted content in Electron is still somewhat uncharted territory, though some apps are finding success (e.g. Beaker Browser). Our goal is to get as close to Chrome as we can in terms of the security of sandboxed content, but ultimately we will always be behind due to a few fundamental issues:

  1. 我们没有像 Chromium 那样专门的资源或专业知识来保障其产品的安全性。我们会尽力利用现有资源,继承 Chromium 的所有可能成果,并快速响应安全问题,但没有 Chromium 所拥有的专门资源,Electron 无法像 Chromium 那样安全。
  2. Chrome 中的一些安全功能(例如安全浏览和证书透明度)需要集中式的权威机构和专用服务器,这与 Electron 项目的目标相悖。因此,我们在 Electron 中禁用了这些功能,但代价是失去了它们原本所提供的相关安全性。
  3. 只有一个 Chromium,而基于 Electron 构建的应用却有数以千计,它们的行为都有些许不同。考虑到这些差异可能会产生巨大的可能性空间,并使在特殊使用情况下确保平台安全变得困难。
  4. 我们无法直接向用户推送安全更新,因此我们依赖应用供应商升级其应用所使用的 Electron 版本,以便安全更新能够到达用户。

虽然我们会尽最大努力将 Chromium 的安全修复回移到较旧版本的 Electron,但我们不能保证每个修复都会被回移。保持安全的最佳方式是使用最新的稳定版本的 Electron。

🌐 While we make our best effort to backport Chromium security fixes to older versions of Electron, we do not make a guarantee that every fix will be backported. Your best chance at staying secure is to be on the latest stable version of Electron.