メインコンテンツへ飛ぶ

プロセスのサンドボックス化

Chromium の重要なセキュリティ機能の一つは、プロセスをサンドボックス内で実行できることです。 サンドボックスは、ほとんどのシステムリソースへのアクセスを制限することで悪意のあるコードが引き起こす被害を制限します。サンドボックスのプロセスは、CPU サイクルとメモリのみを自由に使用できます。 サンドボックス化したプロセスで追加の特権を必要とする操作を実行するには、専用の通信チャンネルを使用してより特権のあるプロセスにタスクを委譲します。

Chromium では、メインプロセス以外のほとんどのプロセスにサンドボックス化が適用されます。 これにはレンダラープロセスのほか、オーディオサービス、GPU サービス、ネットワークサービスなどのユーティリティプロセスも含まれます。

詳しい情報は Chromium の サンドボックスデザインのドキュメント をご参照ください。

Electron 20 から、サンドボックスは追加設定なしでレンダラープロセスに対して有効です。 プロセスのサンドボックスを無効化する場合は、単一のプロセスでのサンドボックス無効化 の節をご参照ください。

Sandbox behavior in Electron

Electron のサンドボックス化したプロセスは ほぼ Chromium と同じように動作しますが、Electron は Node.js とのインターフェイスであるために更に考慮すべき概念がいくつかあります。

レンダラープロセス

Electron のレンダラープロセスをサンドボックス化すると、通常の Chrome レンダラーと同じように動作します。 サンドボックス化したレンダラーは Node.js 環境が初期化されません。

そのため、サンドボックスを有効にすると、レンダラープロセスはプロセス間通信 (IPC) を介したメインプロセスへのタスクの委譲によってのみ、特権的なタスク (ファイルシステムとのやりとり、システムへの変更、サブプロセスの生成など) を実行できます。

note

プロセス間通信に関する詳細は、IPC ガイド をご確認ください。

プリロードスクリプト

レンダラープロセスがメインプロセスと通信できるようにするため、サンドボックス化したレンダラーにアタッチされるプリロードスクリプトでは Node.js API をポリフィルしたサブセットを利用できるようになっています。 Node の require に似た require 関数のモジュールを公開してありますが、これは以下 Electron や Node の組み込みモジュールのサブセットしかインポートできません。

  • electron (following renderer process modules: contextBridge, crashReporter, ipcRenderer, nativeImage, webFrame, webUtils)
  • events
  • timers
  • url

node: インポート は以下のものをサポートしています。

加えて、プリロードスクリプトは以下の Node.js プリミティブもグローバルとしてポリフィルします。

require 関数は機能を限定したポリフィルであるため、CommonJS モジュール を利用したプリロードスクリプトの複数ファイル分割ができません。 プリロードコードを分割する必要がある場合は、webpackParcel のようなバンドラーを使用してください。

preload スクリプトに与えられる環境は、サンドボックス化したレンダラーの環境よりも大幅に特権的です。contextIsolation が有効になっていない限り、特権的な API をレンダラープロセスで実行している信頼されていないコードにリークできることに注意してください。

サンドボックスの設定

ほとんどのアプリでは、サンドボックス化が最良の選択です。 サンドボックスと互換性のない特定のユースケース (例えば、レンダラーでネイティブ Node モジュールを使用する場合) であれば、特定のプロセスに対してサンドボックスを無効化できます。 これは信頼できないコードやコンテンツがサンドボックス化されていないプロセスに存在する場合では特に、セキュリティ上のリスクを招きます。

単一のプロセスでサンドボックスを無効化する

Electron では、BrowserWindow コンストラクタで sandbox: false を設定することでレンダラープロセスごとにサンドボックスを無効化できます。

main.js
app.whenReady().then(() => {
const win = new BrowserWindow({
webPreferences: {
sandbox: false
}
})
win.loadURL('https://google.com')
})

レンダラーで Node.js インテグレーションが有効の場合は、サンドボックス化も無効です。 これは BrowserWindow コンストラクタで nodeIntegration: true フラグを付けるとできます。

main.js
app.whenReady().then(() => {
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
})
win.loadURL('https://google.com')
})

アプリ全体でサンドボックスを有効にする

すべてのレンダラーにサンドボックスを強制したい場合は、app.enableSandbox API も利用できます。 注意として、この API は app の ready イベントより前に呼ぶ必要があります。

main.js
app.enableSandbox()
app.whenReady().then(() => {
// `app.enableSandbox()` が呼び出されたので任意の sandbox:false 呼び出しはオーバーライドされます。
const win = new BrowserWindow()
win.loadURL('https://google.com')
})

Chromium のサンドボックスを無効にする (テストのみ)

--no-sandbox CLI フラグで Chromium のサンドボックスを完全に無効化することもできます。これは、(ユーティリティプロセスを含む) すべてのプロセスのサンドボックスを無効化します。 このフラグはテスト目的でのみ使用し、本番環境では 絶対に 使用しないことを強く推奨します。

注意として、この状況で sandbox: true オプションを指定してもレンダラーの Node.js 環境は無効になります。

信頼されないコンテンツの描画に関する注意

信頼されないコンテンツを Electron で描画することはまだ未知の領域ですが、いくつかのアプリケーションは成功を収めています (例: Beaker Browser)。 私たちの目標はサンドボックス化したコンテンツのセキュリティに関して Chrome にできるだけ近づくことですが、突き詰めるといくつかの基本的な問題のためにいつも後れを取ることになります。

  1. 私たちには Chromium 製品に適したセキュリティのリソースやノウハウがありません。 今あるものを活かして Chromium からできることはすべて継承し、セキュリティ上の問題にも迅速に対応できるようにしていますが、Electron は Chromium のようにリソースを割くことができず、Chromium のようなセキュリティは確保できません。
  2. Chrome のセキュリティ機能 (セーフブラウジングや証明書の透過性など) の中には、中央集権化と専用サーバが必要なものがありますが、どちらも Electron プロジェクトの目的に反しています。 そのため、セキュリティ関連のコストが発生しないように、Electron では機能を無効にしています。
  3. Chromium は 1 つだけですが Electron には何千ものアプリが存在しており、それぞれのアプリの動作は微妙に異なります。 これらの違いを考慮すると巨大な可能性の空間が生じ、通常とは異なるユースケースでのプラットフォームのセキュリティ確保に挑戦することになります。
  4. セキュリティアップデートをユーザーに直接伝えることができないため、セキュリティアップデートをユーザーに届けるために、アプリベンダーに Electron のバージョンをアップグレードして頂いています。

Chromium のセキュリティ修正を古いバージョンの Electron にバックポートするよう最善の努力をしていますが、すべての修正のバックポートは保証できません。 堅牢性を確保するには、Electron の最新の安定版を使用することが最善の方法です。