メインコンテンツへ飛ぶ

セキュリティ

セキュリティ問題の報告について

Electron の脆弱性を報告する正しい方法については SECURITY.md をご参照ください。

上流の Chromium の脆弱性に対して、Electron は Chromium のリリースと交互に更新されます。 詳しくは、Electron リリースタイムライン のドキュメントをご参照ください。

はじめに

私たちは普段、ウェブ開発者としてブラウザの強力なセキュリティを享受しています。つまり、私たちが書いたコードに起因するリスクは比較的小さいと言えます。 私たちのウェブサイトにはサンドボックスに限られた権限が与えられており、ユーザーは新たに発見されたセキュリティ上の脅威に迅速に対応できる、大規模なエンジニアチームによって構築されたブラウザを享受していると考えています。

Electron で開発する時、Electron はブラウザではないということを意識することが重要です。 使い慣れたウェブ技術を使用して、機能あふれるデスクトップアプリケーションを構築できますが、あなたのコードの方がはるかに大きな力を発揮します。 JavaScript はファイルシステム、ユーザシェルなどにアクセスできます。 これはつまり、質の高いネイティブアプリケーションを作成することができる反面、あなたの書くコードに与えられた権限に応じて固有のセキュリティリスクが増加するということです。

それを念頭に置いて、信頼できないソースからの任意のコンテンツを表示するということは、Electron が扱うことを意図しない重大なセキュリティリスクを引き起こすということに注意してください。 実際、人気のある Electron アプリ (Atom、Slack、Visual Studio Code、等) は、主にローカル (あるいは信頼されており、なおかつ Node integration を使用しないリモート) のコンテンツを取り扱います。もしあなたのアプリケーションがオンライン上のリソースからコードを実行する場合、あなたの責任の下でそのコードが悪意のあるものではないことを確認する必要があります。

一般的ガイドライン

セキュリティはみんなの責任

あなたの Electron アプリケーションのセキュリティは、フレームワーク (ChromiumNode.js)、Electron 自身、NPM の依存関係、あなたのコード のセキュリティの結果であることを覚えておくことが大事です。 そのため、いくつかの重要なベストプラックティスに従う、責任があります。

  • あなたのアプリケーションは最新リリースの Electron フレームワークを使う。 あなたはプロダクトをリリースしたとき、Electron、 Chromium 共有ライブラリ、Node.js を組み込んでリリースしています。 これらのコンポーネントに影響する脆弱性は、あなたのアプリケーションのセキュリティに影響する可能性があります。 Electron を最新バージョンにアップデートすることで、致命的な脆弱性 (例えば nodeIntegration のバイパス) にパッチを当てて、アプリケーションで発現しないようにできます。 詳細については、"現行バージョンの Electron を使う" を参照してください。

  • あなたのアプリの依存関係の評価する。 NPM は 50万もの再利用できるパッケージを提供しています。一方、あなたは信頼するサードパーティのライブラリを選択する責任があります。 あなたが既知の脆弱性の影響を受けるライブラリを利用する場合や、あまりメンテナンスされていないコードに頼る場合、あなたのアプリケーションのセキュリティは低下し危険な状態になります。

  • セキュアコーディングプラクティスの採用。 あなたのアプリケーションの防衛の第一歩はあなたのコードです。 クロスサイトスクリプティング (XSS) のような一般的なウェブの脆弱性は Electron アプリケーションに大きなセキュリティ上の影響を与えるため、安全なソフトウェア開発のベストプラクティスの採用とセキュリティテストの実施を強く推奨します。

信頼できないコンテンツの分離

信用されていないソース (例えばリモートサーバー) からコードを受け取ってローカルで実行するときは、常にセキュリティの問題が存在します。 例として、リモートのウェブサイトがデフォルト BrowserWindow 内に表示されていると考えてください。 もし攻撃者がどうにかして(情報源そのものの攻撃や中間者攻撃によって) 得られる内容を変更した場合、ユーザーのPC上でネイティブコードを実行できることになります。

警告

Node.js integration が有効な環境では、リモートコードの読み込みと実行を行うべきではありません。 代わりに、Node.js コードの実行にはローカルファイル (アプリケーションと一緒にパッケージ化されているもの) だけを使用してください。

Electron のセキュリティ警告

セキュリティに関する警告や推奨事項は、開発者コンソールに出力されます。 バイナリ名が Electron の場合にのみ、開発者が現在コンソールを見ているものとして表示しています。

これらの警告を、 process.env または window オブジェクトにELECTRON_ENABLE_SECURITY_WARNINGS または ELECTRON_DISABLE_SECURITY_WARNINGS を設定することで、強制的に有効または無効にできます。

チェックリスト: セキュリティ推奨事項

あなたはあなたのアプリケーションのセキュリティーを向上させるために、少なくとも次のステップを実施してください。

  1. セキュアなコンテンツのみを読み込む
  2. リモートコンテンツを表示する全てのレンダラーで、Node.js integration を無効にする
  3. すべてのレンダラーでコンテキスト分離を有効化する
  4. プロセスのサンドボックス化を有効にする
  5. リモートのコンテンツを表示するすべてのセッションで ses.setPermissionRequestHandler() を利用する
  6. webSecurity を無効にしない
  7. Content-Security-Policy を定義して、スクリプトの読み込み元を制限する (例: script-src 'self')
  8. allowRunningInsecureContent を有効にしない
  9. 実験的な機能を有効にしない
  10. enableBlinkFeatures を使用しない
  11. <webview>: allowpopups を使用しない
  12. <webview>: オプションとパラメータを検証する
  13. ナビゲーションを無効化か制限
  14. 新規ウインドウの作成を無効化か制限
  15. 信用されないコンテンツで shell.openExternal を使用しない
  16. 現行バージョンの Electron を使う
  17. すべての IPC メッセージの sender を確認する
  18. file:// プロトコルの使用を避け、カスタムプロトコルを使うようにする
  19. どの Fuse を変更できるか確認する

設定ミスやセキュアでないパターンを自動的に検出するには、Electronegativity が利用できます。 Electron を使用したアプリケーション開発時の潜在的な脆弱性やバグの埋め込みについてのより詳しい情報は、開発者と監査役向けのガイド をご参照ください。

1. セキュアなコンテンツのみを読み込む

アプリケーションに含まれていない任意のリソースは、HTTPS のようなセキュアなプロトコルを使用して読み込まなければいけません。 つまり、HTTP のようなインセキュアなプロトコルを使用しないでください。 同様に、WS より WSSFTP より FTPS の使用を推奨します。

なぜ?

HTTPS には 2 つの利点があります。

  1. アプリケーションとホスト間の転送中にデータが変更されていないことを確認し、データの整合性を保証します。
  2. ユーザーと宛先ホスト間のトラフィックを暗号化し、アプリとホスト間で送信される情報の盗聴をより難しくします。

どうすればいいの?

main.js (Main Process)
// NG
browserWindow.loadURL('http://example.com')

// OK
browserWindow.loadURL('https://example.com')
index.html (Renderer Process)
<!-- NG -->
<script crossorigin src="http://example.com/react.js"></script>
<link rel="stylesheet" href="http://example.com/style.css">

<!-- OK -->
<script crossorigin src="https://example.com/react.js"></script>
<link rel="stylesheet" href="https://example.com/style.css">

2. リモートコンテンツで Node.js Integration を有効にしない

info

この推奨は、Electron 5.0.0 からデフォルトの振舞いです。

リモートコンテンツをロードするレンダラー (BrowserWindowWebContentsView<webview>) で Node.js integration を有効にしないことが重要です。 リモートコンテンツに与える権限を制限することで、攻撃者がウェブサイトで JavaScript を実行できるようになった場合に、ユーザを傷つけることを劇的に難しくする目的があります。

その後、特定のホストに対して追加の権限を与えることができます。 例えば、https://example.com/ を指す BrowserWindow を開いている場合、あなたはそのウェブサイトに必要な権限を正確に与えることができますが、それ以上は与えられません。

なぜ?

クロスサイトスクリプティング (XSS) 攻撃は、攻撃者がレンダラープロセスを飛び越えてユーザのコンピュータ上でコードを実行できる場合、より危険です。 クロスサイトスクリプティングの攻撃はかなり一般的――かつ問題が発生している間、通常では、その力は実行されているウェブサイトをめちゃくちゃにするだけです。 Node.js integration を無効にすることは、XSS が昇華され、いわゆる "遠隔コード実行" (RCE) 攻撃になるのを防ぐのに役立ちます。

どうすればいいの?

main.js (Main Process)
// 悪い
const mainWindow = new BrowserWindow({
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
nodeIntegrationInWorker: true
}
})

mainWindow.loadURL('https://example.com')
main.js (Main Process)
// 良い
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(app.getAppPath(), 'preload.js')
}
})

mainWindow.loadURL('https://example.com')
index.html (Renderer Process)
<!-- NG -->
<webview nodeIntegration src="page.html"></webview>

<!-- OK -->
<webview src="page.html"></webview>

Node.js integration を無効にすると、ウェブサイトへ Node.js モジュールまたは機能を使用する API を確認することができます。 プリロードスクリプトは引き続き require や他の Node.js の機能にアクセスできるため、開発者は contextBridge API を介してリモートロードされるコンテンツへと公開するカスタム API を確認してください。

3. コンテキスト分離の有効化

info

この推奨は、Electron 12.0.0 からデフォルトの振舞いです。

コンテキストイソレーションは、開発者が専用の JavaScript コンテキストで、プリロードスクリプトと Electron API でコードを実行できるようにする Electron の機能です。 つまり、Array.prototype.pushJSON.parse などのグローバルオブジェクトは、レンダラープロセスで実行されているスクリプトでは変更できません。

Electron は Chromium の コンテンツスクリプト と同じ技術を使用してこの動作を可能にしています。

nodeIntegration: false を使用している場合でも、真に強力なアイソレーションを強制し Node プリミティブの使用を防ぐためには、contextIsolation も使用 しなければなりません

info

contextIsolation が何であるのか及びこれを有効にする方法についての情報は、コンテキスト隔離 ドキュメントをご参照ください。

4. プロセスのサンドボックス化を有効にする

サンドボックス化 は Chromium の機能で、オペレーティングシステムを利用してレンダラープロセスのアクセス範囲を大幅に制限します。 すべてのレンダラーでサンドボックスを有効にするべきです。 メインプロセスを含むサンドボックス化されていないプロセスでは、信頼されないコンテンツをロードしたり、読んだり、処理したりすることはお勧めしません。

info

プロセスのサンドボックス化が何であるのか、及びこれを有効にする方法についての情報は、プロセスのサンドボックス化 のドキュメントをご参照ください。

5. リモートコンテンツからのセッション権限リクエストのハンドリング

Chrome を使用していると、許可リクエストが表示されていることがあります。これはユーザーが手動で承認する必要がある機能 (通知など) をウェブサイトが使用しようとするたびに、そのポップアップが表示されるものです。

API は Chromium 権限 API に基づいており、同じ種類のアクセス許可を実装しています。

なぜ?

デフォルトでは、開発者がカスタムハンドラを手動で設定していない限り、Electron はすべての権限リクエストを自動的に承認します。 セキュリティを意識した開発者は、堅実なデフォルトとしては、まったく反対のことを想定したかもしれません。

どうすればいいの?

main.js (Main Process)
const { session } = require('electron')
const { URL } = require('url')

session
.fromPartition('some-partition')
.setPermissionRequestHandler((webContents, permission, callback) => {
const parsedUrl = new URL(webContents.getURL())

if (permission === 'notifications') {
// 許可の要求を承認します
callback(true)
}

// URL を検証します
if (parsedUrl.protocol !== 'https:' || parsedUrl.host !== 'example.com') {
// 許可の要求を拒否します
return callback(false)
}
})

6. webSecurity を無効にしない

info

この推奨事項は Electron のデフォルトです。

もうお分かりでしょうが、レンダラープロセス (BrowserWindowWebContentsView<webview>) の webSecurity プロパティを無効にすることは、 重要なセキュリティ機能を無効にすることになります。

製品としてのアプリケーションで webSecurity を無効にしないでください。

なぜ?

webSecurity を無効にすると、同一オリジンポリシーが無効になり、allowRunningInsecureContent プロパティが true に設定されます。 つまり、異なるドメインからの安全でないコードの実行を可能にしてしまいます。

どうすればいいの?

main.js (Main Process)
// NG
const mainWindow = new BrowserWindow({
webPreferences: {
webSecurity: false
}
})
main.js (Main Process)
// OK
const mainWindow = new BrowserWindow()
index.html (Renderer Process)
<!-- NG -->
<webview disablewebsecurity src="page.html"></webview>

<!-- OK -->
<webview src="page.html"></webview>

7. コンテンツセキュリティポリシー (CSP) を定義する

Content Security Policy (CSP) は、クロスサイトスクリプティング攻撃やデータインジェクション攻撃から保護する副層です。 Electron 内でロードする任意のウェブサイトで有効にすることを推奨します。

なぜ?

CSP を使用すると、コンテンツを提供するサーバーが、指定されたウェブページに Electron がロードできるリソースを、制限および制御できます。 https://example.com は、https://evil.attacker.com からのスクリプトは許可せず、定義したオリジンのスクリプトを読み込むことを許可して実行する必要があります。 CSP を定義することは、アプリケーションのセキュリティを向上させる簡単な方法です。

どうすればいいの?

以下の CSP は、Electron が現在のウェブサイトと apis.example.com からスクリプトを実行できるようにします。

// NG
Content-Security-Policy: '*'

// OK
Content-Security-Policy: script-src 'self' https://apis.example.com

CSP HTTP ヘッダ

Electron は Content-Security-Policy HTTP ヘッダ とそれぞれの webRequest.onHeadersReceived タグを尊重します。

main.js (Main Process)
const { session } = require('electron')

session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': ['default-src \'none\'']
}
})
})

CSP メタタグ

CSP では HTTP ヘッダを返すことが好まれます。 しかし、file:// プロトコルでのリソースのロードにこの方法は利用できません。 <meta> タグを使って、以下のようにマークアップ内でページに直接ポリシーを設定するほうが便利なことがあります。

index.html (Renderer Process)
<meta http-equiv="Content-Security-Policy" content="default-src 'none'">

8. allowRunningInsecureContent を有効にしない

info

この推奨事項は Electron のデフォルトです。

デフォルトでは、Electron は HTTPS 上でロードされたウェブサイト上でのみ、安全でないソース (HTTP) からスクリプト、CSS、またはプラグインを読み込んで実行できるようにします。 allowRunningInsecureContent プロパティを true にすることで、その保護を無効にします。

HTTPS 経由でウェブサイトの初期 HTML を読み込んで、HTTP 経由で後続のリソースを読み込もうとすることを "混合コンテンツ" といいます。

なぜ?

HTTPS を介してコンテンツをロードすると、トラフィック自体を暗号化しながら、ロードされたリソースの信憑性と完全性が保証されます。 より詳しくは、セキュアなコンテンツのみを表示する を参照して下さい。

どうすればいいの?

main.js (Main Process)
// NG
const mainWindow = new BrowserWindow({
webPreferences: {
allowRunningInsecureContent: true
}
})
main.js (Main Process)
// OK
const mainWindow = new BrowserWindow({})

9. 実験的な機能を有効にしない

info

この推奨事項は Electron のデフォルトです。

Electron の上級ユーザは、experimentalFeatures のプロパティを使用して Chromium の実験的な機能を有効にすることができます。

なぜ?

実験的な機能は、その名前が示すように、実験的であり、Chromium のすべてのユーザに有効にされていません。 さらに、Electron 全体への影響はテストされていない可能性が高いです。

正しい使用方法は存在しますが、何をしているのか分からない限り、このプロパティを有効にしないでください。

どうすればいいの?

main.js (Main Process)
// NG
const mainWindow = new BrowserWindow({
webPreferences: {
experimentalFeatures: true
}
})
main.js (Main Process)
// OK
const mainWindow = new BrowserWindow({})

10. enableBlinkFeatures を使用しない

info

この推奨事項は Electron のデフォルトです。

Blink は、Chromium のバックグラウンドにあるレンダリングエンジンの名前です。 experimentalFeatures と同様に、enableBlinkFeatures プロパティを使用すると、デフォルトで無効になっている機能を有効にすることができます。

なぜ?

一般に、機能がデフォルトで有効になっていない場合は、よい理由が考えられます。 その機能を有効にするための、正しい使用方法は存在します。 開発者は、機能を有効にする必要がある理由、影響の内容、アプリケーションのセキュリティにどのように影響するかを正確に把握する必要があります。 どのような場合においても、機能を推論的に有効にするべきではありません。

どうすればいいの?

main.js (Main Process)
// 悪例
const mainWindow = new BrowserWindow({
webPreferences: {
enableBlinkFeatures: 'ExecCommandInJavaScript'
}
})
main.js (Main Process)
// OK
const mainWindow = new BrowserWindow()

11. WebView で allowpopups を使用しない

info

この推奨事項は Electron のデフォルトです。

<webview> を使用している場合、新しいウインドウを開くには、<webview> タグにページとスクリプトをロードする必要があります。 allowpopups 属性は、window.open() メソッドを使用して新しい BrowserWindow を作成することができるようにします。 そうでなければ、<webview> は新しいウインドウを作成できません。

なぜ?

ポップアップが必要ない場合は、デフォルトで新しい BrowserWindow の作成を許可しないようにしたほうがよいでしょう。 これは必要最低限なアクセスの原則に従っています。ウェブサイトにその機能が必要でない限り、新しいポップアップを作成させないでください。

どうすればいいの?

index.html (Renderer Process)
<!-- NG -->
<webview allowpopups src="page.html"></webview>

<!-- OK -->
<webview src="page.html"></webview>

12. 作成前に WebView のオプションを検証する

Node.js integration が有効になっていないレンダラープロセスで作成された WebView は、integration 自体を有効にすることはできません。 しかし、WebView は常に独自の webPreferences を使用して、独立したレンダラープロセスを作成します。

メインプロセスから新しい <webview> タグの作成を制御し、webPreferences でセキュリティ機能を無効にしていないことを確認することを推奨します。

なぜ?

<webview> は DOM 内に存在するので、Node.js integration が無効になっていても、WebView はウェブサイトで実行されているスクリプトによって作成できます。

Electron では、開発者はレンダラープロセスを制御するさまざまなセキュリティ機能を無効にすることができます。 ほとんどの場合、開発者はこれらの機能を無効にする必要はありません。したがって、新しく作成した <webview> タグを使用します。

どうすればいいの?

<webview> タグが適用される前に、Electron は will-attach-webview イベントを webContents ホスト上で発火します。 安全性の低いオプションを使用して webViews を作成しないようにするには、このイベントを使用します。

main.js (Main Process)
app.on('web-contents-created', (event, contents) => {
contents.on('will-attach-webview', (event, webPreferences, params) => {
// 未使用のプリロードスクリプトを除くか、その URL が正しいことを検証する
delete webPreferences.preload

// Node.js integration を無効にする
webPreferences.nodeIntegration = false

// ロードされる URL を検証する
if (!params.src.startsWith('https://example.com/')) {
event.preventDefault()
}
})
})

繰り返しになりますが、このリストは単にリスクを最小化するだけで、除去するものではありません。 ウェブサイトを表示することが目的であれば、ブラウザの方が安全性の高い選択肢になります。

13. ナビゲーションを無効化か制限

アプリにナビゲートする必要がない場合、または既知のページにナビゲートするだけの場合は、ナビゲーションをその既知の範囲に完全に制限し、他の種類のナビゲーションを禁止することをお勧めします。

なぜ?

ナビゲーションは一般的な攻撃方法です。 攻撃者が現在のページから移動するようにアプリを制御することができると、インターネット上の Web サイトを開くことをアプリに強制する可能性があります。 webContents がより安全に設定されている (nodeIntegration を無効にする、contextIsolation を有効にするなど) 場合でも、アプリにデタラメな Web サイトを開かせる アプリを悪用する方がはるかに簡単になります。

一般的な攻撃パターンは、攻撃者が、アプリでそのユーザに攻撃者のいずれかのページに移動するような方法で操作することを強いることです。 これは通常、リンク、プラグイン、またはその他のユーザー生成コンテンツを介して行われます。

どうすればいいの?

アプリにナビゲーションが不要な場合は、will-navigate ハンドラ内で event.preventDefault() を呼び出すとよいでしょう。 アプリがどのページに移動するかがわかっている場合は、イベントハンドラで URL を確認し、予期している URL と一致する場合にのみナビゲーションを許可します。

URL には Node のパーサーを使用することを推奨します。 単純な文字列比較は時々だまされる可能性があります - startsWith('https://example.com') テストは https://example.com.attacker.com を通過させます 。

main.js (Main Process)
const { URL } = require('url')
const { app } = require('electron')

app.on('web-contents-created', (event, contents) => {
contents.on('will-navigate', (event, navigationUrl) => {
const parsedUrl = new URL(navigationUrl)

if (parsedUrl.origin !== 'https://example.com') {
event.preventDefault()
}
})
})

14. 新規ウインドウの作成を無効化か制限

既知の一連のウインドウがある場合は、アプリ内での追加ウインドウの作成を制限することをお勧めします。

なぜ?

ナビゲーションと同様、新しい webContents の作成は一般的な攻撃手段です。 攻撃者はそのままではページを開こうとしても開くことができないために、新しいウィンドウ、フレーム、その他のレンダラープロセスをより多くの権限で作成するようにアプリに強制しようとします。

あなたが作成する必要があると知っているものに加えてウィンドウを作成する必要がない場合は、作成を無効にするとノーコストで少しの追加のセキュリティが手に入ります。 これは1つの BrowserWindow を開き、実行時に任意の数の追加ウィンドウを開く必要がないアプリケーションで普遍的なケースです。

どうすればいいの?

webContents は、新しいウインドウを作成する前に、ウインドウを開くハンドラー に委譲します。 ハンドラーは、他のパラメータの中の、ウィンドウを開くように要求された url とそのウィンドウを作成するために使用されたオプションを受け取ります。 ウインドウの作成を監視するハンドラを登録し、予期せぬウィンドウの作成は拒否するよう推奨します。

main.js (Main Process)
const { app, shell } = require('electron')

app.on('web-contents-created', (event, contents) => {
contents.setWindowOpenHandler(({ url }) => {
// この例では、既定のブラウザでこのイベントのURLを開くように
// オペレーティングシステムに依頼します。
//
// shell.openExternal に渡す URL を許可する基準ついては、
// 以降の項目を参照してください。
if (isSafeForExternalOpen(url)) {
setImmediate(() => {
shell.openExternal(url)
})
}

return { action: 'deny' }
})
})

15. 信用されないコンテンツで shell.openExternal を使用しない

shell モジュールの openExternal API は、デスクトップのネイティブユーティリティで指定プロトコルの URI を開きます。 これは例えば、macOS の open ターミナルコマンドユーティリティに似た機能で、URI とそのファイルタイプの関連に基づいた特定のアプリケーションでそれを開きます。

なぜ?

openExternal の不適切な利用によって、そのユーザーのホストを危険に曝す可能性があります。 openExternalを信頼できないコンテンツで使用するとき、任意のコマンドの実行を許してしまう可能性があります。

どうすればいいの?

main.js (Main Process)
//  Bad
const { shell } = require('electron')
shell.openExternal(USER_CONTROLLED_DATA_HERE)
main.js (Main Process)
//  Good
const { shell } = require('electron')
shell.openExternal('https://example.com/index.html')

16. 現行バージョンの Electron を使う

常に最新バージョンの Electron を使用するように努力してください。 新しいメジャーバージョンがリリースされる度に、できるだけ早くアプリを更新しましょう。

なぜ?

古いバージョンの Electron、Chromium、Node.js で構築されたアプリケーションは、最新バージョンのこれらコンポーネントを使用しているアプリケーションよりも容易な標的です。 一般的に、古いバージョンの Chromium と Node.js ではより広いセキュリティ問題とエクスプロイトが適用できます。

Chromium と Node.js はどちらも、何千人もの才能のある開発者によって構築された素晴らしい技術です。 人気を考えると、それらのセキュリティは同様に熟練したセキュリティ研究者によって慎重にテストされ分析されます。 これら研究者の多くは、脆弱性を責任を持って開示 しています。これは一般に、研究者が問題を公開する前に Chromium と Node.js に問題を修正する時間を与えることを意味します。 最新バージョンの Electron (および Chromium と Node.js) で実行している場合、潜在的なセキュリティ問題がそれほど広く知られておらずアプリケーションはより安全になります。

どうすればいいの?

Electron の 破壊的変更 のドキュメントを参照し、コードの更新が必要かどうかを確認しながら、メジャーバージョンが上がるごとにアプリを移行しましょう。

17. すべての IPC メッセージの sender を確認する

受信した IPC メッセージの sender プロパティを常に検証し、信頼できないレンダラーへアクションの実行や情報送信をしないように確認すべきです。

なぜ?

iframe や子ウインドウを含め、すべてのウェブフレームは理論的にはメインプロセスに IPC メッセージを送信できます。 event.reply を介して送信者にユーザのデータを返す IPC メッセージがある場合、またはレンダラーがネイティブにできない特権的アクションをメインで実行する場合は、第三者のウェブフレームから来たメッセージを聞いていないことを確認すべきです。

既定で すべて の IPC メッセージの sender を検証すべきです。

どうすればいいの?

main.js (Main Process)
// 悪い例
ipcMain.handle('get-secrets', () => {
return getSecrets()
})

// 良い例
ipcMain.handle('get-secrets', (e) => {
if (!validateSender(e.senderFrame)) return null
return getSecrets()
})

function validateSender (frame) {
// 既存の URL パーサと allowlist を使用して URL のホストを評価します
if ((new URL(frame.url)).host === 'electronjs.org') return true
return false
}

18. file:// プロトコルの使用を避け、カスタムプロトコルを使うようにする

file:// プロトコルではなくカスタムプロトコルからローカルページを提供すべきです。

なぜ?

Electron では file:// プロトコルはウェブブラウザよりも多くの権限を取得し、ブラウザ内でも http/https URL とは異なる扱いを受けます。 カスタムプロトコルを使用すると、何をいつ読み込むかについてさらに細かく制御しながら、従来のウェブ URL の動作にさらに準拠できます。

file:// で実行されているページは、マシン上のすべてのファイルに一方的にアクセスできるため、XSS の欠陥を利用してユーザのマシンから任意のファイルを読まれる可能性があります。 カスタムプロトコルを使用すると、プロトコルを特定のファイルセットのみに提供するように制限できるため、このような問題を防ぐことができます。

どうすればいいの?

カスタムプロトコルからファイル/コンテンツを提供する方法について、protocol.handle の例に従ってください。

19. どの Fuse を変更できるか確認する

Electron には、便利なオプションが多数付属していますが、アプリケーションの大部分ではおそらく不要です。 独自バージョンの Electron をビルドしなくてもよいように、Fuse でこれらをオフまたはオンにできるようになっています。

なぜ?

runAsNodenodeCliInspect などの一部の Fuse を使用すると、特定の環境変数または CLI 引数を使用してコマンドラインから実行すれば、アプリケーションの動作を変更できます。 これらはアプリケーションを通じたデバイス上でのコマンド実行に利用されるかもしれません。

つまり外部スクリプトが、潜在的には許可していないものの、アプリケーションに権限があるかもしれない操作を実行できるようになります。

どうすればいいの?

これら Fuse を簡単に反転させるために、モジュール @electron/fuses を作成しました。 使用方法や潜在的なエラーケースの詳細については、モジュールの README を確認してください。また、ドキュメントの Fuse を反転するにはどうすればよいですか? をご参照ください。