Published on

Electron 进程沙箱化

Authors

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

在 Chromium 中,沙箱适用于除主进程外的大多数进程,这包括渲染进程以及音频服务、GPU 服务和网络服务等实用进程。

从 Electron 20 开始,渲染进程默认启用了沙盒。

Electron 中的沙箱

Electron 中的沙箱进程表现与 Chromium 中的沙箱进程行为基本相同,但由于 Electron 与 Node.js 有交互,因此需要考虑一些额外的概念。

渲染进程

当 Electron 中的渲染进程被沙箱化时,其表现与普通 Chrome 渲染进程相同。沙箱化的渲染进程不会初始化 Node.js 环境。

因此,启用沙箱后,渲染进程只能通过进程间通信(IPC)委托主进程执行高权限的任务(如与文件系统交互、更改系统或生成子进程)。

Preload 脚本

为了允许渲染进程与主进程通信,附加到沙箱化的渲染进程的预加载(Preload)脚本仍将有一个可用的 Node.js API 受限子集。一个与 Node.js 的 require 模块类似的 require 函数被暴露出来,但只能导入 Electron 和 Node 内置模块的子集:

  • electron(渲染进程提供的:contextBridge,crashReporter,ipcRenderer,nativeImage,webFrame,webUtils)
  • events
  • timers
  • url

此外,预加载(Preload)脚本还将某些 Node.js 基础类型,对象和函数通过全局变量的方式暴露出来。

由于 require 函数是一个功能受限的 polyfill,因此无法使用 CommonJS 模块将预加载脚本分割成多个文件。如果需要拆分预加载代码,请使用 webpackParcel 等打包工具。

注:由于预加载脚本的环境比沙箱化的渲染进程的环境具有更高的权限,因此除非启用 contextIsolation (上下文隔离),否则仍有可能将权限 API 泄露给在渲染进程中运行的不受信任的代码。

配置 sandbox

对于大多数应用程序来说,启用沙箱是最佳选择。在某些与沙箱不兼容的使用情况下(例如,在渲染进程中使用原生的 node 模块时),可以禁用特定进程的沙箱。但这样做会带来安全风险,尤其是在未开启沙箱的进程中存在任何不受信任的代码或内容时。

Native Node Modules,由于 Electron 使用了不同的 ABI,所需要针对 Electron 重新编译

禁用单个进程的沙箱

在 Electron 中,可以通过 BrowserWindow 构造函数中的 sandbox: false 参数禁用渲染进程沙箱功能。

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

只要在渲染进程中启用 Node.js 集成,沙盒功能也会被禁用。这可以通过 BrowserWindow 构造函数中的 nodeIntegration: true 标志来实现。

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

全局启用沙箱

如果要强制所有渲染进程使用沙盒,也可以使用 app.enableSandbox API。请注意,必须在应用程序的 ready 事件之前调用此 API。

// 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')
})

请注意,sandbox: true 选项仍将禁用渲染进程的 Node.js 环境。