上下文隔离
667字约2分钟
2024-12-04
上下文隔离是什么?
上下文隔离是一种机制,旨在将主进程、预加载脚本(Preload 脚本)以及渲染进程分隔开,使它们处于不同的上下文环境中。在这种隔离状态下,主进程与预加载脚本之间的通信只能通过 IPC
(进程间通信)来实现。而对于渲染进程和预加载脚本,Electron 提供了专门的 contextBridge
模块,以协助它们之间的通信。
需要注意的是,当启用上下文隔离时,预加载脚本所访问的 window
对象并非网站可访问的对象。例如,若在预加载脚本中设置 window.hello = 'wave'
,当渲染进程中的网站尝试访问 window.hello
对象时,会返回 undefined
。
注意
自 Electron 12 以来,默认情况下已启用上下文隔离,并且它是 _所有应用程序_推荐的安全设置。
预加载脚本注意事项
预加载脚本虽然因为上下文隔离的机制不能访问渲染进程的
window
变量,但它可以访问渲染进程的JavaScript DOM API
(如 document.getElementById、document.querySelector 等)来操作DOM
元素 和 监听页面的事件如DOMContentLoaded
。通过预加载脚本传递给渲染进程的
Node
对象将会被序列化, 去除了能够访问Node.js
和Electron API
的方法。如下:
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
getData: () => {
console.log('old ipcRenderer:', ipcRenderer)
return ipcRenderer
}
})
console.log('new ipcRenderer:', window.electronAPI.getData())
输出结果:
contextBridge
模块
contextBridge
模块是 Electron 提供的一个模块, 它提供了一种安全的方式来将 API 从预加载脚本 Preload 脚本
暴露给渲染进程,而不会受到 contextIsolation
的影响。
// 在上下文隔离启用的情况下使用预加载
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
doAThing: () => {}
})
// 在渲染器进程使用导出的 API
window.myAPI.doAThing()
安全事项
单开启和使用 contextIsolation 并不直接意味着您所做的一切都是安全的。例如,在使用contextBridge
模块暴露API时,应用函数包裹API, 而不要直接暴露API本身。
// preload.js
// ❌ 错误使用
contextBridge.exposeInMainWorld('myAPI', {
send: ipcRenderer.send
})
它直接暴露了一个没有任何参数过滤的高等级权限 API 。 这将允许任何网站发送任意的 IPC 消息,这不会是你希望发生的。 相反,暴露进程间通信相关 API 的正确方法是为每一种通信消息提供一种实现方法。
// preload.js
// ✅ 正确使用
contextBridge.exposeInMainWorld('myAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs')
})