跳到主要內容

突破藩籬:使用沙盒強化應用程式

·4 分鐘閱讀

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 設定時,這同樣會停用沙盒。這是可以理解的:如果您長期以來一直與我們在一起,您可能享受在執行 HTML/CSS 的相同程式碼中加入 require("child_process")require("fs") 的強大功能。

在我們討論如何遷移到沙盒之前,我們先討論一下為何您需要它。

沙盒在所有渲染器程序周圍設置了一個堅硬的籠子,確保無論內部發生什麼,程式碼都在受限環境中執行。作為一個概念,它比 Chromium 早得多,並且由所有主要作業系統作為功能提供。Electron 和 Chromium 的沙盒建立在這些系統功能的基礎之上。即使您從未顯示使用者產生的內容,您也應該考慮您的渲染器可能受到損害的可能性:像供應鏈攻擊這樣複雜的情境,以及像小錯誤這樣簡單的情境,都可能導致您的渲染器執行您並非完全打算讓它執行的操作。

沙盒使這種情況變得不那麼可怕:內部的程序可以自由使用 CPU 週期和記憶體 — 僅此而已。程序無法寫入磁碟或顯示自己的視窗。在我們的 libwep 錯誤的情況下,沙盒確保攻擊者無法安裝或執行惡意軟體。事實上,在最初針對員工 iPhone 的 Pegasus 攻擊案例中,攻擊特別針對未沙盒化的圖像程序以獲取手機的訪問權限,首先突破了正常沙盒化 iMessage 的界限。當宣布像本例中的 CVE 時,您仍然必須將您的 Electron 應用程式升級到安全版本 — 但同時,攻擊者可以造成的損害量會大大降低。

將原始 Electron 應用程式從 sandbox: false 遷移到 sandbox: true 是一項艱鉅的任務。我知道,因為即使我親自撰寫了 Electron 安全指南 的初稿,我也未能將我自己的其中一個應用程式遷移到使用它。這個週末情況發生了變化,我建議您也做出改變。

Don’t be scared by the number of line changes, most of it is in package-lock.json

您需要解決兩件事

  1. 如果您在 preload 腳本或實際的 WebContents 中使用 Node.js 程式碼,則需要將所有 Node.js 互動移至主程序(或者,如果您喜歡,可以使用公用程式程序)。鑑於渲染器已變得如此強大,您的絕大多數程式碼可能真的不需要重構。

    請查閱我們關於 跨程序通訊 的文件。在我的案例中,我移動了大量程式碼,並將其包裝在 ipcRenderer.invoke()ipcMain.handle() 中,但該過程很直接且很快完成。在這裡稍微注意一下您的 API - 如果您建立一個名為 executeCodeAsRoot(code) 的 API,沙盒就無法為您的使用者提供太多保護。

  2. 由於啟用沙盒會停用預先載入腳本中的 Node.js 整合,因此您不能再使用 require("../my-script")。換句話說,您的預先載入腳本需要是單一檔案。

    有多種方法可以做到這一點:Webpack、esbuild、parcel 和 rollup 都可以完成這項工作。我使用了 Electron Forge 出色的 Webpack 外掛程式,同樣受歡迎的 electron-builder 使用者可以使用 electron-webpack

總而言之,整個過程花了我大約四天 — 這包括我絞盡腦汁思考如何駕馭 Webpack 的強大功能,因為我決定藉此機會以許多其他方式重構我的程式碼。