Context Isolation
這是什麼?
Context Isolation 是一項功能,可確保您的 preload
腳本和 Electron 的內部邏輯在與您載入到 webContents
中的網站不同的上下文中執行。這對於安全目的非常重要,因為它有助於防止網站存取 Electron 內部元件或您的預載腳本有權存取的強大 API。
這表示您的預載腳本有權存取的 window
物件實際上與網站有權存取的物件不同。例如,如果您在預載腳本中設定 window.hello = 'wave'
且啟用了 context isolation,如果網站嘗試存取 window.hello
,則其值將會是 undefined。
Context isolation 自 Electron 12 以來預設為啟用,並且是所有應用程式建議的安全設定。
遷移
在沒有 context isolation 的情況下,我過去常使用
window.X = apiObject
從我的預載腳本提供 API。現在該怎麼辦?
之前:context isolation 已停用
從您的預載腳本向渲染器處理程序中載入的網站公開 API 是一種常見的用例。在停用 context isolation 的情況下,您的預載腳本將與渲染器共用一個通用的全域 window
物件。然後,您可以將任意屬性附加到預載腳本
// preload with contextIsolation disabled
window.myAPI = {
doAThing: () => {}
}
然後,doAThing()
函式可以直接在渲染器處理程序中使用
// use the exposed API in the renderer
window.myAPI.doAThing()
之後:context isolation 已啟用
Electron 中有一個專用模組可以幫助您以輕鬆的方式執行此操作。contextBridge
模組可用於安全地將 API 從預載腳本的隔離上下文公開到網站正在執行的上下文中。API 也將可以從網站上的 window.myAPI
存取,就像以前一樣。
// preload with contextIsolation enabled
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
doAThing: () => {}
})
// use the exposed API in the renderer
window.myAPI.doAThing()
請閱讀上面連結的 contextBridge
文件,以充分了解其限制。例如,您無法透過橋接器傳送自訂原型或符號。
安全性考量
僅啟用 contextIsolation
並使用 contextBridge
並不代表您所做的一切都是安全的。例如,此程式碼是不安全的。
// ❌ Bad code
contextBridge.exposeInMainWorld('myAPI', {
send: ipcRenderer.send
})
它直接公開了一個強大的 API,而沒有任何種類的引數篩選。這將允許任何網站傳送任意 IPC 訊息,這是您不希望發生的。公開基於 IPC 的 API 的正確方法是為每個 IPC 訊息提供一個方法。
// ✅ Good code
contextBridge.exposeInMainWorld('myAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs')
})
與 TypeScript 搭配使用
如果您正在使用 TypeScript 建構您的 Electron 應用程式,您會想要將類型新增到透過 context bridge 公開的 API。除非您使用宣告檔案擴充類型,否則渲染器的 window
物件將不會具有正確的類型定義。
例如,假設有這個 preload.ts
腳本
contextBridge.exposeInMainWorld('electronAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs')
})
您可以建立一個 interface.d.ts
宣告檔案,並全域擴充 Window
介面
export interface IElectronAPI {
loadPreferences: () => Promise<void>,
}
declare global {
interface Window {
electronAPI: IElectronAPI
}
}
這樣做將確保 TypeScript 編譯器在您的渲染器處理程序中編寫腳本時,將知道全域 window
物件上的 electronAPI
屬性
window.electronAPI.loadPreferences()