electron大家平时为了方便使用,或是一些网上demo的引导,会让渲染进程的业务界面支持直接使用nodejs,这种开发方式有一定的安全隐患,如果业务界面因为xss之类的漏洞被注入其他代码,危害非常大,属于最高等级的安全问题。那么怎样更好的避免发生这种问题呢?
win = new BrowserWindow({
webPreferences: {
preload:"./preload.js",
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
nodeIntegration: true,
//webviewTag: true,
contextIsolation: true,//隔离
},
});
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
openFile: () => ipcRenderer.invoke('dialog:openFile')
})
在渲染进程界面采用window.electronAPI.openFile()方式调用,为了让渲染进程足够安全,建议设计这里的接口尽量做到仅暴露必要函数和参数,不要直接把诸如electron对象暴露给页面界面,这种事情干多了,这个安全隔离的意义就会逐渐消失。
渲染进程与preload通讯的另外一种方式,通过postmessage,举例
preload.js
window.onmessage = (ev) => {
ev.data.payload === "removeLoading" && removeLoading();
};
渲染页js
postMessage({ payload: "removeLoading" }, "*");
这种方式相比第一种更加安全一点(暴露的信息更加隐蔽),但使用起来比较麻烦,可能需要进一步封装
1.preload.js在跳转到新地址后还会不会存在?
答:会,每次发生跳转preload.js都会重新加载进来,跟普通加载js一样,所以这个js的变量并非持久化的
2.采用exposeInMainWorld暴露的接口需要注意什么?
答:exposeInMainWorld暴露的接口,是拷贝当前对象的属性,并不是真的把属性的引用暴露出来,例如暴露的属性是一个 new?EventEmitter对象,你想在业务界面访问这个属性的on方法是访问不到的。
3.preload跟主进程通讯方式
方式一:invoke和handle的组合
//preload.js
let a = ipcRenderer.invoke('xxx')
//main.js
ipcMain.handle('xxx', async ()=>{
return "123"
})
方式二:on和send的组合
// 在主进程中.
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.reply('asynchronous-reply', 'pong')
})
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.returnValue = 'pong'
})
/在渲染器进程 (网页) 中。
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')