Electron Fuse
パッケージ時機能切り替え
Fuse とはなんでしょうか?
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.
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.
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.
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
デフォルト: 有効
@electron/fuses: FuseV1Options.RunAsNode
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
デフォルト: 無効
@electron/fuses: FuseV1Options.EnableCookieEncryption
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. ほとんどのアプリは安全にこの Fuse を有効化できます。
nodeOptions
デフォルト: 有効
@electron/fuses: FuseV1Options.EnableNodeOptionsEnvironmentVariable
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. ほとんどのアプリは安全にこの Fuse を無効化できます。
nodeCliInspect
デフォルト: 有効
@electron/fuses: FuseV1Options.EnableNodeCliInspectArguments
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. ほとんどのアプリは安全にこの Fuse を無効化できます。
embeddedAsarIntegrityValidation
デフォルト: 無効
@electron/fuses: FuseV1Options.EnableEmbeddedAsarIntegrityValidation
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. ほとんどのアプリは安全にこの Fuse を有効化できます。
For more information on how to use ASAR integrity validation, please read the Asar Integrity documentation.
onlyLoadAppFromAsar
デフォルト: 無効
@electron/fuses: FuseV1Options.OnlyLoadAppFromAsar
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
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
デフォルト: 無効
@electron/fuses: FuseV1Options.LoadBrowserProcessSpecificV8Snapshot
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.
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.
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
デフォルト: 有効
@electron/fuses: FuseV1Options.GrantFileProtocolExtraPrivileges
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.
If you aren't serving pages from file://, you should disable this fuse.
この Fuse によって file:// プロトコルに付与される追加の権限は、大雑把にまとめると以下のようになります。
file://プロトコルのページがfetchを使用して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?
簡単な方法
@electron/fuses is a JavaScript utility designed to make flipping these fuses easy. 使用方法や潜在的なエラーケースといった詳細は、このモジュールの README を確認してください。
const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses')
flipFuses(
// electron へのパス
require('electron'),
// 反転する Fuse
{
version: FuseVersion.V1,
[FuseV1Options.RunAsNode]: false
}
)
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] 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.
難しい方法
[!IMPORTANT] Glossary:
- Fuse Wire: Fuse の制御に使用する Electron バイナリ内のバイト列
- Sentinel: Fuse Wire の位置特定に使用できる静的な既知のバイト列
- Fuse Schema: The format/allowed values for the fuse wire
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.
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_bytesis always this exact string:dL7pKGdnNz796PbbjQWNKmHXBZaB9tsXfuse_versionは単一バイトで、その符号無し整数の値が Fuse Schema のバージョンを表します。fuse_wire_lengthは単一バイトで、その符号無し整数の値は後続の Fuse Wire にある Fuse の数を表します。fuse_wireは N バイトのシーケンスで、各バイトは 1 つの Fuse とその状態を表します。- "0" (0x30) は無効な Fuse を表します
- "1" (0x31) は有効な Fuse を表します
- "r" (0x72) は削除された Fuse を表し、このバイトを 1 や 0 に変更しても効果はありません。
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.
現在のスキーマは こちら で閲覧できます。