跳转到主要内容

Electron Fuses

打包时间功能开关

什么是 Fuses?

从安全角度来看,禁用某些未使用的 Electron 功能是有意义的,这些功能虽然强大,但可能会降低应用程序的安全性。例如,任何不使用 ELECTRON_RUN_AS_NODE 环境变量的应用程序都希望禁用此功能,以防止一小部分“利用现有工具”攻击。

我们也不希望 Electron 用户为了实现这个目标而进行分支开发,因为从源代码构建和维护分支是一项巨大的技术挑战,并且需要花费大量的时间和金钱。

Fuses 是解决这个问题的方案。从高层来看,它们是 Electron 二进制文件中的“魔术位”,可以在打包 Electron 应用程序时翻转,以启用或禁用某些功能/限制。

由于它们在打包时被翻转,在您对应用程序进行代码签名之前,操作系统将负责确保这些位不会通过操作系统级别的代码签名验证(例如,macOS 上的 Gatekeeper 或 Windows 上的 AppLocker)被翻转回去。

当前 Fuses

runAsNode

默认值: 已启用

@electron/fuses: FuseV1Options.RunAsNode

runAsNode Fuse 切换是否尊重 ELECTRON_RUN_AS_NODE 环境变量。如果禁用此 Fuse,则主进程中的 child_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 存档中读取文件的速度。大多数应用程序可以安全地启用此 Fuse。

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

onlyLoadAppFromAsar

默认值: 已禁用

@electron/fuses: FuseV1Options.OnlyLoadAppFromAsar

onlyLoadAppFromAsar Fuse 更改 Electron 用于定位应用程序代码的搜索系统。默认情况下,Electron 将按以下顺序搜索此代码

  1. app.asar
  2. app
  3. default_app.asar

当此 Fuse 启用时,Electron 将搜索 app.asar。结合 embeddedAsarIntegrityValidation Fuse 时,此 Fuse 确保无法加载未验证的代码。

loadBrowserProcessSpecificV8Snapshot

默认值: 已禁用

@electron/fuses: FuseV1Options.LoadBrowserProcessSpecificV8Snapshot

V8 快照可用于提高应用程序启动性能。V8 允许您获取已初始化堆的快照,然后将其加载回来,以避免初始化堆的成本。

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

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

grantFileProtocolExtraPrivileges

默认值: 已启用

@electron/fuses: FuseV1Options.GrantFileProtocolExtraPrivileges

grantFileProtocolExtraPrivileges Fuse 更改从 file:// 协议加载的页面是否获得超出传统 Web 浏览器所能获得的权限。此行为是 Electron 应用程序在 Electron 的原始版本中的核心,但不再需要,因为应用程序现在应该 从自定义协议提供本地文件

如果您没有从 file:// 提供页面,则应禁用此 Fuse。

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

  • file:// 协议页面可以使用 fetch 加载其他 file:// 资源
  • file:// 协议页面可以使用 Service Worker
  • file:// 协议页面对也运行在 file:// 协议上的子框架具有通用访问权限,无论沙盒设置如何

如何翻转 Fuses?

简单的方法

@electron/fuses 是一个 JavaScript 工具,旨在简化翻转这些 Fuse 的过程。请查看该模块的 README 以获取有关用法和潜在错误情况的更多详细信息。

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 验证已翻转的 Fuse 或检查任意 Electron 应用程序的 Fuse 状态。

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

如果您使用 Electron Forge 来分发您的应用程序,可以使用 @electron-forge/plugin-fuses(所有模板均预装)来翻转 Fuse。

困难的方法

信息

术语表

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

手动翻转 Fuse 需要编辑 Electron 二进制文件并修改 Fuse Wire,使其成为表示所需 Fuse 状态的字节序列。

在 Electron 二进制文件的某个位置,您将看到如下字节序列

| ...binary | sentinel_bytes | fuse_version | fuse_wire_length | fuse_wire | ...binary |
  • sentinel_bytes 始终是这个确切的字符串:dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX
  • fuse_version 是一个单字节,其无符号整数值表示 Fuse Schema 的版本
  • fuse_wire_length 是一个单字节,其无符号整数值表示以下 Fuse Wire 中 Fuse 的数量
  • fuse_wire 是一个 N 个字节的序列,每个字节代表一个 Fuse 及其状态。
    • "0" (0x30) 表示 Fuse 已禁用
    • "1" (0x31) 表示 Fuse 已启用
    • "r" (0x72) 表示 Fuse 已删除,将字节更改为 1 或 0 将不会产生任何影响。

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

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