Breach to Barrier: Strengthening Apps with the Sandbox
距离 CVE-2023-4863: 在WebP图片中的堆栈溢出 被公开已经过去了一个星期多。这导致众多渲染 webp
图片的软件都得到了更新:macOS, iOS, Chrome, Firefox 和众多 Linux 发行版都发布了更新。 这是在Citizen Lab进行调查之后进行的。他们发现 “设在华盛顿特区的民间组织” 使用的iPhone通过零点击漏洞在iMessage中被攻击。
Electron也在同一天发布新版本:如果您的应用会显示任何用户提供的内容 您应该更新您的 Electron 版本 - v27 0.0-beta.2, v26.2.1, v25.8.1, v24.8.3, v22.3.24 均包括已经过修复的 libwebp
,一个负责渲染 webp
图像的库。
既然我们大家都新近意识到, 像“渲染一幅图片” 这样看似无害的交互是一种潜在的危险活动, 我们要借此机会提醒大家,Electron包括的进程沙盒将限制下一次大型攻击的猛烈程度,无论它将会是什么。
沙盒从 Electron v1 开始可用,并在 v20 默认情况下启用。 但我们知道许多应用 (尤其是那些已经存在有一段时间的应用) 可能会在其代码中的某个地方有一个 sandbox: false
或 nodeIntegration: true
,这则配置在当没有明确的 sandbox
设置时同样禁用沙盒。 这是可以理解的:如果你已经使用Electron很长时间,你可能已经感受到了 require("child_process")
或 require("fs")
直接扔进运行你的 HTML/CSS 的代码带来的力量。
在我们讨论你能够_如何_迁移到沙盒内之前,我们不如首先讨论你_为什么_会想要迁移。
沙盒围绕所有渲染进程设置了一个保护机制。这确保不论内部发生什么,代码都在受限制的环境中执行。 作为一个概念,它比Chromium老得多,并且所有主流的操作系统都提供了这个功能。 Electron和Chromium的沙盒搭建在这些系统功能之上。 即使您从未显示用户生成的内容,你应该考虑到你的渲染器可能受到损害的可能性:场景像供应链攻击一样复杂,并且很简单,因为小的bug可能会导致你的渲染器做意想不到的事。
沙盒使情景变得更安全:一个在沙盒内的进程可以免费使用 CPU 资源和内存 — 就没别的了。 进程不能写入磁盘或显示自己的窗口。 就我们的 libwep
bug而言,沙盒确保攻击者无法安装或运行恶意程序。 事实上,在最初 Pegasus 袭击雇员 iPhone 的案件中,袭击具体针对的是一个非沙盒图像进程以获得对手机的访问权限,打破了正常情况下 iMessage 沙盒的界限。 当一个CVE像这个示例中的那样被宣布时,您仍然须将您的 Electron 应用程序升级到安全版本 — 不过与此同时,攻击者能够造成的损害受到极大的限制。
将原版Electron应用程序从 sandbox: false
迁移到 sandbox: true
是一项较大的任务。 我理解,因为即使我亲自撰写了 Electron 安全准则,我还没有设法迁移我自己的一个应用来使用该项准则。 在这个周末,我把它改掉了,我建议你也这么做。
你需要处理两件事:
-
如果您在
preload
脚本或实际的WebContents
中使用Node.js 代码,您需要将所有以上这些与 Node.js 的交互迁移到主进程 (或者,如果你愿意的话,一个多用途进程) 。 考虑到最近渲染器正在变得越来越强大,很有可能你的代码很大一部分其实并不需要重构。查阅我们对于 进程间通信 的文档。 就我而言,我移动了许多代码,并用
ipcRenderer.invoke()
和ipcMain.handle()
包装了它,但是这个过程是直截了当的,而且很快就完成了。 请稍微注意你的 API - 如果你构建一个名为executeCodeAsRoot(code)
的API,沙盒将不会过多地保护你的用户。 -
因为启用沙盒会在您的预加载脚本中禁用对 Node.js 的集成,你不再能使用
require("../my-script")
。 换言之,您的预加载脚本需要是一个单一的文件。这样做有多种方式:Webpack、esbuild、parcel 和 rollup 都能办到。 我使用 Electron Forge的出色Webpack插件,而同样受欢迎的
electron-builder
用户可以使用electron-webpack
。
总的来讲,整个过程花了我四天时间 — 而这包括很多,由于我决定利用这次机会通过其他方式去重构我的代码而产生的,对于如何最大化 Webpack 众多效用的思考。