人人都会AI编程

25.4 企业级应用安全加固方案

更新时间:2026-07-11

企业级 Electron 应用的安全不能停留在“关掉 nodeIntegration”这种基础要求上。面对数据泄露、代码注入、供应链攻击等真实威胁,你需要一套覆盖开发、构建、分发、运行全链路的加固方案。以下每一项都是经过大量生产环境验证的硬措施,没有理论空谈。


25.4.1 渲染进程的硬隔离

1. 强制开启 contextIsolation,绝不回退

从 Electron 12 开始,contextIsolation 默认为 true,并且官方强烈建议不要关闭。这一步必须保留并显式确认:

// main.js
const win = new BrowserWindow({
  webPreferences: {
    contextIsolation: true,   // 必须为 true
    nodeIntegration: false,   // 必须为 false
    sandbox: true,            // 见下文
  }
});

关闭 contextIsolation 会让渲染进程的 JavaScript 可以直接访问主进程的 require 和 Electron 内部对象,等同于把整个系统的钥匙交给了网页内容。任何 XSS 漏洞都可以直接变成远程代码执行(RCE)。

2. 启用沙盒(sandbox)

在支持的操作系统上,将渲染进程运行在操作系统级的沙箱中,进一步限制其文件系统、网络和系统调用权限:

webPreferences: {
  sandbox: true
}

启用 sandbox 后,渲染进程默认无法使用 Node.js API,预加载脚本也需要通过 contextBridge 暴露有限功能。即使网页内容被攻破,攻击者也被困在一个极低权限的环境里。


25.4.2 预加载脚本的安全基线

预加载脚本是主进程与渲染进程之间唯一的数据通道,必须做到权限最小化。

1. 使用 contextBridge 精确暴露 API

永远不要通过 preload 直接向 window 对象注入 Node.js 模块或 Electron 的完整 ipcRenderer。正确的做法是:

// preload.js
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('secureApi', {
  // 只暴露这一个方法,并且做参数校验
  saveFile: (filePath, content) => {
    // 参数可在主进程再次验证
    return ipcRenderer.invoke('save-file', { filePath, content });
  },
  getAppVersion: () => ipcRenderer.invoke('get-version')
});

渲染进程只能调用 window.secureApi.saveFile(),它接触不到 ipcRenderer 本体,也无法随意向主进程发送任意消息。

2. 在主进程对 IPC 调用进行参数验证和权限判断

所有来自渲染进程的 invokesend,主进程处理时要把它们当作“不可信数据”:

// main.js
ipcMain.handle('save-file', async (event, { filePath, content }) => {
  // 1. 验证调用来源的窗口或 WebContents(白名单)
  if (!isCallerAllowed(event.sender)) throw new Error('Unauthorized');
  
  // 2. 检查文件路径是否在允许的目录内(防目录遍历)
  const safePath = path.resolve(app.getPath('userData'), 'files', path.basename(filePath));
  
  // 3. 内容大小、类型检查
  if (content.length > MAX_FILE_SIZE) throw new Error('File too large');
  
  return fs.promises.writeFile(safePath, content, 'utf-8');
});

绝不要在 IPC 通道中直接暴露 fs.readFilechild_process.exec 等底层 API,必须在主进程封装一层白名单式的业务方法。


25.4.3 内容安全策略(CSP)

为应用的所有网页设置严格的 CSP 头,这能在浏览器层面阻止 XSS 代码的执行和数据外泄。

1. 通过 meta 标签或响应头设置 CSP

<!-- index.html -->
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; 
               script-src 'self'; 
               style-src 'self' 'unsafe-inline'; 
               img-src 'self' data:;
               connect-src 'self' https://api.mycompany.com;">
  • default-src 'self':所有资源必须来自应用自身,阻止加载外部恶意脚本。
  • script-src 'self':禁止内联脚本和 eval,这是防御 XSS 的关键。如果必须使用内联,可以配合 nonce 或 hash。
  • connect-src:限定应用可以发起的网络请求目标,即使页面被注入代码,也无法将数据发送到攻击者控制的服务器。
  • style-src 'unsafe-inline' 可以根据实际情况收紧,但为了 UI 组件库的兼容性常需保留。

2. 在主进程中通过 session 统一设置

// main.js
const { session } = require('electron');

app.on('ready', () => {
  session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
    callback({
      responseHeaders: {
        ...details.responseHeaders,
        'Content-Security-Policy': [
          "default-src 'self'; script-src 'self'; connect-src 'self' https://api.mycompany.com"
        ]
      }
    });
  });
});

这样可以确保所有加载的页面(包括 iframe、webview)都强制应用同一套策略。


25.4.4 依赖与供应链安全

企业应用很可能使用大量 npm 包,你必须防范恶意依赖和已知漏洞。

1. 锁定依赖版本与完整性校验

使用 package-lock.jsonyarn.lock 并提交到仓库,禁止使用 *^ 的范围版本。在 CI 中启用 npm 的完整性校验(npm ci 而不是 npm install)。

2. 定期运行安全审计

npm audit
# 或
yarn audit

将审计结果集成到 CI 流程中,对高危漏洞设置阻断。但不要盲目全量升级,应在测试环境验证兼容性。

3. SCA(软件成分分析)工具

使用 Snyk、WhiteSource 或 OWASP Dependency-Check 扫描项目依赖,并建立企业级漏洞响应流程。

4. 自建 npm 代理或镜像

通过 Verdaccio、Nexus 等工具自建私有 registry,缓存并审查所有依赖包,防止投毒和供应链中断。


25.4.5 应用签名与完整性

未签名的应用容易被篡改或替换,用户也无法验证其来源。

1. Windows:代码签名证书

从 DigiCert、GlobalSign 或 Certum 购买 EV 代码签名证书,使用 electron-builder 配置自动签名:

// package.json (electron-builder 配置)
"win": {
  "sign": "./scripts/sign.js",
  "certificateFile": "cert.pfx",
  "certificatePassword": "env:CERT_PASSWORD"
}

对于 Windows,使用 signtoolelectron-builder 的集成签名即可。签名后的应用在安装和运行时不会触发 SmartScreen 警告。

2. macOS:公证(Notarization)

自 macOS Catalina 起,未公证的软件会被 Gatekeeper 拦截。你需要:

  • 加入 Apple Developer Program。
  • 配置 electron-builder 使用 notarize 工具(如 @electron/notarize):
  // electron-builder 配置
  "mac": {
    "hardenedRuntime": true,
    "gatekeeperAssess": false,
    "entitlements": "entitlements.mac.plist",
    "entitlementsInherit": "entitlements.mac.plist"
  },
  "afterSign": "scripts/notarize.js"
  

3. 应用更新也必须验证签名

使用 electron-updater 时,在 app-update.yml 中必须配置 publisherName 并启用签名检查:

provider: generic
url: https://updates.mycompany.com
publisherName: My Company Inc.

这种验证能确保更新包在下载和安装过程中未被篡改。


25.4.6 数据安全与本地存储

企业应用通常会在本地存储敏感数据(token、用户配置、离线数据)。

1. 加密本地存储

  • 对于键值对数据,使用 safeStorage API 进行加密后存入 localStorage 或 JSON 文件:
  const { safeStorage } = require('electron');
  const encrypted = safeStorage.encryptString('my-sensitive-data');
  // 存入文件或 sqlite
  

safeStorage 使用操作系统级的加密(macOS Keychain、Windows DPAPI)。

  • 对于结构化数据(如 SQLite),考虑使用 sqlcipherbetter-sqlite3 配合自定义加密层,但更推荐将关键字段单独加密存储。

2. 清除敏感痕迹

  • 禁止在崩溃报告、日志文件中写入敏感信息。所有日志输出前需做脱敏处理。
  • 应用退出时清除剪贴板中的敏感内容(如果业务需要):
  const { clipboard } = require('electron');
  clipboard.clear();
  

3. 网络传输强制 HTTPS

即使在 Electron 里,也不允许回退到 HTTP。可以通过 webRequest 强制升级:

session.defaultSession.webRequest.onBeforeRequest((details, callback) => {
  if (details.url.startsWith('http://')) {
    callback({ redirectURL: details.url.replace('http://', 'https://') });
  } else {
    callback({});
  }
});

25.4.7 进程与权限控制

1. 禁止 remote 模块

@electron/remote 已废弃,新项目严禁使用。它让渲染进程几乎可以调用主进程的所有能力,完全破坏了隔离模型。

2. 限制 webview 标签

如果必须使用 webview,要为其单独设置 preloadsandbox 和严格的 CSP,并在其 console 中监控异常。最好的做法是尽量不用 webview,改用 BrowserViewiframe(配合合适的安全策略)。

3. 关闭不必要的 Chromium 特性

main.js 中通过 app.commandLine.appendSwitch 关掉可能被利用的调试功能和实验特性:

app.commandLine.appendSwitch('disable-http2');
// 生产环境移除或限制 --inspect
app.commandLine.appendSwitch('remote-debugging-port', '0');

另外,务必在打包时设置 ELECTRON_ENABLE_LOGGING=false 并移除 --inspect 相关的启动参数。


25.4.8 安全更新与应急响应

1. 内置强制更新机制

使用 electron-updater 并配置为启动时自动检查更新,对关键安全补丁实行强制升级:

autoUpdater.on('update-downloaded', () => {
  // 提示用户,如果版本是最低安全基线以下则退出应用
  if (currentVersion < MINIMUM_SECURE_VERSION) {
    dialog.showMessageBox({ message: '安全更新已完成,应用即将重启' });
    autoUpdater.quitAndInstall();
  }
});

2. 漏洞应急流程

  • 建立对 Electron 和 Chromium 安全公告(Electron Security)的监控。
  • 确定内部修复 SLA(通常高危漏洞在 48 小时内完成修复和推送)。
  • 紧急情况下通过 autoUpdater 推送补丁版本,并利用应用内置的消息通道广播给所有在线用户。

25.4.9 自动化安全检查

最后,把这些策略固化为 CI 规则和代码扫描,避免人工遗忘。

1. 使用 Electronegativity

Electronegativity 是一款专门针对 Electron 应用的静态分析工具,能检测 nodeIntegration 开启、contextIsolation 关闭、危险 API 使用等常见配置错误。将其集成到 CI 管道:

npx @doyensec/electronegativity -i ./app

如果检出高危问题,直接阻断构建。

2. ESLint 安全插件

在项目中启用 eslint-plugin-security 和自定义规则,禁止在渲染进程代码中直接出现 require('fs')ipcRenderer.send 等模式。

3. 定期渗透测试

即使有自动化工具,仍然需要定期邀请安全团队或外部机构对应用进行渗透测试,特别是针对主进程 IPC 接口的模糊测试。


企业级安全防护不是一次性配置,而是一套持续集成的流程。上面这些措施每一个都能显著提升应用的抗攻击能力,合在一起才能构建起纵深防御。结合你的具体业务场景,可以先从“关闭 nodeIntegration + contextIsolation + CSP” 三项立即生效的硬措施开始,然后逐步向签名、加密存储和 CI 检测推进。