跳至主要內容

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

·4 分鐘閱讀

CVE-2023-4863:WebP 中的堆積緩衝區溢位公開以來,已經過了一個多星期,導致許多軟體發佈新的版本以渲染 webp 圖像:macOS、iOS、Chrome、Firefox 和各種 Linux 發行版都收到了更新。此前,公民實驗室進行調查,發現一個「位於華盛頓特區的公民社會組織」使用的 iPhone,正在使用 iMessage 中的零點擊漏洞受到攻擊。

Electron 也立即採取行動,並在同一天發佈了新版本:如果您的應用程式渲染任何使用者提供的內容,則應更新您的 Electron 版本 – v27.0.0-beta.2、v26.2.1、v25.8.1、v24.8.3 和 v22.3.24 都包含 libwebp 的修復版本,libwebp 是負責渲染 webp 圖像的程式庫。

既然我們都清楚知道「渲染圖像」這種看似無害的互動,實際上是潛在的危險活動,我們要藉此機會提醒大家,Electron 附帶一個程序沙盒,可以限制下次重大攻擊的影響範圍,無論它可能是什麼。

沙盒自 Electron v1 起就已提供,並在 v20 中預設啟用,但我們知道許多應用程式 (尤其是那些存在已久的應用程式) 可能在其程式碼中的某處有 sandbox: false,或者有 nodeIntegration: true,這在沒有明確的 sandbox 設定時也會停用沙盒。這是可以理解的:如果您跟我們很久了,您可能很享受將 require("child_process")require("fs") 放入執行您的 HTML/CSS 的同一個程式碼中的能力。

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

沙盒會在所有渲染程序周圍建立一個硬性的隔離區,確保無論內部發生什麼事,程式碼都會在受限制的環境中執行。作為一個概念,它比 Chromium 更古老,並且是所有主要作業系統都提供的功能。Electron 和 Chromium 的沙盒建立在這些系統功能的基礎上。即使您從未顯示使用者產生的內容,您也應該考慮您的渲染器可能被入侵的可能性:複雜如供應鏈攻擊和簡單如小錯誤的情形,都可能導致您的渲染器執行您不完全希望它做的事情。

沙盒使這種情形不再那麼可怕:內部程序可以自由使用 CPU 週期和記憶體 – 就這樣而已。程序無法寫入磁碟或顯示自己的視窗。在我們的 libwep 錯誤中,沙盒確保攻擊者無法安裝或執行惡意軟體。事實上,在最初對員工的 iPhone 進行飛馬攻擊的情況下,該攻擊特別針對一個非沙盒化的圖像程序,以獲得對手機的訪問權,首先突破了正常沙盒化的 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 的強大功能上撓頭思考,因為我決定藉此機會以許多其他方式重構我的程式碼。