← [ BACK_TO_NOTES ]

Electron contextBridge

contextBridge 在 contextIsolation 开启时把 preload 的 Isolated World 与页面 Main World 连接起来,并以可序列化、可审核的窄接口暴露能力;它不是通用对象共享机制,也不应直接暴露 ipcRenderer。

#desktop #electron #concept #evergreen

[!info] related notes

Electron contextBridge

一句话定义

contextBridge 是 Electron 在 contextIsolation 模型下提供的跨 JavaScript context 桥接机制。

典型关系:

preload / Isolated World
→ contextBridge
→ renderer / Main World

它的目标不是“共享整个 preload 环境”,而是:

只把明确允许的、最小的 API contract 暴露给页面。

为什么需要它

contextIsolation 开启后:

  • preload 与页面不是同一个 JavaScript context;
  • preload 的 window 与页面的 window 不相同;
  • 页面不能直接读取 preload 内部对象。

因此旧写法:

window.myApi = …

不能再作为隔离模式下的标准桥接方案。

应通过:

contextBridge.exposeInMainWorld(…)

显式定义页面可见能力。

API Contract

推荐暴露:

  • getVersion()
  • openFile()
  • saveSettings(input)
  • onUpdateAvailable(callback)

这类业务语义 API。

不推荐暴露:

  • ipcRenderer
  • fs
  • shell
  • process
  • 任意 invoke(channel, payload)
  • 任意 send(channel, payload)

原因是:

renderer compromise 时,攻击者只能使用你暴露的 capability。

API 越窄,攻击面越小。

Electron 29 的边界

Electron 29 起,ipcRenderer 不能整体通过 contextBridge 传递。

这不仅是 API breaking change,也是明确的安全方向:

不要把整个 IPC surface 暴露给 renderer。

官方推荐提供 safe wrapper,例如只暴露某个固定事件或固定 invoke。

跨 Bridge 的值

contextBridge 并不是任意 JavaScript object 的共享内存。

跨 context 的参数、返回值会受到类型与序列化约束。

常见简单数据:

  • string
  • number
  • boolean
  • Array
  • plain object

通常更适合作为 contract。

自定义 prototype、某些复杂对象、Symbol 等不能按普通引用语义跨 bridge 使用。

因此 renderer-facing API 应倾向:

plain serializable data + functions

而不是暴露底层 Electron object。

Callback Wrapper

如果 main 向 renderer 推送事件,不要把原始 IPC event 对象直接传给页面。

错误方向:

renderer callback(event, data)

其中 event 可能携带 sender 等高权限相关能力。

更安全:

preload 接收 IPC event
→ 丢弃 event object
→ 只把已验证 data 传给 renderer callback

这与 Electron 官方 IPC 教程的安全建议一致。

TypeScript

对于 renderer:

window.appApi.openFile()

应该有明确类型。

推荐把 renderer-facing interface 单独定义:

  • API method name;
  • input;
  • output;
  • event payload。

然后通过 global Window declaration 暴露类型。

这样 preload contract 既是安全边界,也是编译期 contract。

contextBridge 不是 Validation Layer 的全部

即使 renderer 只能调用:

window.appApi.deleteFile(path)

main 进程仍然必须验证:

  • sender;
  • path;
  • permission;
  • domain rule;
  • current app state。

因为 renderer 输入仍然应该视为不可信。

常见失败模式

万能 send/invoke

页面自己选择 channel。

→ 白名单边界基本失效。

把 Node object 暴露出去

→ capability 太大,且跨 bridge 语义不稳定。

callback 泄漏 IPC event

→ renderer 获得超出预期的底层对象。

API 名称只反映技术实现

例如:

invokeFileChannel()

比:

openFile()

更容易让 renderer 和 IPC implementation 强耦合。

学习检查

  1. contextBridge 为什么在 contextIsolation 开启时需要存在?
  2. Isolated World 与 Main World 的 window 为什么不是同一个对象?
  3. 为什么 openFile() 比 invoke(channel) 更安全?
  4. Electron 29 对 ipcRenderer 跨 bridge 做了什么限制?
  5. 为什么 callback 不应直接收到原始 IPC event?
  6. contextBridge 为什么不等于任意对象共享机制?
  7. 设计一个 settings API,只暴露 getSettings / updateSettings 两个 renderer capability。
创建于 2026/4/13 更新于 2026/9/30
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本