看起来 Electron 的安全性是这样发展的 (source)。
Electron 1 nodeIntegration 默认为 true
Renderer 可以完全访问 Node API ——如果 Renderer 加载远程代码,会带来巨大的安全风险。
Electron 5 nodeIntegration 默认为 false
当设置为 false 时,预加载脚本用于向渲染器公开特定的 API。 (无论 nodeIntegration 的值如何,预加载脚本始终可以访问 Node API)
//preload.js
window.api = {
deleteFile: f => require('fs').unlink(f)
}
Electron 5 contextIsolation 默认为 true(实际上在 Electron 11 中仍默认为 false)
这会导致预加载脚本在单独的上下文中运行。你不能再做window.api = ...。你现在必须做:
//preload.js
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('api', {
deleteFile: f => require('fs').unlink(f)
})
Electron 6 require()ing 沙盒渲染器中的内置节点不再隐式加载远程版本
如果 Renderer 将 sandbox 设置为 true,您必须这样做:
//preload.js
const { contextBridge, remote } = require('electron')
contextBridge.exposeInMainWorld('api', {
deleteFile: f => remote.require('fs').unlink(f)
})
Electron 10 enableRemoteModule 默认为 false(remote 模块在 Electron 12 中已弃用)
remote 模块在您需要从沙盒渲染器访问节点 API 时使用(如上例所示);或者当您需要访问仅可用于主进程(例如对话框、菜单)的 Electron API 时。如果没有remote,您将需要编写显式 IPC 处理程序,如下所示。
//preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('api', {
displayMessage: text => ipcRenderer.invoke("displayMessage", text)
})
//main.js
const { ipcMain, dialog } = require('electron')
ipcMain.handle("displayMessage", text => dialog.showMessageBox(text))
Electron 10 deprecate nodeIntegration 标志(在 Electron 12 中已移除)
推荐
始终设置{nodeIntegration: false, contextIsolation: true, enableRemoteModule: false}。
为获得最大安全性,请设置{sandbox: true}。您的预加载脚本必须使用 IPC 来调用主进程来执行所有操作。
如果sandbox 为假,您的预加载脚本可以直接访问Node API,如require('fs').readFile。只要您不这样做,您就是安全的:
//bad
contextBridge.exposeInMainWorld('api', {
readFile: require('fs').readFile
})