电子IPC和节点集成

Ant*_*lga 7 javascript reactjs webpack electron

因此,我遵循了许多指南来设置Webpack,Electron和React来制作桌面应用程序。完成设置后,我开始工作,并了解到我需要从主机和渲染器获得IPC机制才能进行通信。

import {ipcRenderer} from "electron"; 将其添加到我的renderer.js文件会导致错误Uncaught ReferenceError: require is not defined

在将我的问题带给一些同事之后,建议我在main.js文件中进行更改

webPreferences: {
    nodeIntegration: false,
}
Run Code Online (Sandbox Code Playgroud)

webPreferences: {
    nodeIntegration: true,
}
Run Code Online (Sandbox Code Playgroud)

我在Google上阅读的所有内容都非常清楚地表明,如果您关心安全性,那么您就不应该这样做。但是,我为电子ipc能够使用的所有资源都使用了ipcRenderer。

现在,互联网上的每个示例是否都存在巨大的安全漏洞,还是我在这里错过了一些关键部分?

我的问题如下。

  1. 是否可以在不启用nodeIntegration的情况下使用ipcRenderer?
  2. 如果是这样,我该怎么办?为什么会有这么多资源排除此信息?
  3. 如果不是,我该怎么用?

如果我问错了问题,或者我错过了什么,或者我问这个问题的方式还有其他明显的问题,请让我知道,否则请先谢谢。

Luk*_*e H 6

  1. 是否可以在不启用nodeIntegration的情况下使用ipcRenderer?

可能,但是很奇怪。可以通过使用preload脚本来完成。

  1. 如果是这样,我该怎么办?为什么会有这么多资源排除此信息?

可以使用preload如下所示的脚本。但是,并不安全。现有的大多数文档都没有显示最佳安全实践。

随后给出一个更安全的示例。

// preload.js
const electron = require('electron');

process.once('loaded', () => {
  global.ipcRenderer = electron.ipcRenderer;
});
Run Code Online (Sandbox Code Playgroud)
// main.js
const {app, BrowserWindow} = require('electron');

app.on('ready', () => {
  // Create the browser window.
  win = new BrowserWindow({
      backgroundColor: '#fff', // always set a bg color to enable font antialiasing!
      webPreferences: {
        preload: path.join(__dirname, './preload.js'),
        nodeIntegration: false,
        enableRemoteModule: false,
        // contextIsolation: true,
        // nativeWindowOpen: true,
        // sandbox: true,
      }
  });
  win.loadURL(`file://${path.join(__dirname, 'index.html')}`);
Run Code Online (Sandbox Code Playgroud)

注意预加载脚本的路径必须是绝对路径,并且在使用webpack / babel时这也可能变得很复杂,因为输出文件可能是不同的路径。

  1. 如果不是,我该怎么用?

如上所述,尽管可以使用如上所示的ipcRenderer,但是当前的电子安全建议也建议启用contextIsolation。这将使上述方法无法使用,因为您无法再将数据添加到全局范围。

最安全的建议是AFAIK addEventListenerpostMessage而是使用和,并使用预加载脚本作为渲染器和主脚本之间的桥梁。

// preload.js
const { ipcRenderer } = require('electron');

process.once('loaded', () => {
  window.addEventListener('message', event => {
    // do something with custom event
    const message = event.data;

    if (message.myTypeField === 'my-custom-message') {
      ipcRenderer.send('custom-message', message);
    }
  });
});
Run Code Online (Sandbox Code Playgroud)
// main.js
const {app, ipcMain, BrowserWindow} = require('electron');

app.on('ready', () => {
  ipcMain.on('custom-message', (event, message) => {
    console.log('got an IPC message', e, message);
  });

  // Create the browser window.
  win = new BrowserWindow({
      backgroundColor: '#fff', // always set a bg color to enable font antialiasing!
      webPreferences: {
        preload: path.join(__dirname, './preload.js'),
        nodeIntegration: false,
        enableRemoteModule: false,
        contextIsolation: true,
        sandbox: true,
        // nativeWindowOpen: true,
      }
  });
  win.loadURL(`file://${path.join(__dirname, 'index.html')}`);
Run Code Online (Sandbox Code Playgroud)
// renderer.js
window.postMessage({
  myTypeField: 'my-custom-message',
  someData: 123,
});
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此配置是为了最大程度地提高安全性,假设您的应用程序可以打开外部URL。如果您仔细地锁定了外部站点的使用,则可以使用具有某些安全性的节点集成。 (2认同)
  • 您实际上无法使用此系统使用“require”,因为这是通过静默序列化和反序列化的消息进行的唯一通信。这意味着您无法按身份传递对象(仅传递数据的副本),并且任何特殊类都会丢失。本质上,这就像执行 JSON.parse(JSON.serialize(...)) 。您只能传递数据。您基本上需要在主进程中实现任何类似节点的逻辑,并使用消息向渲染器进程发送/接收纯数据 (2认同)