外部コンテンツ

Chrome アプリのセキュリティ モデルでは、iframe 内の外部コンテンツの使用、インライン スクリプトと eval() の使用は禁止されています。これらの制限はオーバーライドできますが、外部コンテンツをアプリから分離する必要があります。

分離されたコンテンツは、アプリのデータやどの API にも直接アクセスできません。クロスオリジンの XMLHttpRequests とポスト メッセージを使用して、イベントページとサンドボックス化されたコンテンツの間で通信し、API に間接的にアクセスします。

外部リソースの参照

アプリで使用されるコンテンツ セキュリティ ポリシーでは、さまざまな種類のリモート URL の使用が禁止されているため、アプリページから外部の画像、スタイルシート、フォントを直接参照することはできません。代わりに、クロスオリジンの XMLHttpRequests を使用してこれらのリソースを取得し、blob: URL を介して提供できます。

マニフェストの要件

クロスオリジンの XMLHttpRequests を実行できるようにするには、リモート URL のホストの権限を追加する必要があります。

"permissions": [
    "...",
    "https://supersweetdomainbutnotcspfriendly.com/"
  ]

クロスオリジンの XMLHttpRequest

リモート URL をアプリにフェッチし、そのコンテンツを blob: URL として提供します。

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://supersweetdomainbutnotcspfriendly.com/image.png', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
  var img = document.createElement('img');
  img.src = window.URL.createObjectURL(this.response);
  document.body.appendChild(img);
};

xhr.send();

これらのリソースをローカルに保存して、オフラインで使用できるようにすることもできます。

外部ウェブページの埋め込み

webview タグを使用すると、ウェブページなどの外部のウェブ コンテンツをアプリ内に埋め込むことができます。Chrome アプリ内で無効になっているリモート URL を参照する iframe を置き換えます。iframe とは異なり、webview タグは別のプロセスで実行されます。その内部の悪用は隔離され、昇格された権限を取得できません。さらに、ストレージ(Cookie など)はアプリから分離されているため、ウェブ コンテンツがアプリのデータにアクセスできません。

WebView 要素を追加する

webview 要素にはソース コンテンツへの URL を含め、サイズを指定する必要があります。

<webview src="http://news.google.com/" width="640" height="480"></webview>

プロパティの更新

webview タグの srcwidthheight プロパティを動的に変更するには、これらのプロパティを JavaScript オブジェクトで直接設定するか、setAttribute DOM 関数を使用します。

document.querySelector('#mywebview').src =
    'http://blog.chromium.org/';
// or
document.querySelector('#mywebview').setAttribute(
    'src', 'http://blog.chromium.org/');

ローカル コンテンツをサンドボックス化する

サンドボックス化することで、指定したページをサンドボックス化された一意のオリジンで配信できます。それらのページはコンテンツ セキュリティ ポリシーから除外されます。サンドボックス化されたページでは、iframe、インライン スクリプト、eval() を使用できます。sandbox のマニフェスト フィールドの説明を確認します。

ただしトレードオフ: サンドボックス化されたページでは Chrome を使用できない*。API との統合なども可能です。eval() などを行う必要がある場合は、この方法を採用して CSP から除外してください。ただし、便利な新機能は使用できません。

サンドボックスでインライン スクリプトを使用する

インライン スクリプトと eval() を使用するサンドボックス化されたページの例を次に示します。

<html>
  <body>
    <h1>Woot</h1>
    <script>
      eval('console.log(\'I am an eval-ed inline script.\')');
    </script>
  </body>
</html>

マニフェストにサンドボックスを含める

マニフェストに sandbox フィールドを追加し、サンドボックス内で配信されるアプリページをリストする必要があります。

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

サンドボックス化されたページをウィンドウで開く

他のアプリページと同様に、サンドボックス化されたページを開くウィンドウを作成できます。次のサンプルでは、サンドボックス化されていないメインアプリ ウィンドウとサンドボックス化されたページ用のウィンドウを 2 つ作成します。

chrome.app.runtime.onLaunched.addListener(function() {
  chrome.app.window.create('window.html', {
    'bounds': {
      'width': 400,
      'height': 400,
      'left': 0,
      'top': 0
    }
  });

  chrome.app.window.create('sandboxed.html', {
    'bounds': {
      'width': 400,
      'height': 400,
      'left': 400,
      'top': 0
    }
  });
});

サンドボックス化されたページをアプリページに埋め込む

サンドボックス化されたページは、iframe を使用して別のアプリページ内に埋め込むこともできます。

<!DOCTYPE html>
<html>
<head>
</head>
  <body>
    <p>I am normal app window.</p>

    <iframe src="sandboxed.html" width="300" height="200"></iframe>
  </body>
</html>

サンドボックス化されたページへのメールの送信

メッセージの送信には 2 つの部分があります。送信元のページまたはウィンドウからメッセージを送信する段階と、受信側のページまたはウィンドウでメッセージをリッスンする部分です。

メッセージを投稿

postMessage を使用して、アプリとサンドボックス化されたコンテンツの間で通信できます。次に、サンドボックス化されたページを開くためにメッセージを投稿するバックグラウンド スクリプトのサンプルを示します。

var myWin = null;

chrome.app.runtime.onLaunched.addListener(function() {
  chrome.app.window.create('sandboxed.html', {
    'bounds': {
      'width': 400,
      'height': 400
    }
  }, function(win) {
       myWin = win;
       myWin.contentWindow.postMessage('Just wanted to say hey.', '*');
     });
});

ウェブでは一般的に、メッセージの送信元の正確な送信元を指定する必要があります。Chrome アプリはサンドボックス化されたコンテンツの一意の生成元にはアクセスできないため、すべてのオリジンを許可オリジン(「*」)として許可リストに登録することしかできません。受信側では通常、オリジンを確認しますが、Chrome アプリのコンテンツが含まれているためその必要はありません。詳しくは、window.postMessage をご覧ください。

メッセージを聞いて返信

次に、サンドボックス化されたページに追加するメッセージ受信者の例を示します。

var messageHandler = function(event) {
  console.log('Background script says hello.', event.data);

  // Send a reply
  event.source.postMessage(
      {'reply': 'Sandbox received: ' + event.data}, event.origin);
};

window.addEventListener('message', messageHandler);

詳しくは、sandboxのサンプルをご覧ください。