Electron 保险丝¶
打包时的功能开关
什么是保险丝?¶
从安全角度来看,禁用某些未使用的 Electron 功能是合理的,这些功能虽然强大,但可能会削弱应用的安全态势。例如,任何不使用 ELECTRON_RUN_AS_NODE 环境变量的应用都应禁用该功能,以防止一部分“就地取材”攻击。
我们也不希望 Electron 用户通过创建分支(fork)来实现这一目标,因为从源代码构建并维护一个分支是一项巨大的技术挑战,需要耗费大量时间和金钱。
保险丝是解决此问题的方案。从高层次来看,它们是 Electron 二进制文件中的“魔法位”,可以在打包 Electron 应用时翻转,以启用或禁用某些功能/限制。
由于这些位在你代码签名应用之前于打包时翻转,操作系统将负责确保这些位不会通过操作系统级别的代码签名验证被翻转回去(例如 macOS 上的 Gatekeeper 或 Windows 上的 AppLocker)。
当前保险丝¶
runAsNode¶
默认: 已启用
@electron/fuses: FuseV1Options.RunAsNode
runAsNode 保险丝用于切换 ELECTRON_RUN_AS_NODE 环境变量是否生效。禁用此保险丝后,child_process.fork 会抛出异常,因为它依赖此环境变量才能工作。相反,我们建议你使用 Utility Processes,它适用于许多需要独立 Node.js 进程的使用场景(例如 SQLite 服务器进程)。
cookieEncryption¶
默认: 已禁用
@electron/fuses: FuseV1Options.EnableCookieEncryption
cookieEncryption 保险丝用于切换磁盘上的 cookie 存储是否使用操作系统级别的加密密钥进行加密。默认情况下,Chromium 用于存储 cookie 的 SQLite 数据库会以明文存储这些值。如果你希望确保应用的 cookie 像 Chromium 一样被加密,则应启用此保险丝。请注意,这是一个单向转换——如果你启用此保险丝,现有未加密的 cookie 将在写入时加密,但随后禁用此保险丝会使你的 cookie 存储损坏且无法使用。大多数应用可以安全地启用此保险丝。
[!IMPORTANT] 在 macOS 上,此保险丝依赖于与
safeStorage相同的操作系统级别 Keychain 访问权限,因此你的应用应 代码签名 才能正确工作。
nodeOptions¶
默认: 已启用
@electron/fuses: FuseV1Options.EnableNodeOptionsEnvironmentVariable
nodeOptions 保险丝用于切换 NODE_OPTIONS 和 NODE_EXTRA_CA_CERTS 环境变量是否生效。NODE_OPTIONS 环境变量可用于向 Node.js 运行时传递各种自定义选项,通常不被生产环境中的应用使用。大多数应用可以安全地禁用此保险丝。
nodeCliInspect¶
默认: 已启用
@electron/fuses: FuseV1Options.EnableNodeCliInspectArguments
nodeCliInspect 保险丝用于切换 --inspect、--inspect-brk 等标志是否生效。禁用时,它还确保 SIGUSR1 信号不会初始化主进程检查器。大多数应用可以安全地禁用此保险丝。
embeddedAsarIntegrityValidation¶
默认: 已禁用
@electron/fuses: FuseV1Options.EnableEmbeddedAsarIntegrityValidation
embeddedAsarIntegrityValidation 保险丝用于切换 macOS 和 Windows 上的一项功能,该功能在加载 app.asar 文件时验证其内容。此功能旨在对性能影响最小,但可能会轻微降低从 app.asar 归档内部读取文件的速度。大多数应用可以安全地启用此保险丝。
有关如何使用 ASAR 完整性验证的更多信息,请阅读 ASAR 完整性 文档。
onlyLoadAppFromAsar¶
默认: 已禁用
@electron/fuses: FuseV1Options.OnlyLoadAppFromAsar
onlyLoadAppFromAsar 保险丝会更改 Electron 用于定位应用代码的搜索系统。默认情况下,Electron 会按以下顺序搜索此代码:
app.asarappdefault_app.asar
启用此保险丝后,Electron 将 仅 搜索 app.asar。与 embeddedAsarIntegrityValidation 保险丝结合使用时,此保险丝可确保不可能加载未经验证的代码。
loadBrowserProcessSpecificV8Snapshot¶
默认: 已禁用
@electron/fuses: FuseV1Options.LoadBrowserProcessSpecificV8Snapshot
V8 快照可用于改善应用启动性能。V8 允许你对已初始化的堆进行快照,然后重新加载它们,以避免初始化堆的开销。
loadBrowserProcessSpecificV8Snapshot 保险丝会更改浏览器进程使用的 V8 快照文件。默认情况下,Electron 的所有进程都会使用同一个 V8 快照文件。启用此保险丝后,主进程会使用名为 browser_v8_context_snapshot.bin 的文件作为其 V8 快照。其他进程将使用它们通常使用的 V8 快照文件。
为渲染进程和主进程使用不同的快照可以提高安全性,尤其是确保渲染进程不使用启用了 nodeIntegration 的快照。详见 electron/electron#35170。
当主进程运行在自定义 V8 快照上——此保险丝,或用 electron-mksnapshot 生成的 v8_context_snapshot.bin 替换的快照——Electron 会从源代码而不是其嵌入的 Node.js 启动快照中引导主进程的 Node.js 环境,以便自定义快照中的对象可供主进程使用。这会消耗一部分本可由嵌入快照节省的主进程启动时间。
grantFileProtocolExtraPrivileges¶
默认值: 启用
@electron/fuses: FuseV1Options.GrantFileProtocolExtraPrivileges
grantFileProtocolExtraPrivileges 保险丝用于更改从 file:// 协议加载的页面是否获得传统 Web 浏览器中不会获得的额外权限。在 Electron 的早期版本中,这种行为是 Electron 应用的核心,但现在不再需要,因为应用现在应该改为通过自定义协议提供本地文件。
如果你没有从 file:// 提供页面,应该禁用此保险丝。
此保险丝授予 file:// 协议的额外权限未完全记录,如下所示:
file://协议页面可以使用fetch通过file://加载其他资源file://协议页面可以使用 Service Workerfile://协议页面会获得对同样运行在file://协议上的子框架的通用访问权限,无论沙箱设置如何
wasmTrapHandlers¶
默认值: 启用
@electron/fuses: FuseV1Options.WasmTrapHandlers
wasmTrapHandlers 保险丝控制 V8 是否使用信号处理程序来捕获来自 WebAssembly 的越界内存访问。该功能通过在 WebAssembly 内存周围设置大型保护区域,然后安装一个信号处理程序来捕获尝试访问保护区域中内存的操作来实现。该功能仅支持以下 64 位系统:
- Linux, macOS, Windows - x86_64
- Linux, macOS - aarch64
当保险丝被禁用时,V8 将在生成的 WebAssembly 代码中使用显式边界检查以确保内存安全。然而,这种方法有一些缺点
- 编译器会为每个内存引用生成额外的节点,由于这些节点需要额外的处理时间,导致编译时间变长。
- 反过来,这些额外节点会导致生成大量额外代码,使 WebAssembly 模块比理想情况更大。
- 这些额外代码,尤其是每次内存引用之前的比较和分支,会带来显著的运行时开销。
如何切换保险丝?¶
简单方式¶
@electron/fuses 是一个 JavaScript 实用工具,旨在让这些保险丝的切换变得简单。有关用法和潜在错误情况的更多详细信息,请查看该模块的 README。
```js @ts-nocheck const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses')
flipFuses( // Path to electron require('electron'), // Fuses to flip { version: FuseVersion.V1, [FuseV1Options.RunAsNode]: false } )
你可以使用 `@electron/fuses` CLI 验证已切换的保险丝,或检查任意 Electron 应用的保险丝状态。
```bash
npx @electron/fuses read --app /Applications/Foo.app
[!NOTE] 如果你使用 Electron Forge 分发应用程序,可以使用
@electron-forge/plugin-fuses来切换保险丝,该插件已预装在所有模板中。
困难方式¶
[!IMPORTANT] 术语表:
- 保险丝线:Electron 二进制文件中用于控制保险丝的一段字节序列
- 哨兵:一段静态已知的字节序列,可用于定位保险丝线
- 保险丝架构:保险丝线的格式/允许值
手动切换保险丝需要编辑 Electron 二进制文件,并将保险丝线修改为代表你想要设置的保险丝状态的字节序列。
在 Electron 二进制文件的某个位置,会有一段看起来像这样的字节序列:
sentinel_bytes始终是这个精确字符串:dL7pKGdnNz796PbbjQWNKmHXBZaB9tsXfuse_version是单个字节,其无符号整数值表示保险丝架构的版本fuse_wire_length是单个字节,其无符号整数值表示后续保险丝线中的保险丝数量fuse_wire是 N 个字节的序列,每个字节代表单个保险丝及其状态。- "0"(0x30)表示保险丝已禁用
- "1"(0x31)表示保险丝已启用
- "r"(0x72)表示保险丝已被移除,将该字节更改为 1 或 0 都不会产生效果。
要切换保险丝,请找到它在保险丝线中的位置,并根据你想要的状态将其更改为 "0" 或 "1"。
你可以在这里查看当前架构。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 el/electron