Я загружаю внешний контент в свое электронное приложение, которое может быть небезопасным. Я хочу предоставить API для этого выгруженного контента в виде класса. Этот класс API должен иметь доступ к привилегиям nodeIntegration, однако я НЕ хочу, чтобы ненадежный внешний контент имел такие привилегии. Ненадежный код загружается в веб-просмотр, а класс API загружается в веб-представление посредством предварительной загрузки. Скрипт загружается, и класс создается, он может без проблем выполнять все функции, которые я хочу. Но вот в чем проблема: после того, как скрипт завершит загрузку, класс, который я хочу оставить в глобальной области видимости, будет уничтожен. Единственный способ для этого ненадежного кода получить доступ к моему 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
1
Ian Wise 22 Сен 2018 в 01:23

2 ответа

Лучший ответ

Поместите API в переменную окна под сценарием предварительной загрузки. Пример:

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
Ian Wise 23 Сен 2018 в 22:47

Скопировано из моего ответа здесь: https://stackoverflow.com/a/57656281/289203

  1. Можно ли использовать ipcRenderer без включения nodeIntegration?

Это возможно, но неудобно. Это можно сделать с помощью скрипта preload.

  1. Если да, то как мне это сделать и почему так много ресурсов исключают эту информацию?

Это возможно, используя сценарий preload, как указано ниже. Однако это не считается безопасным. . Большая часть существующей документации не содержит лучших практик безопасности.

Позже приводится более безопасный пример.

// 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. Если нет, что мне использовать?

Как уже упоминалось, хотя можно использовать ipcRenderer, как показано выше, в текущих рекомендациях по электронной безопасности рекомендуется также включить contextIsolation. Это сделает вышеупомянутый подход непригодным для использования, поскольку вы больше не сможете добавлять данные в глобальную область.

Самая безопасная рекомендация, AFAIK, - использовать вместо них addEventListener и postMessage и использовать сценарий предварительной загрузки в качестве моста между средством визуализации и основными сценариями.

// 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,
});
0
Luke H 26 Авг 2019 в 10:40