人人都会AI编程

23.1 安全基线配置清单

更新时间:2026-07-11

如果你准备将应用分发给真实用户,安全配置就不是“可选项”,而是必须认真对待的底线。Electron 的强大之处在于它赋予了 Web 页面访问系统层的能力,但这也意味着任何一个前端漏洞都可能被放大为本地攻击。庆幸的是,通过一组明确且经过行业验证的配置,你可以极大程度地缩小攻击面。下面这份清单覆盖了每个 Electron 应用都应该遵循的安全基线。

1. 开启上下文隔离(Context Isolation)

配置项webPreferences.contextIsolation
推荐值true(Electron 12 起默认为 true

这是 Electron 安全模型中最关键的一道防线。开启上下文隔离后,渲染进程的 JavaScript 环境与预加载脚本的 JavaScript 环境被完全分开,页面无法直接访问 require 或 Electron 内部 API,只能通过 contextBridge 暴露的有限接口与主进程通信。

如果你还在维护老项目,见到 contextIsolation: false 应立即列入迁移计划。它可以被简单理解为:关闭它,等于把主进程的大门钥匙直接扔在页面上。

2. 关闭 Node.js 集成

配置项webPreferences.nodeIntegration
推荐值false(Electron 5 起默认为 false

该选项控制渲染进程是否可以直接使用 Node.js 的 require。在生产环境中应始终设置为 false,否则任何 XSS 攻击都可能通过 require('child_process') 直接执行系统命令。如果你确实需要在页面中使用 Node API,请通过预加载脚本 (preload) 使用 contextBridge 安全地暴露,绝不能在全局范围内开启。

3. 启用沙盒模式

配置项app.enableSandbox()webPreferences.sandbox
推荐值true

开启沙盒后,渲染进程会被限制在操作系统的严格权限隔离环境中,即使攻击者成功执行恶意代码,也无法直接访问文件系统、网络或系统调用(除非经由主进程明确授权)。从 Electron 20 开始,沙盒默认开启,但你需要确保不额外关闭它。同时要注意,沙盒模式下除非你使用 contextBridge 或者通过主进程转发,否则预加载脚本也无法直接使用 Node.js 模块。

4. 防止敏感 API 的直接暴露

配置项webPreferences.preload 脚本中的 contextBridge 用法
推荐做法:永远不要在预加载脚本中直接暴露整个 ipcRenderershell 等模块。应该封装功能函数,比如:

// 错误:直接暴露全能 api
contextBridge.exposeInMainWorld('api', {
  send: ipcRenderer.send,
  invoke: ipcRenderer.invoke,
});

// 正确:暴露有限语义化操作
contextBridge.exposeInMainWorld('fileAPI', {
  openFile: () => ipcRenderer.invoke('dialog:openFile'),
  saveFile: (content) => ipcRenderer.invoke('fs:saveFile', content),
});

这种做法限缩了渲染进程的攻击面,避免恶意页面通过 invoke 调用任意频道,绕过后端校验。

5. 启用 webSecurity 并谨慎处理跨域

配置项webPreferences.webSecurity
推荐值true(默认值)

禁用 webSecurity 会让你的渲染页面失去同源策略保护,可以随意加载远程脚本、发起跨域请求。永远不要为了开发方便而在生产环境禁用它。有条件访问远程内容的场景,应通过主进程代理请求或使用 CORS 白名单,而不是关闭安全锁。

6. 配置内容安全策略(CSP)

配置方式:通过 HTTP 头或 <meta> 标签在渲染页面中设置
推荐策略:至少包含以下指令

<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">

CSP 是缓解 XSS 攻击后果的重要机制。因为 Electron 页面通常从本地文件加载(file:// 协议),常规的 HTTP 头无法下发,因此强烈建议在 HTML 中通过 <meta> 标签直接定义。禁止 eval 和不必要的外部脚本加载,能有效控制被注入后的灾难范围。

7. 限制或禁止远程内容加载

配置项webPreferences.webviewTag
推荐值false(除非必要)

<webview> 标签本质上是另一个独立的渲染进程,可用来嵌入第三方网页。但它的配置项复杂,且容易配置错误形成安全漏洞。建议改用 BrowserView(由主进程管控)代替。如果必须使用 webview,务必对其 preloadnodeIntegrationallowpopups 等属性单独限制。

同时,务必验证应用中任何加载的远程 URL 是否都来自受信来源。不要使用 win.loadURL(userInput) 这样的模式,避免用户控制窗口加载的地址。

8. 安全地处理用户输入和文件路径

原则:所有来自渲染进程的输入都视为不可信。
实践:在主进程接收到文件路径或命令参数时,不要直接拼接到 shell.openPathchild_process.exec 中。使用白名单校验、路径规范化(例如 path.normalize() 并检查是否在允许的目录内)来防止路径遍历攻击。避免使用 evalnew Function 处理用户提供的数据。

9. 控制新窗口的创建

配置项webPreferences 或监听 new-window 事件
推荐做法:在主进程中监听 webContentsnew-window 事件,并强制所有外部链接在外部浏览器中打开。

win.webContents.setWindowOpenHandler(({ url }) => {
  if (url.startsWith('https://yourdomain.com')) {
    return { action: 'allow' };
  }
  require('electron').shell.openExternal(url);
  return { action: 'deny' };
});

这避免恶意页面通过 window.open 偷偷创建无边栏的新窗口进行钓鱼攻击。

10. 使用安全的进程间通信(IPC)

推荐:完全使用 ipcRenderer.invoke / ipcMain.handle 模式(请求-响应式),避免使用 send/on 进行双向通信。
理由invoke/handle 返回 Promise,代码更清晰,且能确保每一次调用都有对应的处理逻辑,减少消息劫持和逻辑混乱的风险。在主进程中,务必对传入的参数进行校验,不要盲目信任频道名称和数据负载。

// 主进程中
ipcMain.handle('user:getById', async (event, userId) => {
  if (typeof userId !== 'number') throw new Error('Invalid parameter');
  return await db.getUser(userId);
});

11. 自动更新与签名

虽然不是运行时配置,但分发环节的安全同样重要。始终为你的安装包进行代码签名(Windows 使用 Authenticode,macOS 使用 Apple 开发者证书),并配置 electron-updater 或类似工具实现仅接受经过签名的更新包。这能防止中间人攻击篡改应用升级流程。

12. 定期审查 Electron 版本与依赖

Electron 团队会定期修复安全漏洞(通常跟随 Chromium 的安全更新周期)。你应该订阅 Electron 的安全公告,并制定计划至少在每个主要版本发布后进行升级。同时,审查 package.json 中的第三方依赖是否引入了已知漏洞(可使用 npm audit 或 Snyk 等工具)。


以上清单覆盖了构建安全 Electron 应用的必要配置。其核心思想可以概括为三条通用原则:

  • 最小权限:渲染进程只应拥有完成界面工作所需的最少能力。
  • 信任边界:永远把主进程和渲染进程之间的通信视为不可信边界,严格执行输入验证和操作限定。
  • 纵深防御:即便某层被突破(如 XSS),后续的沙盒、CSP、权限控制依然能限制损失的扩散。

从你着手构建第一个生产窗口开始,就用这份清单作为你的安全检查表。安全不是一个后期打补丁的过程,而是融入架构选择阶段的基本意识。