Skip to content

隔离进程

上下文隔离

向军大叔每晚八点在 抖音bilibli 直播

xj-small

上下文隔离是从安全角度考量的,即不允许 webcontent网页使用electron内部组件与node等权限 。 默认情况下 electron 是开启上下文隔离的。

因为使用Electron开发的桌面应用,是比较特殊的。他是使用网页开发的,所以会引用第三方的应用,如果不进行隔离,这些应用是有机会调用node.js api 的,如果应用是恶意的,就会对用户电脑带来案全隐患。

使用上下文隔离对团队开发好处也是明显的,可以让熟悉vue、react的前端工程师专门编写前端页面逻辑,让熟悉nodejs与electron的开发者负责node.js程序编写。

变量隔离

关闭上下文隔离后,网页脚本可以使用electron与node api等部分高级api。

下面是在 main.js 中禁用上下文隔离的方法

...
webPreferences: {
    preload: path.resolve(__dirname, 'preload.js'),
    contextIsolation: false,
    nodeIntegration: true,
},
...

禁用上下文隔离后 preload.js与renderer.js没有隔离机制,在preload.js中定义的变量可以在renderer.js中直接使用。

在 preload.js 定义全局变量

window.hd = 'abc'

现在可以在 renderer.js 网页脚本中访问了

console.log(window.hd)

exposeInMainWorld

禁用上下文隔离后 contextIsolation: false,在preload.js中则不需要使用 contextBridge.exposeInMainWorldrenderer.js 中提供接口了。

main.js主进程定义IPC事件

const { app, shell } = require('electron')
const { BrowserWindow, ipcMain } = require('electron/main')
const path = require('path')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 500,
    height: 500,
    webPreferences: {
      preload: path.resolve(__dirname, 'preload.js'),
      contextIsolation: false
    },
  })
  win.webContents.openDevTools()
  win.loadFile(path.resolve(__dirname, 'index.html'))
}

app.whenReady().then(() => {
  createWindow()
  //定义IPC事件处理程序
  ipcMain.handle('show', () => {
    return 'houdunren.com'
  })
})

preload.js 直接定义接口

const { ipcRenderer } = require('electron')
const { contextBridge } = require('electron/renderer')

window.api = {
  show: () => ipcRenderer.invoke('show'),
}

renderer.js 渲染脚本使用

window.api.show().then((res) => {
  console.log(res)
})

nodeIntegration

可以通过修改 main.js 中的 nodeIntegration 配置,来开启node支持,这时就可以在preload.js或renderer.js中使用fs 等高级模块了。

...
const win = new BrowserWindow({
    width: 500,
    height: 500,
    webPreferences: {
      preload: path.resolve(__dirname, 'preload.js'),
      nodeIntegration: true,
    },
  })
...

preload.js 默认只能使用有限的 node.js api,不能使用 fs 等高级模块,但开启 nodeIntegration 后,就可以使用了。

const { readFileSync } = require('fs')

const res = readFileSync('package.json', {
  encoding: 'utf-8',
})
console.log(res)

如果想在 renderer.js 中使用 node.js 高级模块也是可以的,需要在 main.js 文件中关闭上下文隔离 contextIsolation: false 和开启node支持 nodeIntegration: true

...
const win = new BrowserWindow({
  width: 300,
  height: 300,
  x: 1500,
  y: 100,
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
    contextIsolation: false,
    nodeIntegration: true,
  },
})
...

进程沙盒

当 Electron 中的渲染进程被沙盒化时,它们的行为与常规 Chrome 渲染器一样。 一个沙盒化的渲染器不会有Node.js 环境。

在沙盒中,渲染进程只能通过进程间通讯 (inter-process communication, IPC) 委派任务给主进程的方式,来执行需权限的任务 (例如:文件系统交互,对系统进行更改或生成子进程) 。

如果我们想在preload.js中使用node.jselectron高级应用,如shell、fs等,可以通过关闭沙盒完成。当然通过开启 nodeIntegration 也可以实现该功能,但这会让renderer.js也可以使用node.js高级api,这是不安全的。

所以,开启沙盒,可以赋予preload.js高级权限,但不影响renderer.js。

  • electron默认是开启沙盒模式的
  • nodeIntegration:true 时会自动开启沙盒
  • sandbox: false 时 preload.js 可以使用nodejs、electron的高级api,如fs模块

基本使用

下面演示在关闭沙盒后,可以在 preload.js 中使用electron的shell模块

main.js主进程中禁用沙盒模式

const { app, shell } = require('electron')
const { BrowserWindow } = require('electron/main')
const path = require('path')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 500,
    height: 500,
    webPreferences: {
      preload: path.resolve(__dirname, 'preload.js'),
      //关闭沙盒模式
      sandbox: false,
    },
  })
  win.webContents.openDevTools()
  win.loadFile(path.resolve(__dirname, 'index.html'))
}

app.whenReady().then(() => {
  createWindow()
})

关闭沙盒模式后preload.js 中可以使用shell模块打开链接了

const { shell } = require('electron')

shell.openExternal('https://www.houdunren.com')

自动关闭沙盒

以下代码表示禁用上下文隔离,设置了 nodeIntegration:true 也会关闭沙盒。

...
webPreferences: {
    preload: path.resolve(__dirname, 'preload.js'),
    contextIsolation: false,
    nodeIntegration: true,
},
...

这时可以在renderer.js渲染进程脚本中使用 node 与 electron api 等部分高级api。

const { shell } = require('electron')

shell.openExternal('https://www.houdunren.com')