【Electron】remote moduleがdeprecatedになっている背景

Electron 10.0.0が先日リリースされて、remote module がデフォルトで無効になりました。

バージョンを上げた時に、一部機能が動かなくなる場合など出てくると思いますので

  • そもそもremote moduleとは
  • なぜ remote module を使うとよくないのか

を整理してみたので、共有してみたいと思います。

この内容は2020年02月に開催されたCovalenceConf 2020のセッション(Jeremy Apthorp: Remote Module Considered Harmful )を元にまとめた内容であり、コードは動画内のものを引用しています。

remote module とは

remote module を使うことでレンダラプロセス内であたかもメインプロセス内のオブジェクトを直接触れるように見せかけることができます。

例えば、remote module を使って、レンダラプロセスで以下のようなサーバーを起動するようなコードを書くことができます。が、実際にはメインプロセスでソケットが開いていて、3000番ポートにリクエストがあった際、メインプロセスからレンダラプロセスをIPCで通信します。

// CovalenceConf 2020のセッション
// (Remote Module Considered Harmful )から引用

// Renderer process
const remote = require('electron').remote

const remoteHttp = remote.require('http')

const s = remoteHttp.createServer((req, res) => {
  res.setHeader('Access-Control-Allow-Origin, '*')
  res.end('yay')
})

s.listen(3000, () => {
  fetch('http://localhost:3000')
    .then(r=> r.text())
    .then(t => alert(t))
})

問題が発生する要因

remote moduleを通してメインプロセスとレンダラプロセスのIPC通信を実現する手段として、proxy objectsというものが介在しているようです。

まずい点その①遅い(パフォーマンス問題)

proxy objects が介在すると気がつかない間にIPC通信が増えてしまい、気がつかない間にパフォーマンスに問題が発生するケースがあるようです。 動画内では、以下のコードスニペットをあげており、この短いコードの中で9回IPC通信が行われます。

また、そもそもレンダラプロセスからメインプロセスのオブジェクトにアクセスすると、IPC通信を介することでローカルオブジェクトへのアクセスより1000倍遅くなるようです。

// CovalenceConf 2020のセッション
// (Remote Module Considered Harmful )から引用

// Main process
global.thing = {
  rectangle: {
    getBounds() {
      return { x, y, width, height } }
    setBounds(bounds) { /* ... */ }
  }
}
// Renderer process
let thing = remote.getGlobal('thing')
let { x, y, width, height} =
  thing.rectangle.getBounds()
thing.rectangle.setBounds(
  { x, y, width, height: height + 100 })

パフォーマンス問題が発生することで、プロセス間の非同期処理が失敗したり、デバッグが難しい問題を引き起こすことがあるようです。

まずい点その②セキュリティ問題がある

remote module を使ってレンダラプロセスからメインプロセスにIPC通信する際、ELECTRON_BROWSER_FUNCTION_CALLというIPCメッセージを送れると、メインプロセスの全ての権限が与えられてなんでもできちゃうという潜在的な問題があるようです。 PNGjsonを読み込むなど信頼できないコードが含まれる場合もある(セキュリティ脆弱性NVD - CVE-2019-7317NVD - CVE-2014-3188)ので、セキュリティホールになるようです。

remote moduleを無くすためのElectronの展開

以下のElectronのバージョンでそれぞれ対応を行い、徐々にremote module を無くす予定のようです。

  • v9: 明示的に有効にせずremote module を使っている場合、警告を出す
  • v10: デフォルトでremote moduleを無効に
  • (今後) v12: require('electron').remote または enableRemoteModule: trueにしている場合、警告を出すように
  • (今後) v14: require('electron').remoteを削除

remote moduleを無くすためのアプリケーション側の対応

現状 remote モジュールを使って、レンダラプロセスからあたかもローカルオブジェクトのようにメインプロセス内のオブジェクトを使っている場合、今後どうしたら良いのか。 対応としては2つあるようです。

①明示的にIPC通信で処理するように置き換える

remote moduleを使ってメインプロセス内のオブジェクトを参照し、暗黙的にIPC通信が行われることによって様々な問題が発生するので、明示的なIPC通信に置き換えていくことを推奨しているようです。

f:id:moritamorie:20200830103205p:plain

② 移管されるelectron-userland/remoteを使う

build-inで提供されている remote moduleは将来的に削除され、electron-userland/remoteに移管されるのでそれを使い続けるというのもできるようです。

参照ドキュメント