Electron ContextBridge 安全 IPC

FreeGuideOnline 最新 2026-07-11
获取主进程数据
```

安全 IPC 最佳实践

严格控制暴露的方法

永远不要直接暴露 ipcRenderer 本身,哪怕是通过 ContextBridge 包装。每个暴露的函数应该只接受预期参数,并在主进程中完成验证。

// ❌ 危险做法:暴露原始 ipcRenderer 通道
contextBridge.exposeInMainWorld('api', {
  send: (channel, data) => ipcRenderer.send(channel, data)
});
// ✅ 安全做法:为每个功能定义独立方法
contextBridge.exposeInMainWorld('api', {
  saveFile: (content) => ipcRenderer.invoke('save-file', content),
  openDialog: (options) => ipcRenderer.invoke('open-dialog', options)
});

验证通过参数

在主进程的 ipcMain.handle 中,对传入参数进行严格校验。使用类型检查、范围检查或白名单。

ipcMain.handle('save-file', async (event, content) => {
  if (typeof content !== 'string' || content.length > 10000) {
    throw new Error('非法参数');
  }
  // 安全写入文件
});

限制渲染进程的日志能力

避免暴露 console.logprocess 对象,否则可能泄露堆栈信息。

使用 invoke/handle 模式而非 send/on

invokehandle 返回 Promise,使异步通信更简洁,也更易于防止监听器泄漏。只在必须使用事件流时才使用 send/on,并在窗口关闭时移除监听器。

对暴露对象使用 Object.freeze 或定义不可配置属性

ContextBridge 默认创建的对象是可配置的,但为了增强安全性,可以在预加载脚本中冻结暴露的对象。

const api = {
  getData: (param) => ipcRenderer.invoke('get-data', param)
};
contextBridge.exposeInMainWorld('secureApi', Object.freeze(api));

常见场景和解决方案

传递复杂数据

通过 invoke 可以传递可被结构克隆或 JSON 序列化的数据。对于 Buffer 或大文件,可以在预加载脚本中暴露处理路径的方法,而非直接发送文件内容。

响应渲染进程请求时更新 UI

如果需要主进程主动向渲染进程推送消息(例如通知),可以使用 webContents.send 并在渲染进程通过暴露的回调监听。但需要确保在窗口销毁时清理监听器。

预加载脚本

contextBridge.exposeInMainWorld('notifications', {
  onUpdate: (callback) => {
    // 移除旧的监听器再添加新的,防止内存泄漏
    ipcRenderer.removeAllListeners('update-trigger');
    const handler = (_event, value) => callback(value);
    ipcRenderer.on('update-trigger', handler);
  }
});

主进程

win.webContents.send('update-trigger', { status: 'done' });