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.log 或 process 对象,否则可能泄露堆栈信息。
使用 invoke/handle 模式而非 send/on
invoke 和 handle 返回 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' });