Chrome 拡張機能で eval を使用する

Chrome の拡張機能システムでは、かなり厳格なデフォルトのコンテンツ セキュリティ ポリシー(CSP)が適用されます。ポリシーの制限は単純です。スクリプトは行外に配置し、 JavaScript ファイルとインライン イベント ハンドラは、addEventListener を使用するように変換する必要があります。eval() は、 無効です。Chrome アプリにはより厳格なポリシーがあり、Google はそのセキュリティにも満足しています プロパティを定義できます。

ただし、さまざまなライブラリで eval()eval に似た構造( new Function(): パフォーマンスの最適化と式の容易さ。テンプレート ライブラリは、特にこのスタイルの実装に適しています。Angular.js など、一部のフレームワークは CSP を標準でサポートしていますが、多くの一般的なフレームワークは、拡張機能の eval のない世界に対応するメカニズムにまだ更新されていません。そのため、この機能のサポートを終了することは、デベロッパーにとって想定よりも問題が多いことが判明しました。

このドキュメントでは、セキュリティを損なうことなくこれらのライブラリをプロジェクトに含めるための安全なメカニズムとして、サンドボックス化について説明します。簡潔にするために拡張機能という用語を使用していますが、 アプリケーションに等しく適用されます。

サンドボックスを使用する理由

eval は拡張機能内で危険です。実行されるコードは、拡張機能の高権限環境内のすべてのものにアクセスできるためです。ユーザーのセキュリティとプライバシーに深刻な影響を与える可能性がある強力な chrome.* API が多数用意されています。単純なデータ漏洩は、心配の種のほんの一部にすぎません。提案されているソリューションは、eval が拡張機能のデータや拡張機能の高価値 API にアクセスすることなくコードを実行できるサンドボックスです。データも API も、まったく問題ありません。

これは、拡張機能パッケージ内の特定の HTML ファイルをサンドボックス化してリストすることで実現しています。 サンドボックス化されたページが読み込まれるたびに、そのページは一意のオリジンに移動され、chrome.* API へのアクセスが拒否されます。このサンドボックス化されたページを iframe 経由で拡張機能に読み込むと、次のことができます。 メッセージを渡してなんらかの形で処理し、API から返されるのを待ちます。 表示されます。このシンプルなメッセージ メカニズムにより、eval ドリブンを安全に含めるために必要なすべての機能が提供されます。 ワークフローで確認します。

サンドボックスの作成と使用

コードをすぐに詳しく知りたい場合は、サンドボックスのサンプル拡張機能を入手し、 オフ。これは、Handlebars 上に構築された小さなメッセージング API の実例です。 使用するために必要なものがすべて揃っているはずです。詳しく説明したい場合は、このサンプルを一緒に見てみましょう。

マニフェスト内のファイルを一覧表示する

サンドボックス内で実行する必要がある各ファイルは、sandbox プロパティを追加して拡張機能マニフェストに登録する必要があります。これは重要なステップであり、忘れがちなので、サンドボックス化されたファイルがマニフェストに含まれていることを再度確認してください。このサンプルでは、巧妙に「sandbox.html」という名前のファイルをサンドボックス化しています。マニフェスト エントリは次のようになります。

{
  ...,
  "sandbox": {
     "pages": ["sandbox.html"]
  },
  ...
}

サンドボックス化されたファイルを読み込む

サンドボックス化されたファイルで何か面白いことをするには、拡張機能のコードによってアクセスできるコンテキストでファイルを読み込む必要があります。ここでは、sandbox.htmliframe を介して拡張機能のイベントページeventpage.html)にアクセスする。eventpage.js には、ブラウザ アクションがクリックされるたびに、ページ上の iframe を見つけてその contentWindowpostMessage メソッドを実行することで、サンドボックスにメッセージを送信するコードが含まれています。メッセージは、contextcommand の 2 つのプロパティを含むオブジェクトです。後ほど詳しく説明します。

chrome.browserAction.onClicked.addListener(function() {
 var iframe = document.getElementById('theFrame');
 var message = {
   command: 'render',
   context: {thing: 'world'}
 };
 iframe.contentWindow.postMessage(message, '*');
});
postMessage API に関する一般的な情報については、MDN に関する postMessage のドキュメント をご覧ください。かなり完全な内容なので、一読する価値があります。特に、データはシリアル化可能である場合にのみやり取りできます。たとえば、関数は対象外です。

危険なことをする

sandbox.html が読み込まれると、Handlebars ライブラリを読み込み、インライン 次のように Handlebars が提案する方法を使用します。

<script src="handlebars-1.0.0.beta.6.js"></script>
<script id="hello-world-template" type="text/x-handlebars-template">
  <div class="entry">
    <h1>Hello, !</h1>
  </div>
</script>
<script>
  var templates = [];
  var source = document.getElementById('hello-world-template').innerHTML;
  templates['hello'] = Handlebars.compile(source);
</script>

絶対に失敗することはありません。Handlebars.compile が最終的に new Function を使用する場合でも、すべてが期待どおりに機能し、templates['hello'] にコンパイルされたテンプレートが作成されます。

結果を返す

このテンプレートを使用できるように、コマンドを受け入れるメッセージ リスナーをセットアップします。 [イベント]ページから渡された command を使用して、実行する処理を決定します( レンダリング以外の処理も想像してくださいテンプレートの作成などが考えられます場合によっては、 渡され、context はレンダリングのためにテンプレートに直接渡されます。レンダリングされた HTML はイベントページに渡され、拡張機能で後で使用できるようになります。

<script>
  window.addEventListener('message', function(event) {
    var command = event.data.command;
    var name = event.data.name || 'hello';
    switch(command) {
      case 'render':
        event.source.postMessage({
          name: name,
          html: templates[name](event.data.context)
        }, event.origin);
        break;

      // case 'somethingElse':
      //   ...
    }
  });
</script>

イベントページに戻ると、このメッセージが表示され、渡された html データを使って面白いことを行います。この例では、デスクトップ通知でエコーを出力しますが、この HTML を拡張機能の UI の一部として安全に使用することも可能です。挿入方法 innerHTML は、サンドボックス化の完全な不正使用であっても、重大なセキュリティ リスクをもたらすことはありません。 危険なスクリプトやプラグインのコンテンツを挿入することは アクセスします。

このメカニズムにより、テンプレート化が簡単になりますが、もちろんテンプレート化に限定されません。厳格なコンテンツ セキュリティ ポリシーですぐに動作しないコードはすべてサンドボックス化できます。実際、プログラムの各部分を適切に実行するために必要な最小限の権限セットに制限するために、正しく動作する拡張機能のコンポーネントをサンドボックス化することがよくあります。Google 提供の安全なウェブアプリと Chrome 拡張機能の作成に関するプレゼンテーション I/O 2012 では、これらの手法の実例をいくつか紹介しています。 あります。