セキュリティを考える:ElectronでWebブラウザを作る(その2)

Electronの手習いでWebブラウザを作成するシリーズの第2回として、Electronで作成するアプリのセキュリティについて考えます。

Web上の情報を集めて検討し、本開発においてのセキュリティ・チェックリストとしてまとめます。

はじめに

前回、仮にWebを表示するところを作成しました。

仮にもネットワークに接続するプログラムですから、セキュリティについては考えなくてはなりません。(いえ、今どきは接続しないプログラムでも悪意を想定しないとなりませんが。プログラムを書き換えられたりとか。)

WEBの情報から

付け焼き刃が見え見えですが、まずはWebより情報を集め、それをもとに作成Webブラウザはどうするかを考えます。

各節の先頭に、参照させて頂きましたページを示します。

Electronのドキュメントから

Electronのドキュメントには、それについてのページがありました。

最初の章には「信頼できるところ以外からコードを取得して実行するな」と書いてあります。

当たり前のことなのですが、広く考えるとブラウザのビュー内でjavascriptが実行されることも含まれるのかもしれません。

そして次の「Ignoring Above Advice」の章をみると、Noteに「リモートのコンテンツを表示するときはwebview内でして、nodeIntegrationが無効のことを確認しなさい」とあります。

その下のチェックリストを要約すると以下です。

  • 安全な(https)のみを表示する。
  • リモートコンテンツを表示するレンダラーではnodeIntegrationを無効にする。
  • webSecurityを無効にしない。
  • 「Content-Security-Policy」を「script-src ‘self’」など制限的に定義する。
  • evalをオーバーライドして無効にする。
  • allowDisplayingInsecureContentやallowRunningInsecureContentをtrueに設定しない。
  • 熟知せずにexperimentalFeatures、experimentalCanvasFeaturesを有効にしない。またblinkFeaturesを使用しない。
  • WebViewsでは、nodeintegration属性を追加しない。disablewebsecurity、allowpopups、insertCSS、executeJavaScriptを使用しない。

1点目はWebブラウザとしては厳しいですね。証明書があることがサイトの信頼になり中間者攻撃を防ぐという意味ではわかるのですが、このブログは見られません(´・ω・`)。ここはデフォルトhttpsとし、最後は使う人の判断ということにします。

2点目は、<webview> Tagのページにかいてある「セキュリティのため、nodeIntegrationを有効にしたBrowserWindowsでしかwebviewは使えません」と相反するように読めます。

しかしこれはwebviewを使わない場合についてですね。前回までのプログラムのmain.jsにて、「MainWin = new BrowserWindow」のオプションに「webPreferences: { nodeIntegration: false },」を追加すると、最初の「Helo World!」を表示しません。

またデフォルトでwebviewのnodeIntegrationが無効なことは、前回の実行にて「Hello World!」の下に「process.versions.electron」の表示がなされなかったことで、実は確認済みです。(window.htmlのwebviewタグにnodeIntegration属性を追加してみると、Electronのバージョンが表示されました。)

4点目は、windows.htmlのヘッダに以下を加えることにします。

<meta http-equiv="Content-Security-Policy" content="default-src 'self';" />

(実はこれではうまくありません。詳しくは次回。)

5点目は、window.jsの先頭に以下を加えます。

window.eval = global.eval = function() {
  throw new Error("Can't use eval().");
}

残りの項目については、使わない・設定しないようにします。

最後の章には、nodeintegrationが無効でも、Nodeのglobal.Bufferが現在は有効で、将来は無効になるであろう旨が書かれています。

メモリを消費する悪さはできそうな気がしますので、将来無効になるまではpreload scriptで無効にしておいたほうが良いのでしょう。

クロスサイトスクリプティングの脅威

ここには、DOM-based XSS(クロスサイトスクリプティング)の脅威が大きい旨が書かれています。

webviewにnodeIntegrationをせず、Content-Security-Policyを定義したとしても、「結局XSSでwebviewをnodeIntegration有効で作られたらおしまい」の旨が書かれています。

その緩和として、iframe sandboxの利用が述べられています。

iframe sandbox=” allow-same-origin “で開いてその中でDOM操作を行うという、「最後のひと網」の手法です。

しかしDOM操作が複雑そうなのと、CSSをどうするかがピンと来ませんので要検討です。

キホンのキホン

こちらも参照させていただきました。(ありがとうございます。)

最後のまとめを引用させていただきます。

  • テキストノードや属性値としてHTMLを出力する時点で「<」「>」「”」「’」「&」の5文字をエスケープする
  • 属性値は引用符で囲む
  • URLをリンクとして取り扱う場合にはhttpおよびhttpsスキームに限定する

1点目は基本ですね。(私でもわかります。)

2点目はそうしています。一応コーディング標準にも展開。

3点目については、ファイル(fileプロトコル)も見たいですね。

折衷案として以下のような仕様にしたいと思います。

  • ユーザーの操作からは、ファイルを開くことができる。(fileプロトコル)
  • fileプロトコルのコンテンツからは、file:へのリンク及び、http:・https:へのリンクが有効になる。
  • http及びhttpsプロトコルのコンテンツからは、http:及びhttps:へのリンクのみが有効になる。

実際は、webviewからのイベント処理でチェックすることになると思います。

glasspotのチェック項目

以上検討の結果、作成するアプリのセキュリティに関するチェック項目は以下になります。

仕様について:

  • 基本はhttpsプロトコルのみ。
  • httpプロトコルの利用はユーザーの操作によるか、同意していることを確実にする。
  • ユーザー操作か、その延長のみfileプロトコルが有効。

実装について:

  • windows.html:DOM操作をする部分はiframe化(要検討)。
  • windows.html:Content-Security-Policyの記述。
  • window.js:evalの無効化、エスケープの確実化。
  • preload.js:eval とBufferの無効化。
  • BrowserWindowsやwebviewに危険なオプションは追加しない。
  • 有効なプロトコルのみを通す設計。

preload.jsでもevalを無効にすることにしました。影響のあるページはあるかもしれませんが、大抵はJSON.parse()で済ましているように思います。

以上でも漏れはまだあると思いますし、セキュリティはいくつも網を掛けるものですので、思いついたらチェック項目に加えたいと思います。

Electronなどのベースのアプリをアップデートした時も再検討が必要ですね。

まとめ

昔(2000年頃)の話ですが、C言語のstringライブラリ(string.h)で「バッファーオーバーランが危険」と言われるようになりました。Visual Cなんかは、それでバッファサイズを指定する引数がついた関数の、新しいstringライブラリができました。

もしプログラムにバッファサイズ指定のない関数を使っており、「セキュリティ的に問題」となったならば、関数を全部調べて書き換えなければなりません。(呼び出しごとにバッファサイズを調べなければならないので、単純に置換は無理です。)

後から問題になると、このように大変な修正が必要になることもありますから、セキュリティについて早めに検討しても損はありません。

ちなみにその2000年頃C言語で組み込みをしていた私は、既にバッファ数指定のstringライブラリを自作してそれを使っていました。外からの脅威という観点でなく、自分のミスでバッファーオーバーランしそうだったから。

次回は、今回決定したセキュリティのチェック項目を、プログラムに組み込みたいと思います。

コメントを残す