编辑2022年
我已经发表了一篇关于Electron历史的更大文章,它的安全性提供了有关影响不同框架版本中如何实现安全性的变化的额外背景信息(以及采取的最佳方法是什么)。
原始答案
我希望这个答案得到一些关注,因为这里的绝大多数答案都会在你的电子应用程序中留下很大的安全漏洞。事实上,这个答案本质上是你应该在你的电子应用程序中使用的东西(只是有一个新的电子API,使它在v7中更干净一些)。require()
我在github中使用了最新的电子apis编写了一个详细的解释/解决方案,说明如何做某事,但我在这里简要解释为什么你应该遵循使用预加载脚本,contextBridge和ipc的方法。require()
问题
Electron应用程序很棒,因为我们可以使用node,但这种功能是一把双刃剑。如果我们不小心,我们会通过我们的应用程序让某人访问节点,而使用node,不良行为者可能会损坏您的计算机或删除您的操作系统文件(除其他外,我想)。
正如@raddevus在注释中提出的,这在加载远程内容时是必需的。如果您的电子应用程序完全是离线/本地的,那么您可能只需打开即可。但是,我仍然会选择继续充当使用您的应用程序的意外/恶意用户的保护措施,并防止任何可能安装在您计算机上的恶意软件与您的电子应用程序交互并使用攻击媒介(非常罕见,但可能发生)!nodeIntegration:true
nodeIntegration:false
nodeIntegration:true
问题看起来如何
当您(以下任一情况)时,此问题会显现出来:
- 已启用
nodeIntegration:true
- 使用
远程
模块
所有这些问题都允许从渲染器进程不间断地访问节点。如果您的渲染器进程被劫持,您可以认为所有内容都丢失了。
我们的解决方案是什么
解决方案是不要让渲染器直接访问节点(即),而是让我们的电子主进程访问,并且每当我们的渲染器进程需要使用时,将请求封送到主进程。require()
require
require
这在最新版本(7 +)的Electron中的工作方式是在渲染器方面,我们设置了ipcRenderer绑定,在主方面我们设置了ipcMain绑定。在 ipcMain 绑定中,我们设置了使用模块 we .这很好,因为我们的主要流程可以满足它想要的一切。require()
require
我们使用 contextBridge 将 ipcRenderer 绑定传递给我们的应用代码(使用),因此当我们的应用需要在 main 中使用 d 模块时,它会通过 IPC(进程间通信)发送一条消息,主进程运行一些代码,然后我们发送一条消息并返回我们的结果。require
粗略地说,这是您要执行的操作。
主要.js
const {
app,
BrowserWindow,
ipcMain
} = require("electron");
const path = require("path");
const fs = require("fs");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
async function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false, // is default value after Electron v5
contextIsolation: true, // protect against prototype pollution
enableRemoteModule: false, // turn off remote
preload: path.join(__dirname, "preload.js") // use a preload script
}
});
// Load app
win.loadFile(path.join(__dirname, "dist/index.html"));
// rest of code..
}
app.on("ready", createWindow);
ipcMain.on("toMain", (event, args) => {
fs.readFile("path/to/file", (error, data) => {
// Do something with file contents
// Send result back to renderer process
win.webContents.send("fromMain", responseObj);
});
});
预紧力.js
const {
contextBridge,
ipcRenderer
} = require("electron");
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
"api", {
send: (channel, data) => {
// whitelist channels
let validChannels = ["toMain"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
}
}
);
索引.html
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8"/>
<title>Title</title>
</head>
<body>
<script>
window.api.receive("fromMain", (data) => {
console.log(`Received ${data} from main process`);
});
window.api.send("toMain", "some data");
</script>
</body>
</html>
免責聲明
我是secure-electron-template
的作者,这是一个构建电子应用程序的安全模板。我关心这个话题,并且已经为此工作了几个星期(在这个时间点)。