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

Eiji Kitamura
Eiji Kitamura

一般に、データをキャッシュに保存することでパフォーマンスを改善できます。これにより、同じデータに対する今後のリクエストを迅速に処理できます。たとえば、ネットワークからリソースをキャッシュに保存することで、サーバーへのラウンド トリップを回避できます。キャッシュに保存された計算結果により、同じ計算を実行する時間を短縮できます。

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)がリクエストされます。ブラウザは、画像 URL をキーとして使用して、HTTP キャッシュをチェックし、このリソースがすでにキャッシュに保存されているかどうかを確認します。ブラウザはキャッシュで一致を見つけると、リソースのキャッシュ バージョンを使用します。

キャッシュキー: 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 に似た識別子を保存できます。

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

キャッシュ パーティショニングによって Chrome の HTTP キャッシュにどのような影響がありますか?

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

前の例で、キャッシュ パーティショニングがさまざまなコンテキストでどのように機能するかを確認してください。

キャッシュキー { https://a.example、https://a.example、https://x.example/doge.png}
キャッシュキー: { https://a.examplehttps://a.examplehttps://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.examplehttps://b.examplehttps://x.example/doge.png }

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

画像がネットワークからリクエストされ、https://b.examplehttps://b.examplehttps://x.example/doge.png で構成されるタプルを使用してキーとしてキャッシュに保存されます。

キャッシュキー { https://a.example、https://a.example、https://x.example/doge.png}
キャッシュキー: { https://a.examplehttps://a.examplehttps://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.examplehttps://c.examplehttps://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.examplehttps://c.examplehttps://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.examplehttps://c.examplehttps://x.example/doge.png }

iframe が複数回ネストされている場合はどうなりますか?ユーザーが https://a.example にアクセスします。そこでは iframe(https://b.example)が埋め込まれ、さらに別の 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/ に戻り、[ロギングを停止] を押します。
  5. https://netlog-viewer.appspot.com/#import に移動します。
  6. [Choose File] を押して、保存したログファイルを渡します。

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

同じページで 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 とフレーム scheme://eTLD+1 を使用
  • Safari: トップレベル eTLD+1 を使用
  • Firefox: トップレベル スキーム://eTLD+1 で実装を計画し、Chrome などの 2 つ目のキーを含めることを検討中

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

専用のワーカーは現在のフレームと同じ鍵を使用します。Service Worker と共有ワーカーは、複数のトップレベル サイト間で共有される場合があるため、より複雑です。そうしたソリューションについては現在検討中です。

関連情報