Electron 上下文隔離

2023-02-16 17:14 更新

上下文隔離是什么?

上下文隔離功能將確保您的 預(yù)加載腳本 和 Electron的內(nèi)部邏輯 運(yùn)行在所加載的 ?webcontent? 網(wǎng)頁(yè) 之外的另一個(gè)獨(dú)立的上下文環(huán)境里。 這對(duì)安全性很重要,因?yàn)樗兄谧柚咕W(wǎng)站訪問(wèn) Electron 的內(nèi)部組件 和 您的預(yù)加載腳本可訪問(wèn)的高等級(jí)權(quán)限的API 。

這意味著,實(shí)際上,您的預(yù)加載腳本訪問(wèn)的 window 對(duì)象并不是網(wǎng)站所能訪問(wèn)的對(duì)象。 例如,如果您在預(yù)加載腳本中設(shè)置 window.hello = 'wave' 并且啟用了上下文隔離,當(dāng)網(wǎng)站嘗試訪問(wèn)window.hello對(duì)象時(shí)將返回 undefined。

自 Electron 12 以來(lái),默認(rèn)情況下已啟用上下文隔離,并且它是 所有應(yīng)用程序推薦的安全設(shè)置。

遷移

沒(méi)有上下文隔離,從預(yù)加載腳本提供API時(shí),經(jīng)常會(huì)使用?window.X = apiObject? 那么現(xiàn)在呢?

之前: 上下文隔離禁用

在渲染進(jìn)程中,預(yù)加載腳本暴露給已加載的頁(yè)面 API 是一個(gè)常見的使用方式。 當(dāng)上下文隔離時(shí),您的預(yù)加載腳本可能會(huì)暴露一個(gè)常見的全局window對(duì)象給渲染進(jìn)程。 此后,您可以從中添加任意的屬性到預(yù)加載在腳本。

// 上下文隔離禁用的情況下使用預(yù)加載
window.myAPI = {
  doAThing: () => {}
}

doAThing() 函數(shù)可以在渲染進(jìn)程中直接使用。

// 在渲染器進(jìn)程使用導(dǎo)出的 API
window.myAPI.doAThing()

之后:?jiǎn)⒂蒙舷挛母綦x

Electron 提供一種專門的模塊來(lái)無(wú)阻地幫助您完成這項(xiàng)工作。 ?contextBridge? 模塊可以用來(lái)安全地從獨(dú)立運(yùn)行、上下文隔離的預(yù)加載腳本中暴露 API 給正在運(yùn)行的渲染進(jìn)程。 API 還可以像以前一樣,從 window.myAPI 網(wǎng)站上訪問(wèn)。

// 在上下文隔離啟用的情況下使用預(yù)加載
const { contextBridge } = require('electron')

contextBridge.exposeInMainWorld('myAPI', {
  doAThing: () => {}
})
// 在渲染器進(jìn)程使用導(dǎo)出的 API
window.myAPI.doAThing()

請(qǐng)閱讀 contextBridge 的文檔,以全面了解其限制。 例如,您不能在 contextBridge 中暴露原型或者 Symbol。

安全事項(xiàng)

單單開啟和使用 contextIsolation 并不直接意味著您所做的一切都是安全的。 例如,此代碼是 不安全的。

// ? 錯(cuò)誤使用
contextBridge.exposeInMainWorld('myAPI', {
  send: ipcRenderer.send
})

它直接暴露了一個(gè)沒(méi)有任何參數(shù)過(guò)濾的高等級(jí)權(quán)限 API 。 這將允許任何網(wǎng)站發(fā)送任意的 IPC 消息,這不會(huì)是你希望發(fā)生的。 相反,暴露進(jìn)程間通信相關(guān) API 的正確方法是為每一種通信消息提供一種實(shí)現(xiàn)方法。

// ? 正確使用
contextBridge.exposeInMainWorld('myAPI', {
  loadPreferences: () => ipcRenderer.invoke('load-prefs')
})

與Typescript一同使用

如果您正在使用 TypeScript 構(gòu)建 Electron 應(yīng)用程序,您需要給通過(guò) context bridge 暴露的 API 添加類型。 渲染進(jìn)程的 window 對(duì)象將不會(huì)包含正確擴(kuò)展類型,除非給其添加了 類型聲明。

例如,在這個(gè) preload.ts 腳本中:

contextBridge.exposeInMainWorld('electronAPI', {
  loadPreferences: () => ipcRenderer.invoke('load-prefs')
})

您可以創(chuàng)建一個(gè) renderer.d.ts 類型聲明文件,并且全局增強(qiáng) Window 接口。

export interface IElectronAPI {
  loadPreferences: () => Promise<void>,
}

declare global {
  interface Window {
    electronAPI: IElectronAPI
  }
}

以上所做皆是為了確保在您編寫渲染進(jìn)程的腳本時(shí), TypeScript 編譯器將會(huì)知曉electronAPI合適地在您的全局window對(duì)象中

window.electronAPI.loadPreferences()


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)