Electron Fuses
打包时间功能切换
¥Package time feature toggles
fuses 是什么?
¥What are fuses?
从安全角度来看,禁用某些功能强大但可能降低应用安全性的未使用 Electron 功能是合理的。例如,任何不使用 ELECTRON_RUN_AS_NODE 环境变量的应用都应该禁用此功能,以防止部分 "自给自足" 攻击。
¥From a security perspective, it makes sense to disable certain unused Electron features
that are powerful but may make your app's security posture weaker. For example, any app that doesn't
use the ELECTRON_RUN_AS_NODE environment variable would want to disable the feature to prevent a
subset of "living off the land" attacks.
我们也不希望 Electron 用户为了实现此目标而创建分支,因为从源代码构建和维护分支是一项巨大的技术挑战,并且会耗费大量时间和金钱。
¥We also don't want Electron consumers forking to achieve this goal, as building from source and maintaining a fork is a massive technical challenge and costs a lot of time and money.
熔丝是解决此问题的方法。从宏观层面来说,它们是 Electron 二进制文件中的 "魔法位",可以在打包 Electron 应用时进行翻转,以启用或禁用某些功能/限制。
¥Fuses are the solution to this problem. At a high level, they are "magic bits" in the Electron binary that can be flipped when packaging your Electron app to enable or disable certain features/restrictions.
由于它们在应用代码签名之前会在打包时进行翻转,因此操作系统将负责通过操作系统级别的代码签名验证来确保这些位不会被翻转回去(例如,macOS 上的 Gatekeeper 或 Windows 上的 AppLocker)。
¥Because they are flipped at package time before you code sign your app, the OS becomes responsible for ensuring those bits aren't flipped back via OS-level code signing validation (e.g. Gatekeeper on macOS or AppLocker on Windows).
当前熔丝位
¥Current fuses
runAsNode
默认:已启用
¥Default: Enabled
@electron/fuses:FuseV1Options.RunAsNode
runAsNode 保险丝用于切换是否遵循 ELECTRON_RUN_AS_NODE 环境变量。禁用此熔丝后,主进程中的 child_process.fork 将无法正常工作,因为它依赖于此环境变量才能运行。我们建议你使用 实用程序进程,它适用于许多需要独立 Node.js 进程的用例(例如 SQLite 服务器进程)。
¥The runAsNode fuse toggles whether the ELECTRON_RUN_AS_NODE
environment variable is respected or not. With this fuse disabled, child_process.fork in the main process will not function
as expected, as it depends on this environment variable to function. Instead, we recommend that you
use Utility Processes, which work for many use cases where you need a
standalone Node.js process (e.g. a SQLite server process).
cookieEncryption
默认:已禁用
¥Default: Disabled
@electron/fuses:FuseV1Options.EnableCookieEncryption
cookieEncryption 熔丝用于切换是否使用操作系统级别的加密密钥对磁盘上的 cookie 存储进行加密。默认情况下,Chromium 用于存储 cookie 的 SQLite 数据库以明文形式存储这些值。如果你希望确保你的应用 Cookie 以与 Chrome 相同的方式加密,则应启用此熔丝。请注意,这是一个单向转换 - 如果你启用此熔丝,现有的未加密 Cookie 将在写入时加密;但之后禁用此熔丝将导致你的 Cookie 存储损坏且无法使用。大多数应用都可以安全地启用此保险丝。
¥The cookieEncryption fuse toggles whether the cookie store on disk is encrypted using OS level
cryptography keys. By default, the SQLite database that Chromium uses to store cookies stores the
values in plaintext. If you wish to ensure your app's cookies are encrypted in the same way Chrome
does, then you should enable this fuse. Please note it is a one-way transition—if you enable this
fuse, existing unencrypted cookies will be encrypted-on-write, but subsequently disabling the fuse
later will make your cookie store corrupt and useless. Most apps can safely enable this fuse.
nodeOptions
默认:已启用
¥Default: Enabled
@electron/fuses:FuseV1Options.EnableNodeOptionsEnvironmentVariable
nodeOptions 熔丝位会切换是否应用 NODE_OPTIONS 和 NODE_EXTRA_CA_CERTS 环境变量。NODE_OPTIONS 环境变量可用于将各种自定义选项传递给 Node.js 运行时,并且通常不被生产中的应用使用。大多数应用可以安全地禁用此保险丝。
¥The nodeOptions fuse toggles whether the NODE_OPTIONS
and NODE_EXTRA_CA_CERTS
environment variables are respected. The NODE_OPTIONS environment variable can be used to pass all
kinds of custom options to the Node.js runtime and isn't typically used by apps in production.
Most apps can safely disable this fuse.
nodeCliInspect
默认:已启用
¥Default: Enabled
@electron/fuses:FuseV1Options.EnableNodeCliInspectArguments
nodeCliInspect 熔丝用于切换是否应用 --inspect、--inspect-brk 等标志。禁用后,它还可以确保 SIGUSR1 信号不会初始化主进程检查器。大多数应用可以安全地禁用此保险丝。
¥The nodeCliInspect fuse toggles whether the --inspect, --inspect-brk, etc. flags are respected
or not. When disabled, it also ensures that SIGUSR1 signal does not initialize the main process
inspector. Most apps can safely disable this fuse.
embeddedAsarIntegrityValidation
默认:已禁用
¥Default: Disabled
@electron/fuses:FuseV1Options.EnableEmbeddedAsarIntegrityValidation
embeddedAsarIntegrityValidation 熔丝位会切换 macOS 和 Windows 上的一项功能,该功能会在加载 app.asar 文件时验证其内容。此功能旨在对性能影响最小,但可能会稍微减慢从 app.asar 存档内部读取文件的速度。大多数应用都可以安全地启用此保险丝。
¥The embeddedAsarIntegrityValidation fuse toggles a feature on macOS and Windows that validates the
content of the app.asar file when it is loaded. This feature is designed to have a minimal
performance impact but may marginally slow down file reads from inside the app.asar archive.
Most apps can safely enable this fuse.
有关如何使用 ASAR 完整性验证的更多信息,请阅读 阿萨尔诚信 文档。
¥For more information on how to use ASAR integrity validation, please read the Asar Integrity documentation.
onlyLoadAppFromAsar
默认:已禁用
¥Default: Disabled
@electron/fuses:FuseV1Options.OnlyLoadAppFromAsar
onlyLoadAppFromAsar 熔丝位会更改 Electron 用于查找应用代码的搜索系统。默认情况下,Electron 将按以下顺序搜索此代码:
¥The onlyLoadAppFromAsar fuse changes the search system that Electron uses to locate your app code.
By default, Electron will search for this code in the following order:
app.asarappdefault_app.asar
启用此熔丝后,Electron 将仅搜索 app.asar。与 embeddedAsarIntegrityValidation 熔丝结合使用时,此熔丝可确保无法加载未经验证的代码。
¥When this fuse is enabled, Electron will only search for app.asar. When combined with the embeddedAsarIntegrityValidation fuse, this fuse ensures that
it is impossible to load non-validated code.
loadBrowserProcessSpecificV8Snapshot
默认:已禁用
¥Default: Disabled
@electron/fuses:FuseV1Options.LoadBrowserProcessSpecificV8Snapshot
V8 快照可用于提高应用启动性能。V8 允许你对已初始化的堆进行快照,然后将其重新加载,以避免初始化堆的成本。
¥V8 snapshots can be useful to improve app startup performance. V8 lets you take snapshots of initialized heaps and then load them back in to avoid the cost of initializing the heap.
loadBrowserProcessSpecificV8Snapshot 熔丝位会更改浏览器进程使用的 V8 快照文件。默认情况下,Electron 的所有进程都将使用同一个 V8 快照文件。启用此熔丝后,主进程将使用名为 browser_v8_context_snapshot.bin 的文件作为其 V8 快照。其他进程将像往常一样使用 V8 快照文件。
¥The loadBrowserProcessSpecificV8Snapshot fuse changes which V8 snapshot file is used for the browser
process. By default, Electron's processes will all use the same V8 snapshot file. When this fuse is
enabled, the main process uses the file called browser_v8_context_snapshot.bin for its V8 snapshot.
Other processes will use the V8 snapshot file that they normally do.
对渲染器进程和主进程使用单独的快照可以提高安全性,尤其是确保渲染器不使用启用 nodeIntegration 的快照。详情请参见 electron/electron#35170。
¥Using separate snapshots for renderer processes and the main process can improve security, especially
to make sure that the renderer doesn't use a snapshot with nodeIntegration enabled.
See electron/electron#35170 for details.
grantFileProtocolExtraPrivileges
默认:已启用
¥Default: Enabled
@electron/fuses:FuseV1Options.GrantFileProtocolExtraPrivileges
grantFileProtocolExtraPrivileges 熔丝位会更改通过 file:// 协议加载的页面是否拥有超出传统 Web 浏览器权限的权限。此行为是 Electron 早期版本中 Electron 应用的核心功能,但现在应用应该使用 从自定义协议提供本地文件,因此不再需要此功能。
¥The grantFileProtocolExtraPrivileges fuse changes whether pages loaded from the file:// protocol
are given privileges beyond what they would receive in a traditional web browser. This behavior was
core to Electron apps in original versions of Electron, but is no longer required as apps should be
serving local files from custom protocols now instead.
如果你未使用 file:// 提供页面,则应禁用此熔丝。
¥If you aren't serving pages from file://, you should disable this fuse.
下面不完整地记录了该熔丝授予 file:// 协议的额外权限:
¥The extra privileges granted to the file:// protocol by this fuse are incompletely documented below:
-
file://协议页面可以使用fetch通过file://加载其他资源¥
file://protocol pages can usefetchto load other assets overfile:// -
file://协议页面可以使用 Service Worker¥
file://protocol pages can use service workers -
无论沙箱设置如何,
file://协议页面都向同样在file://协议上运行的子框架授予通用访问权限¥
file://protocol pages have universal access granted to child frames also running onfile://protocols regardless of sandbox settings
如何切换熔丝位?
¥How do I flip fuses?
最简单的方法
¥The easy way
@electron/fuses 是一个 JavaScript 工具,旨在简化熔丝位的切换操作。查看该模块的自述文件,了解有关使用和潜在错误情况的更多详细信息。
¥@electron/fuses is a JavaScript utility designed to make flipping these fuses easy. Check out the README of that module for more details on usage and potential error cases.
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 应用的熔丝位状态。
¥You can validate the fuses that have been flipped or check the fuse status of an arbitrary Electron
app using the @electron/fuses CLI.
npx @electron/fuses read --app /Applications/Foo.app
[!NOTE] 如果你使用 Electron Forge 分发你的应用,你可以使用
@electron-forge/plugin-fuses来切换熔丝位,所有模板都预装了@electron-forge/plugin-fuses。¥[!NOTE] If you are using Electron Forge to distribute your application, you can flip fuses using
@electron-forge/plugin-fuses, which comes pre-installed with all templates.
艰难的路
¥The hard way
[!重要] 术语表:
¥[!IMPORTANT] Glossary:
Fuse Wire:Electron 二进制文件中用于控制熔丝的字节序列
¥Fuse Wire: A sequence of bytes in the Electron binary used to control the fuses
哨兵:可用于定位保险丝的静态已知字节序列
¥Sentinel: A static known sequence of bytes you can use to locate the fuse wire
Fuse Schema:熔丝的格式/允许值
¥Fuse Schema: The format/allowed values for the fuse wire
手动翻转保险丝需要编辑 Electron 二进制文件并将保险丝修改为代表所需保险丝状态的字节序列。
¥Manually flipping fuses requires editing the Electron binary and modifying the fuse wire to be the sequence of bytes that represent the state of the fuses you want.
在 Electron 二进制文件的某个位置,会有一段类似这样的字节序列:
¥Somewhere in the Electron binary, there will be a sequence of bytes that look like this:
| ...binary | sentinel_bytes | fuse_version | fuse_wire_length | fuse_wire | ...binary |
-
sentinel_bytes始终返回以下字符串:dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX¥
sentinel_bytesis always this exact string:dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX -
fuse_version是一个单字节,其无符号整数值表示熔丝模式的版本¥
fuse_versionis a single byte whose unsigned integer value represents the version of the fuse schema -
fuse_wire_length是一个单字节,其无符号整数值代表后面的保险丝中的保险丝数量¥
fuse_wire_lengthis a single byte whose unsigned integer value represents the number of fuses in the following fuse wire -
fuse_wire是 N 个字节的序列,每个字节代表单个熔丝及其状态。¥
fuse_wireis a sequence of N bytes, each byte represents a single fuse and its state.-
"0" (0x30) 表示保险丝已禁用
¥"0" (0x30) indicates the fuse is disabled
-
"1"(0x31)表示熔丝已使能
¥"1" (0x31) indicates the fuse is enabled
-
"r" (0x72) 表示熔丝已被移除,将字节更改为 1 或 0 将不起作用。
¥"r" (0x72) indicates the fuse has been removed and changing the byte to either 1 or 0 will have no effect.
-
要熔断保险丝,请找到它在保险丝线路中的位置,并根据所需状态将其更改为 "0" 或 "1"。
¥To flip a fuse, you find its position in the fuse wire and change it to "0" or "1" depending on the state you'd like.
你可以查看当前的架构 此处。
¥You can view the current schema here.