キャッシュをパーティショニングすることでセキュリティとプライバシーを確保

一般的に、キャッシュにデータを保存すると、同じデータに対する今後のリクエストがより速く処理されるため、パフォーマンスが向上します。たとえば、ネットワークからキャッシュに保存されたリソースを使用すると、サーバーへのラウンドトリップを回避できます。キャッシュに保存された計算結果を使用すると、同じ計算を行う時間を省略できます。

Chrome では、キャッシュ メカニズムがさまざまな方法で使用されています。HTTP キャッシュはその一例です。

Chrome の HTTP キャッシュの現在の仕組み

バージョン 85 以降の Chrome では、ネットワークから取得したリソースをキャッシュに保存し、それぞれのリソース URL をキャッシュキーとして使用します。(キャッシュキーは、キャッシュに保存されたリソースを識別するために使用されます)。

次の例は、1 つの画像が 3 つの異なるコンテキストでキャッシュに保存され、どのように処理されるかを示しています。

キャッシュキー: https://x.example/doge.png
キャッシュキー: { https://x.example/doge.png }

ユーザーが画像(https://x.example/doge.png)をリクエストするページ(https://a.example)にアクセスします。画像はネットワークからリクエストされ、https://x.example/doge.png をキーとしてキャッシュに保存されます。

キャッシュキー: https://x.example/doge.png
キャッシュキー: { https://x.example/doge.png }

同じユーザーが別のページ(https://b.example)にアクセスし、同じ画像(https://x.example/doge.png)をリクエストします。ブラウザは HTTP キャッシュをチェックし、画像の URL をキーとして、このリソースがすでにキャッシュに保存されているかどうかを確認します。ブラウザはキャッシュ内で一致を見つけたため、キャッシュに保存されているバージョンのリソースを使用します。

キャッシュキー: https://x.example/doge.png
キャッシュキー: { https://x.example/doge.png }

画像が iframe 内から読み込まれているかどうかは関係ありません。ユーザーが iframe(https://d.example)を含む別のウェブサイト(https://c.example)にアクセスし、iframe が同じ画像(https://x.example/doge.png)をリクエストした場合、キャッシュキーはすべてのページで同じであるため、ブラウザはキャッシュから画像を読み込むことができます。

このメカニズムは、パフォーマンスの観点から長い間うまく機能してきました。ただし、ウェブサイトが HTTP リクエストに応答するまでの時間から、ブラウザが過去に同じリソースにアクセスしたことが判明する可能性があります。これにより、ブラウザが次のようなセキュリティ攻撃やプライバシー攻撃の対象になる可能性があります。

  • ユーザーが特定のサイトにアクセスしたかどうかを検出する: 攻撃者は、キャッシュに特定のサイトまたはサイトのコホートに固有のリソースが含まれているかどうかを確認することで、ユーザーのブラウジング履歴を検出できます。
  • クロスサイト検索攻撃: 攻撃者は、特定のウェブサイトで使用されている「検索結果なし」の画像がブラウザのキャッシュに存在するかどうかを確認することで、任意の文字列がユーザーの検索結果に含まれているかどうかを検出できます。
  • クロスサイト トラッキング: キャッシュを使用して、クロスサイト トラッキング メカニズムとして Cookie のような ID を保存できます。

これらのリスクを軽減するため、Chrome 86 以降、HTTP キャッシュがパーティショニングされるようになります。

キャッシュ パーティショニングは Chrome の HTTP キャッシュにどのように影響しますか?

キャッシュ パーティショニングが行われる際、キャッシュに保存されるリソースには、リソース URL に新しい「ネットワーク分離キー」を加えたキーが付与されます。ネットワーク分離キーは、トップレベル サイトと現在のフレーム サイトで構成されます。

前述の例をもう一度見てみましょう。さまざまなコンテキストでキャッシュ パーティショニングがどのように機能するかを確認します。

キャッシュキー { https://a.example, https://a.example, https://x.example/doge.png}
キャッシュキー: { https://a.example, https://a.example, https://x.example/doge.png }

ユーザーが画像(https://x.example/doge.png)をリクエストするページ(https://a.example)にアクセスします。この場合、画像はネットワークからリクエストされ、https://a.example(最上位サイト)、https://a.example(現在のフレームサイト)、https://x.example/doge.png(リソース URL)からなるタプルをキーとしてキャッシュに保存されます。(リソース リクエストが最上位フレームからのものである場合、ネットワーク アイソレーション キーの最上位サイトと現在のフレームサイトは同じです)。

キャッシュキー { https://a.example, https://a.example, https://x.example/doge.png}
キャッシュキー: { https://b.example, https://b.example, https://x.example/doge.png }

同じユーザーが別のページ(https://b.example)にアクセスし、同じ画像(https://x.example/doge.png)をリクエストします。前の例では同じ画像が読み込まれましたが、キーが一致しないため、キャッシュヒットにはなりません。

イメージはネットワークからリクエストされ、https://b.examplehttps://b.examplehttps://x.example/doge.png からなるタプルをキーとしてキャッシュに保存されます。

キャッシュキー { https://a.example, https://a.example, https://x.example/doge.png}
キャッシュキー: { https://a.example, https://a.example, https://x.example/doge.png }

ユーザーは https://a.example に戻りますが、今回は画像(https://x.example/doge.png)が iframe に埋め込まれています。この場合、キーは https://a.examplehttps://a.examplehttps://x.example/doge.png を含むタプルであり、キャッシュ ヒットが発生します。(トップレベルのサイトと iframe が同じサイトの場合は、トップレベルのフレームでキャッシュに保存されたリソースを使用できます)。

キャッシュキー { https://a.example, https://a.example, https://x.example/doge.png}
キャッシュキー: { https://a.example, https://c.example, https://x.example/doge.png }

ユーザーは https://a.example に戻りますが、今回は画像は https://c.example の iframe でホストされています。

この場合、https://a.examplehttps://c.examplehttps://x.example/doge.png で構成されるキーに一致するリソースがキャッシュにないため、イメージはネットワークからダウンロードされます。

キャッシュキー { https://a.example, https://a.example, https://x.example/doge.png}
キャッシュキー: { https://a.example, https://c.example, https://x.example/doge.png }

ドメインにサブドメインまたはポート番号が含まれている場合はどうなりますか?ユーザーが https://subdomain.a.example にアクセスすると、iframe(https://c.example:8080)が埋め込まれ、画像がリクエストされます。

キーは「scheme://eTLD+1」に基づいて作成されるため、サブドメインとポート番号は無視されます。したがって、キャッシュ ヒットが発生します。

キャッシュキー { https://a.example, https://a.example, https://x.example/doge.png}
キャッシュキー: { https://a.example, https://c.example, https://x.example/doge.png }

iframe が複数回ネストされている場合はどうなりますか?ユーザーが https://a.example にアクセスすると、iframe(https://b.example)が埋め込まれます。この iframe にはさらに別の iframe(https://c.example)が埋め込まれ、最終的に画像がリクエストされます。

キーはトップフレーム(https://a.example)とリソースを読み込む直前のフレーム(https://c.example)から取得されるため、キャッシュ ヒットが発生します。

よくある質問

Chrome ですでに有効になっていますか?どうすれば確認できますか?

この機能は 2020 年後半にリリースされる予定です。Chrome インスタンスがすでにサポートしているかどうかを確認する手順は次のとおりです。

  1. chrome://net-export/ を開き、[ディスクへのログ記録を開始] を押します。
  2. パソコンにログファイルを保存する場所を指定します。
  3. Chrome で 1 分間ウェブを閲覧します。
  4. chrome://net-export/ に戻り、[Stop Logging] を押します。
  5. https://netlog-viewer.appspot.com/#importに向かいます。
  6. [ファイルを選択] を押して、保存したログファイルを渡します。

ログファイルの出力が表示されます。

同じページで SplitCacheByNetworkIsolationKey を見つけます。Experiment_[****] が続いている場合は、Chrome で HTTP キャッシュ パーティショニングが有効になっています。Control_[****] または Default_[****] が続く場合は、有効になりません。

Chrome で HTTP キャッシュ パーティショニングをテストするにはどうすればよいですか?

Chrome で HTTP キャッシュ パーティショニングをテストするには、コマンドライン フラグ --enable-features=SplitCacheByNetworkIsolationKey を使用して Chrome を起動する必要があります。ご利用のプラットフォームでコマンドライン フラグを使用して Chrome を起動する方法については、フラグを使用して Chromium を実行するの手順をご覧ください。

ウェブ デベロッパーとして、この変更に対応するために必要な対応はありますか?

これは互換性を破る変更ではありませんが、一部のウェブサービスではパフォーマンスに関する考慮事項が生じる可能性があります。

たとえば、多くのサイトにキャッシュに保存しやすいリソース(フォントや一般的なスクリプトなど)を大量に提供するサイトでは、トラフィックが増加する可能性があります。また、このようなサービスを利用するユーザーは、それらのサービスに依存するようになる可能性があります。

ウェブ共有ライブラリプレゼンテーション動画)という、プライバシーを保護しながら共有ライブラリを有効にする提案がありますが、まだ検討中です)。

この動作の変更による影響

全体的なキャッシュ ミス率は約 3.6% 増加し、FCP(First Contentful Paint)の変化はわずか(約 0.3%)で、ネットワークから読み込まれるバイトの割合は全体で約 4% 増加します。パフォーマンスへの影響の詳細については、HTTP キャッシュ パーティショニングの説明をご覧ください。

これは標準化されていますか?他のブラウザでは動作が異なりますか?

「HTTP キャッシュ パーティション」はフェッチ仕様で標準化されていますが、ブラウザによって動作が異なります。

  • Chrome: トップレベル スキーム://eTLD+1 とフレーム スキーム://eTLD+1 を使用
  • Safari: トップレベルの eTLD+1 を使用
  • Firefox: トップレベル スキーマ://eTLD+1 で実装を計画中。Chrome のような 2 つ目のキーを含めることを検討中

ワーカーからの取得はどのように処理されますか?

専用ワーカーは、現在のフレームと同じキーを使用します。Service Worker と共有ワーカーは、複数のトップレベル サイト間で共有される可能性があるため、より複雑です。解決策については現在検討中です。

リソース