我将外部内容加载到我的电子应用程序中,这可能是不安全的。我想以类的形式向此卸载的内容公开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
答案 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
- 是否可以在不启用nodeIntegration的情况下使用ipcRenderer?
可能,但很奇怪。可以使用preload
脚本来完成。
- 如果是,该怎么办?为什么会有这么多资源排除此信息?
可以使用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时会变得复杂,因为输出文件可能是不同的路径。
- 如果不是,我该怎么用?
如上所述,尽管可以使用ipcRenderer,但当前的电子安全建议也建议启用contextIsolation
。这将使上述方法无法使用,因为您无法再将数据添加到全局范围。
最安全的建议是AFAIK改为使用addEventListener
和postMessage
,并使用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,
});