跳转到主要内容

Electron Fuses

打包时功能开关

什么是 Fuses?

对于一部分 Electron 功能,在整个应用程序中禁用某些功能是合理的。例如,99% 的应用程序都不使用 ELECTRON_RUN_AS_NODE,这些应用程序希望能够提供一个无法使用该功能的二进制文件。我们也不希望 Electron 的消费者从源代码构建 Electron,因为这是一个巨大的技术挑战,并且耗费大量的时间和金钱。

Fuses 就是解决这个问题的方案。从宏观上讲,它们是 Electron 二进制文件中的“魔法位”,在打包你的 Electron 应用时可以进行切换,以启用/禁用特定的功能/限制。由于它们在代码签名之前打包时进行切换,因此操作系统负责确保这些位不会通过操作系统级别的代码签名验证(Gatekeeper / App Locker)被改回。

当前 Fuses

runAsNode

默认:启用

@electron/fuses: FuseV1Options.RunAsNode

runAsNode fuse 切换是否尊重 ELECTRON_RUN_AS_NODE 环境变量。请注意,如果此 fuse 被禁用,则主进程中的 process.fork 将无法按预期工作,因为它依赖此环境变量才能正常运行。相反,我们建议使用 Utility Processes,它适用于许多需要独立 Node.js 进程的用例(例如 SQLite 服务器进程或类似场景)。

cookieEncryption

默认:禁用

@electron/fuses: FuseV1Options.EnableCookieEncryption

cookieEncryption fuse 切换是否使用操作系统级别的加密密钥对磁盘上的 cookie 存储进行加密。默认情况下,Chromium 用于存储 cookie 的 SQLite 数据库以明文形式存储值。如果你希望确保你的应用 cookie 以与 Chrome 相同的方式加密,则应启用此 fuse。请注意,这是一个单向迁移,如果你启用此 fuse,现有的未加密 cookie 将在写入时加密,但如果你再次禁用该 fuse,你的 cookie 存储将有效地损坏且无法使用。大多数应用程序可以安全地启用此 fuse。

nodeOptions

默认:启用

@electron/fuses: FuseV1Options.EnableNodeOptionsEnvironmentVariable

nodeOptions fuse 切换是否尊重 NODE_OPTIONSNODE_EXTRA_CA_CERTS 环境变量。NODE_OPTIONS 环境变量可用于向 Node.js 运行时传递各种自定义选项,通常不用于生产环境中的应用程序。大多数应用程序可以安全地禁用此 fuse。

nodeCliInspect

默认:启用

@electron/fuses: FuseV1Options.EnableNodeCliInspectArguments

nodeCliInspect fuse 切换是否尊重 --inspect--inspect-brk 等标志。禁用时,它还确保 SIGUSR1 信号不会初始化主进程检查器。大多数应用程序可以安全地禁用此 fuse。

embeddedAsarIntegrityValidation

默认:禁用

@electron/fuses: FuseV1Options.EnableEmbeddedAsarIntegrityValidation

embeddedAsarIntegrityValidation fuse 在 macOS 和 Windows 上切换一项实验性功能,该功能在加载 app.asar 文件时验证其内容。此功能旨在对性能影响最小,但可能会稍微减慢从 app.asar 归档文件内部进行读取的速度。

有关如何使用 asar 完整性验证的更多信息,请阅读 Asar Integrity 文档。

onlyLoadAppFromAsar

默认:禁用

@electron/fuses: FuseV1Options.OnlyLoadAppFromAsar

onlyLoadAppFromAsar fuse 更改了 Electron 用于定位应用程序代码的搜索系统。默认情况下,Electron 将按以下顺序搜索 app.asar -> app -> default_app.asar。启用此 fuse 后,搜索顺序变为单个条目 app.asar,从而确保当与 embeddedAsarIntegrityValidation fuse 结合使用时,无法加载未经验证的代码。

loadBrowserProcessSpecificV8Snapshot

默认:禁用

@electron/fuses: FuseV1Options.LoadBrowserProcessSpecificV8Snapshot

loadBrowserProcessSpecificV8Snapshot fuse 更改了浏览器进程使用的 V8 快照文件。默认情况下,Electron 的所有进程都将使用相同的 V8 快照文件。启用此 fuse 后,浏览器进程将使用名为 browser_v8_context_snapshot.bin 的文件作为其 V8 快照。其他进程将使用它们通常使用的 V8 快照文件。

V8 快照可用于提高应用程序启动性能。V8 允许你拍摄已初始化堆的快照,然后将其重新加载,以避免初始化堆的开销。

为渲染器进程和主进程使用单独的快照可以提高安全性,特别是为了确保渲染器不使用启用了 nodeIntegration 的快照。有关详细信息,请参阅 #35170

grantFileProtocolExtraPrivileges

默认:启用

@electron/fuses: FuseV1Options.GrantFileProtocolExtraPrivileges

grantFileProtocolExtraPrivileges fuse 更改了从 file:// 协议加载的页面是否获得比传统 Web 浏览器中获得的权限更多的权限。此行为是早期版本 Electron 中 Electron 应用程序的核心,但现在不再需要,因为应用程序应 使用自定义协议提供本地文件 而不是 file://。如果你不从 file:// 提供页面,则应禁用此 fuse。

此 fuse 为 file:// 协议授予的额外权限记录如下:

  • file:// 协议页面可以使用 fetch 来加载其他 file:// 协议下的资源
  • file:// 协议页面可以使用 service workers
  • file:// 协议页面可以对同样运行在 file:// 协议下的子框架拥有通用访问权限,而无需考虑沙箱设置

如何切换 Fuses?

简单方法

我们创建了一个方便的模块 @electron/fuses,可以轻松切换这些 fuses。有关使用方法和潜在错误场景的更多详细信息,请查看该模块的 README。

const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses')

flipFuses(
// Path to electron
require('electron'),
// Fuses to flip
{
version: FuseVersion.V1,
[FuseV1Options.RunAsNode]: false
}
)

您可以使用 fuses CLI 验证 fuses 是否已切换,或检查任意 Electron 应用程序的 fuse 状态。

npx @electron/fuses read --app /Applications/Foo.app

困难方法

快速词汇表

  • Fuse Wire:Electron 二进制文件中用于控制 fuses 的字节序列
  • Sentinel:可用于定位 fuse wire 的静态已知字节序列
  • Fuse Schema:fuse wire 的格式/允许值

手动切换 fuses 需要编辑 Electron 二进制文件并修改 fuse wire,使其成为表示你想要的 fuses 状态的字节序列。

Electron 二进制文件中的某个位置将有一个字节序列,看起来像这样:

| ...binary | sentinel_bytes | fuse_version | fuse_wire_length | fuse_wire | ...binary |
  • sentinel_bytes 始终是精确字符串 dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX
  • fuse_version 是一个单字节,其无符号整数值表示 fuse schema 的版本
  • fuse_wire_length 是一个单字节,其无符号整数值表示后面 fuse wire 中的 fuses 数量
  • fuse_wire 是一个 N 字节的序列,每个字节代表一个 fuse 及其状态。
    • "0" (0x30) 表示 fuse 已禁用
    • "1" (0x31) 表示 fuse 已启用
    • "r" (0x72) 表示 fuse 已移除,将该字节更改为 1 或 0 都将无效。

要切换 fuse,你需要找到它在 fuse wire 中的位置,并根据你想要的状态将其更改为“0”或“1”。

你可以在 这里 查看当前 schema。