电子,如何在不使用nodeIntegration的情况下访问节点API

时间:2018-09-21 22:23:04

标签: javascript node.js class security electron

我将外部内容加载到我的电子应用程序中,这可能是不安全的。我想以类的形式向此卸载的内容公开API。该API类应该有权访问nodeIntegration特权,但是我不希望不受信任的外部内容具有这种特权。不受信任的代码被加载到webview中,并且API类通过preload被加载到webview中。脚本加载并创建了类,它可以执行我想要的所有功能而不会出现问题。但是,这里的问题是,脚本完成加载后,我想保留在全局范围内的类被破坏了。这种不受信任的代码访问我的API的唯一方法是,如果此类保留在全局范围内。 是否可以在预加载脚本中实例化一个可以访问nodeIntegration的类,并且可以通过非预加载脚本文件访问该类?

示例:

预加载的脚本:

var API = function() {
    const fs = remote.require('fs');

    API.createFile = function(){
        /*... do stuff with fs here ...*/
    }
}

未预加载脚本(不受信任的代码)

var instanceOfAPI = new API();

instanceOfAPI.createFile(); //should work
fs.writeFile(); //should NOT work

2 个答案:

答案 0 :(得分:1)

将API放入preload脚本下的window变量中。示例:

var API = function() {
    const fs = remote.require('fs');

    API.createFile = function(){
        /*... do stuff with fs here ...*/
    }
}

window.api = new API();

以下内容现在适用于无法访问nodeIntegration的脚本

window.api.createFile() //works
fs.writeFile() //does not

答案 1 :(得分:0)

从我的回答此处复制:https://stackoverflow.com/a/57656281/289203

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

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

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

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

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

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

process.once('loaded', () => {
  global.ipcRenderer = electron.ipcRenderer;
});
// 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')}`);

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

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

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

最安全的建议是AFAIK改为使用addEventListenerpostMessage,并使用preload脚本作为渲染器和主要脚本之间的桥梁。

// 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);
    }
  });
});
// main.js
const {app, ipcMain, BrowserWindow} = require('electron');

app.on('ready', () => {
  ipcMain.on('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')}`);
// renderer.js
window.postMessage({
  myTypeField: 'my-custom-message',
  someData: 123,
});