ウェブ デベロッパー向けのサイト分離

パソコン版 Chrome 67 では、サイト分離という新機能がデフォルトで有効になっています。この記事では、サイト分離の概要と必要性、ウェブ デベロッパーがサイト分離に注意すべき理由について説明します。

サイト分離とは

インターネットは、猫の動画の視聴や暗号通貨ウォレットの管理などに使用できますが、貴重な暗号通貨を fluffycats.example がアクセスできないようにする必要があります。幸いなことに、同一オリジン ポリシーにより、ウェブサイトはブラウザ内で互いのデータにアクセスすることはできません。それでも、悪意のあるウェブサイトがこのポリシーを回避して他のウェブサイトを攻撃する可能性があり、場合によっては、同一オリジン ポリシーを適用するブラウザコードにセキュリティ バグが見つかることがあります。Chrome チームは、このようなバグをできるだけ早く修正することを目指しています。

サイト分離は、このような攻撃が成功しにくくなる追加の防御策を提供する Chrome のセキュリティ機能です。さまざまなウェブサイトのページが常に異なるプロセスに配置され、各プロセスがサンドボックス内で実行され、プロセスの実行が制限されます。また、プロセスが他のサイトから特定の種類の機密データを受信できないようにブロックします。そのため、サイト分離を使用することで、悪意のあるウェブサイトが Spectre などの投機的サイドチャネル攻撃を使用して他のサイトからデータを盗むことは、はるかに困難になります。Chrome チームが追加の適用を完了すると、攻撃者のページがそのプロセスの中で一部のルールを破る可能性がある場合でも、サイト分離が役立ちます。

サイト分離により、信頼できないウェブサイトが他のウェブサイト上のアカウントから情報にアクセスしたり情報を盗んだりすることが効果的に困難になります。これにより、最近の Meltdown や Spectre のサイドチャネル攻撃など、さまざまな種類のセキュリティ バグに対する保護が強化されます。

サイト分離について詳しくは、Google セキュリティ ブログの記事をご覧ください。

クロスオリジン読み取りブロック

すべてのクロスサイト ページが個別のプロセスに配置されている場合でも、ページは画像や JavaScript などのクロスサイト サブリソースを合法的にリクエストできます。悪意のあるウェブページが <img> 要素を使用して、銀行残高などの機密データを含む JSON ファイルを読み込むおそれがあります。

<img src="https://your-bank.example/balance.json" />
<!-- Note: the attacker refused to add an `alt` attribute, for extra evil points. -->

サイト分離を使用しないと、JSON ファイルの内容がレンダラ プロセスのメモリに送られ、レンダラは有効な画像形式ではないことに気づき、画像をレンダリングしません。しかし、攻撃者は Spectre などの脆弱性を悪用して、そのメモリチャンクを読み取ることができます。

攻撃者は、<img> を使用する代わりに、<script> を使用して機密データをメモリに commit することもできます。

<script src="https://your-bank.example/balance.json"></script>

クロスオリジン読み取りブロック(CORB)は、MIME タイプに基づいて、balance.json のコンテンツがレンダラ プロセスのメモリに入らないようにする新しいセキュリティ機能です。

CORB の仕組みを詳しく見ていきましょう。ウェブサイトは、次の 2 種類のリソースをサーバーにリクエストできます。

  1. HTML、XML、JSON ドキュメントなどのデータリソース
  2. メディア リソース(画像、JavaScript、CSS、フォントなど)

ウェブサイトが、自身のオリジンまたは制限の緩い CORS ヘッダー(Access-Control-Allow-Origin: * など)を持つ他のオリジンからデータリソースを受信できる。一方、メディア リソースは、制限が緩やかな CORS ヘッダーがなくても、どのオリジンからでも含めることができます。

CORB は、次の場合、レンダラ プロセスがクロスオリジン データリソース(HTML、XML、JSON など)を受信できないようにします。

  • リソースに X-Content-Type-Options: nosniff ヘッダーがある
  • CORS はリソースへのアクセスを明示的に許可しない

クロスオリジン データリソースに X-Content-Type-Options: nosniff ヘッダーが設定されていない場合、CORB はレスポンスの本文を盗聴して、HTML、XML、JSON のどれであるかを判断しようとします。たとえば、一部のウェブサーバーが正しく構成されておらず、画像を text/html として提供するため、これが必要となります。

CORB ポリシーによってブロックされたデータリソースは、空としてプロセスに提示されますが、リクエストは引き続きバックグラウンドで発生します。その結果、悪意のあるウェブページがクロスサイト データを pull して盗むことは困難です。

セキュリティを最適化し、CORB を活用するには、次のことをおすすめします。

  • レスポンスに正しい Content-Type ヘッダーを付加します。(たとえば、HTML リソースは text/htmlJSON MIME タイプの JSON リソース、XML MIME タイプの XML リソースとして提供する必要があります)。
  • X-Content-Type-Options: nosniff ヘッダーを使用してスニッフィングを無効にします。このヘッダーがないと、Chrome は迅速なコンテンツ分析を行い、タイプが正しいことを確認します。ただし、これは JavaScript ファイルなどをブロックしないようにレスポンスを許可する側にエラーが起きるので、積極的に正しいことをする方が賢明です。

詳しくは、ウェブ デベロッパー向けの CORB に関する記事または CORB の詳細な説明をご覧ください。

ウェブ デベロッパーがサイト分離を考慮すべき理由

サイト分離はほとんどがバックグラウンドのブラウザ機能であり、ウェブ デベロッパーには直接公開されません。たとえば、ウェブに公開する新しい API について学習する必要はありません。一般的に、ウェブページはサイト分離の有無にかかわらず、その違いを認識できません。

ただし、この規則にはいくつかの例外があります。サイト分離を有効にすると、ウェブサイトに影響する可能性がある微妙な副作用が伴います。Google では、サイト分離に関する既知の問題のリストを管理しており、特に重要な問題について以下で詳しく説明しています。

全画面レイアウトが同期されないようになりました

サイト分離を使用すると、ページのフレームが複数のプロセスに分散される可能性があるため、ページ全体のレイアウトの同期が保証されなくなります。レイアウト変更がページ上のすべてのフレームにすぐに反映されると想定している場合は、ページに影響する可能性があります。

例として、social-widget.example でホストされているソーシャル ウィジェットと通信する fluffykittens.example という名前のウェブサイトについて考えてみましょう。

<!-- https://fluffykittens.example/ -->
<iframe src="https://social-widget.example/" width="123"></iframe>
<script>
  const iframe = document.querySelector('iframe');
  iframe.width = 456;
  iframe.contentWindow.postMessage(
    // The message to send:
    'Meow!',
    // The target origin:
    'https://social-widget.example'
  );
</script>

最初は、ソーシャル ウィジェットの <iframe> の幅は 123 ピクセルです。しかし、FluffyKittens のページが幅を 456 ピクセルに変更し(レイアウトをトリガー)、次のコードを含むソーシャル ウィジェットにメッセージを送信します。

<!-- https://social-widget.example/ -->
<script>
  self.onmessage = () => {
    console.log(document.documentElement.clientWidth);
  };
</script>

ソーシャル ウィジェットは、postMessage API を介してメッセージを受信するたびに、ルート <html> 要素の幅をログに記録します。

ログに記録される幅の値はどれですか。Chrome でサイト分離を有効にする前は、正解は「456」でした。document.documentElement.clientWidth にアクセスすると、レイアウトが強制されます。Chrome でサイト分離を有効にする前は、同期していました。ただし、サイト分離を有効にすると、クロスオリジン ソーシャル ウィジェットの再レイアウトが別のプロセスで非同期に行われるようになりました。そのため、回答は 123(古い width 値)にすることもできます。

ページがクロスオリジンの <iframe> のサイズを変更してから postMessage を送信した場合、サイト分離により、メッセージの受信時に受信フレームが新しいサイズをまだ認識していない可能性があります。一般的に、レイアウトの変更がページ上のすべてのフレームにすぐに反映されると想定している場合、ページが中断される可能性があります。

この特定の例では、より堅牢なソリューションとして、親フレームに width を設定し、resize イベントをリッスンすることで <iframe> の変更を検出します。

アンロード ハンドラがタイムアウトする頻度が高くなることがある

フレームが移動するか閉じると、古いドキュメントとそれに埋め込まれたサブフレーム ドキュメントはすべて unload ハンドラを実行します。新しいナビゲーションが同じレンダラ プロセスで発生する場合(同一オリジン ナビゲーションの場合など)、古いドキュメントとそのサブフレームの unload ハンドラは、新しいナビゲーションが commit されるまでの任意の時間にわたって実行できます。

addEventListener('unload', () => {
  doSomethingThatMightTakeALongTime();
});

この場合は、すべてのフレームの unload ハンドラの信頼性が非常に高くなります。

ただし、サイト分離がなくても、一部のメインフレーム ナビゲーションはプロセス間となり、アンロード ハンドラの動作に影響します。たとえば、アドレスバーに URL を入力して old.example から new.example に移動すると、new.example ナビゲーションは新しいプロセスで行われます。old.example とそのサブフレームのアンロード ハンドラは、new.example ページが表示された後に、バックグラウンドで old.example プロセス内で実行されます。古いアンロード ハンドラは、特定のタイムアウト時間内に完了しない場合に終了します。アンロード ハンドラがタイムアウトまでに完了しない可能性があるため、アンロード動作の信頼性が低下します。

サイト分離を使用すると、すべてのクロスサイト ナビゲーションがクロスプロセスになるため、異なるサイトのドキュメント間でプロセスが共有されることはありません。その結果、上記の状況はより多くのケースに当てはまります。多くの場合、<iframe> のアンロード ハンドラには、上記のバックグラウンドとタイムアウトの動作があります。

サイト分離に起因するもう一つの違いは、アンロード ハンドラの新しい並列順序です。サイト分離を使用しない場合、アンロード ハンドラはフレームをまたいで厳密な上から順に実行されます。しかしサイト分離を使用すると、アンロード ハンドラは異なるプロセス間で並行して実行されます。

これらは、サイト分離を有効にした場合の基本的な結果です。Chrome チームは、一般的なユースケースに対するアンロード ハンドラの信頼性を可能な限り改善に取り組んでいます。また、サブフレーム アンロード ハンドラがまだ特定の機能を利用できず、解決に取り組んでいます。

アンロード ハンドラの重要なケースとして、セッション終了の ping を送信します。これは、一般的に次のように行われます。

addEventListener('pagehide', () => {
  const image = new Image();
  img.src = '/end-of-session';
});

この変更に照らして、より堅牢な方法としては、代わりに navigator.sendBeacon を使用する方法があります。

addEventListener('pagehide', () => {
  navigator.sendBeacon('/end-of-session');
});

リクエストをより詳細に制御する必要がある場合は、Fetch API の keepalive オプションを使用できます。

addEventListener('pagehide', () => {
  fetch('/end-of-session', {keepalive: true});
});

おわりに

サイト分離は、各サイトを独自のプロセスに分離することで、信頼できないウェブサイトが他のウェブサイトのアカウントにアクセスしたり、情報を盗んだりしにくくします。その一環として、CORB は機密データリソースをレンダラ プロセスから排除しようとします。上記の推奨事項によって、これらの新しいセキュリティ機能を最大限に活用できます。

この記事の下書き版を読んでフィードバックをお寄せくださった Alex Moshchuk、Charlie Reis、Jason Miller、Nasko Oskov、Philip Walton、Shubhie Panicker、Thomas Steiner に感謝いたします。