本节摘要:安全防线的收尾是把"还开着的门"逐一清点:IPC 通道按能力分级,高危通道要么删除要么改造;沙箱在遗留代码上做强化迁移;依赖供应链用审计工具与锁文件纪律看住。本节给出能力分级方法、一份上线前安全自查表,并以一次依赖投毒事件的响应过程展示供应链防御的实战形态。
基线、CSP、防注入都做完,最后一公里的问题很具体:桥上还开着哪些门?每扇门后面是什么能力?给通道分级是收口的前提。按"攻击者拿到这扇门后能做什么"来分级,实践中三档够用:
| 等级 | 判定标准 | 典型通道 | 处置要求 |
|---|---|---|---|
| 一级 无害 | 只读展示类,无副作用 | 取应用版本号、读界面配置 | 常规评审 |
| 二级 受限写 | 影响应用自身数据 | 保存设置、追加笔记 | 参数校验 + 范围限定 |
| 三级 高危 | 触达文件系统、网络、命令 | 任意路径读写、调用外部工具、执行脚本 | 逐条论证必要性,能删则删 |
三级的通道是审计的主战场。逐条过的时候问三个问题:这个通道的业务必要性是什么?能否降级成受限引用(4.3 节的 ID 化思路)?失败时的损害半径有多大?实践中最常见的三类该死通道:任意路径读写(应改为应用数据目录内操作)、通用求值与脚本执行(调试遗留,直接删)、转发型通道(4.1 节说过的"通用转发器",等于把白名单整个撕开)。
// 一次典型的通道降级改造 // 改造前:任意路径读——三级 ipcMain.handle('file:read', (_e, p) => fs.readFile(p, 'utf8')); // 改造后:限定在应用数据目录内的受限读——二级 const DATA_DIR = app.getPath('userData'); ipcMain.handle('file:read', async (_e, name) => { const target = path.join(DATA_DIR, String(name)); if (!path.resolve(target).startsWith(path.resolve(DATA_DIR))) { throw new Error('路径越界'); // 防 ../ 穿越 } return fs.readFile(target, 'utf8'); });
注意改造里那段"前缀校验"——路径拼接类接口的专用补丁,防止用相对路径技巧逃出限定目录。这类细节没有 API 替你把守,只能靠评审时多问一句"这个字符串能被构造成什么"。
2.5 节讲过沙箱的原理与"少关为妙",这里补遗留项目的强化路线图,分四步走:第一步盘点,全库搜索 preload 与渲染层里对 Node 模块的引用,列清单;第二步迁移,把文件、压缩、加密类逻辑整体搬进主进程,包装成 handle 处理器;第三步收口 preload,全部改写为 contextBridge 白名单(2.4 节的模式);第四步开启沙箱并全量回归。四步每步独立可验证,切忌"一口气全开"式改造——沙箱一开、报错一片、然后匆匆关掉回到原点,是这条路上最常见的失败剧本。
Electron 应用的依赖树深得吓人:前端框架、UI 库、构建插件、Electron 生态工具,传递依赖动辄上千包。供应链攻击(某个上游包被投毒)不是理论风险,JavaScript 生态里真实发生过多次。防御的三件日常武器:
# 武器一:本地审计,扫描已知漏洞 $ npm audit found 3 vulnerabilities (1 moderate, 2 high) # 武器二:锁文件纪律——锁文件进版本库,任何更新走评审 # 锁文件记录每个依赖的精确版本与完整性校验值, # 神秘的版本漂移在这里无所遁形 # 武器三:升级 Electron 走安全公告核对 # 应用自带浏览器内核,Chromium 的漏洞公告对同样适用, # 停更的应用等于一台不打补丁的浏览器
三件武器之外还有一条软纪律:新增依赖要有"入职审查"——维护活跃度、下载量、传递依赖规模、是否被社区广泛使用。一个只为了一个小函数引入的冷门包,是供应链上最脆弱的一环。
背景:某天早间,社区传出消息:一个被广泛使用的工具函数库的新版本被植入了窃取环境变量的代码,投毒版本发布数小时后包管理源下架。团队的锁文件里恰好有这个包。
操作:应急流程四步。确认——查锁文件锁定的是哪个版本(幸运:旧版本,未中招);排查——在 CI 里加扫描步骤,确认没有任何构建环境拉过投毒版本;加固——把该依赖锁定到已知安全版本并加监控;复盘——由此推动"新依赖入职审查"与"锁文件变更评审"成为硬流程。
结果:本次有惊无险,但流程从此不同——两周后另一个依赖爆出类似事件时,团队用十五分钟完成了确认与排查,当天完成升级。
解读:供应链安全的胜负手在平时:锁文件纪律让你知道自己用的是什么,入职审查让新风险进不来,定期审计让存量风险看得见。变式:对安全等级要求更高的团队,可以引入私有镜像源加代理缓存,所有包先过自己的源再进工程,把"实时拉取"变成"受控放行"。
把本章四节收拢成一张可执行的表,每次发版前过一遍:
[ ] 基线四开关:nodeIntegration 关 / contextIsolation 开 / sandbox 开 / webSecurity 开 [ ] 远程内容窗口:will-navigate 管制 + 开窗改道系统浏览器 [ ] CSP:生产策略无 unsafe-inline / 无 unsafe-eval / 来源白名单最小化 [ ] 注入面:innerHTML 族 API 不接用户数据,命令调用全部参数化 [ ] 通道分级:三级通道逐条论证,路径类接口有越界校验 [ ] 依赖:audit 清零或豁免有记录,锁文件无未评审变更 [ ] 版本:Electron 非 EOS 版本,安全公告已核对
安全工程收官。主线的下一站是体感篇:第五章直面用户抱怨最多的内存与启动问题,让窗口身轻如燕。