問題と判断基準
IXC Insights Editorial · 技術確認基準日:2026年9月26日
商品画面の高速化のためにCDNキャッシュを有効にしたところ、ログインした顧客に別の顧客の契約価格が表示されたと仮定します。同じ商品URLという理由で応答を共用したものの、実際の価格は顧客ごとに異なっていた設計例です。最初に調べるべきなのはキャッシュヒット率ではなく、どのリクエスト同士なら同じ応答を受け取ってよいかです。
本稿では、次の区分を出発点にします。公開静的アセットと誰にでも同じ公開コンテンツを共有キャッシュの候補にし、個人情報・顧客企業別データ・認証状態を含む応答はまず除外します。公開価格・在庫・検索結果は、許容する情報の遅延と応答が変わる条件を決めてから判断します。動的に生成したという理由だけでキャッシュできないわけではありません。HTTPキャッシュが扱うのは応答の保存・再利用条件であり、静的ファイルかどうかだけでは安全性を決められません。[1]
運用上は、同じキャッシュキーに入るリクエストを、権限・本文・応答ヘッダー・許容する鮮度の面で相互に置き換えられるかを問うことが役立ちます。説明が難しければ、TTLを延ばす前に応答を分離するか共有キャッシュを無効にするところから始めます。
ブラウザーに残すことと他の利用者に共有することは異なる
ブラウザーのプライベートキャッシュとCDNの共有キャッシュでは利用範囲が異なります。Cache-Controlも「保存できるか」と「保存したものをいつ再利用できるか」を分けて読みます。以下は、フィールド名を指定しない一般的な応答ディレクティブの意味です。[1]
| 応答ディレクティブ | 保存・再利用の意味 | 混同しやすい点 |
|---|---|---|
private | 共有キャッシュには保存しません。プライベートキャッシュには保存できます。 | ブラウザーにも残すなという意味ではありません。 |
no-store | プライベート・共有HTTPキャッシュに、このリクエスト・応答を保存しないよう指示します。 | すでに存在するすべてのコピーを遠隔削除する命令ではありません。 |
no-cache | 保存は可能ですが、再利用前にオリジンでの再検証に成功する必要があります。 | 名前とは異なり、保存禁止ではありません。 |
max-ageは新鮮と扱う期間を表します。s-maxageは共有キャッシュに適用され、そこではmax-ageより優先されます。鮮度の期限切れと物理的な即時削除は異なります。 期限切れのオブジェクトを再検証したり、特定条件で再利用したりできるため、TTLが0という説明だけを保存禁止と解釈してはいけません。[3]
この区分もHTTPキャッシュの範囲です。サーバー内のデータキャッシュ、アプリケーションが保持する画面状態、ブラウザーの閲覧履歴は別に点検します。HTTP標準も閲覧履歴とキャッシュを区別しています。ログアウト後に画面を消す要件を、ヘッダー1つで満たしたと判断しないことが必要です。[1]
コンテンツに合わせて配信経路を設計 — ファイルの更新方法に応じてキャッシュを分け、エッジ配信の結果とオリジン負荷を監視します。
応答別のポリシー表から作る
次の表は編集者が作成した設計例です。顧客事例や実行結果ではなく、数値も比較のための仮定であり推奨する最適値ではありません。基本の対象は参照用のGET応答です。注文の作成・変更など状態を変更するリクエストに、この表をそのまま適用しません。
表で共通するキーの出発点はリクエストメソッドと対象URLです。実際のCDNのキー構成と正規化は別途確認します。「CDNで30秒」は鮮度ポリシーの目標であり、その間オブジェクトが必ず保持されるという保証ではありません。[1]
| 応答の種類 | 共有可否・ブラウザーポリシー | 応答を分ける条件・キー | TTL・鮮度の仮定 | 無効化・切り替えの契機 | オリジン障害時の設計 |
|---|---|---|---|---|---|
| バージョン付きの公開JS・CSS・画像 | 共有可、ブラウザー保存可 | コンテンツのバージョンを含むURL、必要な表現形式 | CDN・ブラウザーで30日 | 変更時は新URL。セキュリティ上撤回するファイルは別途遮断・無効化 | 撤回されていない同一バージョンに限り、期限切れ後さらに24時間の提供を検討 |
| 匿名利用者に同じ内容を返す公開記事・一覧 | 条件付きで共有、ブラウザーは再利用前に再検証 | 言語、ページ、公開フィルターなど実際の差分条件 | CDNで60秒 | 修正・削除・非公開化の際に関連一覧も無効化 | 期限切れ後の追加提供は許可しない |
| ログイン処理・トークン発行・アカウント別リダイレクト | 共有対象外、ブラウザーはno-store | セッション・認証状態に依存。共通オブジェクトに統合しない | 保存しない | セッションの作成・置換・終了。過去のキャッシュがあれば削除 | 成功応答や別セッションの応答で置き換えない |
| 個人の注文・プロフィール・支払い手段の参照 | 共有対象外、ブラウザーはno-store | 認証済み利用者とオブジェクトへのアクセス権限 | 保存しない | ログアウト・権限変更・データ修正 | 古い個人応答の代わりにエラーまたは再試行を案内 |
| 顧客企業別ダッシュボード・契約価格 | 原則共有対象外、ブラウザーはno-store | 検証済みtenant・利用者・ロール・オブジェクト範囲 | 保存しない | 所属企業の移動・ロール変更・契約変更 | 以前の権限の応答で迂回しない |
| 誰でも見られる表示用価格 | 条件付きで共有、ブラウザーは再利用前に再検証 | 商品・通貨・販売市場・価格表示条件 | CDNで30秒 | 価格公開・プロモーション変更 | 期限切れ後の追加提供禁止。注文確定時に正となる価格を再確認 |
| 公開在庫案内 | 条件付きで共有、ブラウザーは再利用前に再検証 | 商品・公開地域・在庫照会単位 | CDNで5秒 | 入出庫・売り切れ・販売停止 | 期限切れ後は確認不可と表示。予約・在庫減算の判断には使わない |
| 匿名の公開検索結果 | 条件付きで共有、ブラウザーは再利用前に再検証 | 検索語・フィルター・並び順・ページ・言語 | CDNで10秒 | インデックス変更・公開範囲変更 | 期限切れ後の追加提供禁止。個人化された検索・機微な検索は別途除外 |
ログイン画面も区別が必要です。セッション情報をまったく含まない共通の画面枠や公開画像には、前述の公開コンテンツのポリシーを適用できます。一方、同じ画面にワンタイムトークン、利用者名、アカウント別の移動先が含まれるなら、「ログインページ」という名称だけで1つのポリシーにまとめません。
価格と在庫は、画面表示で許容する遅延と取引判断で許容する遅延を分けて合意する方が安全です。上の例は表示用の参照だけを共有する設計です。注文確定や在庫減算までキャッシュされた照会結果に任せる設計ではありません。顧客別の割引が混ざった時点で、公開価格の行から個人・顧客企業別の行へ移します。
CDNに保存した直後の応答でも、アプリケーションが古いデータスナップショットから生成したなら業務上の最新情報ではありません。ポリシーの検討では、CDNのTTLに加えオリジンデータの更新、非同期の反映、無効化の遅延も記載します。短いTTLに対応しない場合や変更の伝播が要件を満たさない場合は、その応答をキャッシュ対象から外す選択肢も残します。
キーに含めるものは応答が変わる理由から決める
保存済みの応答はキャッシュキーで探します。Varyは応答の選択に影響するリクエストヘッダーを示す標準の仕組みです。[2] 設計ではURLだけでなく、クエリ、言語、通貨、Cookie、認証状態、顧客企業の識別情報のうち何が実際の応答を変えるのかを追います。
例えば通貨Cookieを読んで価格を変える一方、キャッシュをURLだけで区別すると、同じURLで異なる価格が必要という事実がキーに反映されません。逆に、応答に影響しない追跡用の値をすべてキーに入れることも、最初に選ぶ理由はありません。オリジンとCDNが同じリクエストを同じように解釈するかを検証したうえで、必要な差分だけを残す方法が適切です。
ここで、オリジンへ転送する値とキャッシュキーに含める値は同じとは限りません。 CloudFrontはキャッシュポリシーに含めた値をオリジンにも転送しますが、別のオリジンリクエストポリシーでキーに含めない値を転送することもできます。[4] 「サーバーまで顧客企業のヘッダーが届く」と確認しただけでは、企業別にキャッシュが分かれていると結論できません。
顧客企業の識別子をキーに含めても、権限検査の代わりにはなりません。本稿の基本案が企業別応答を共有キャッシュから除外する理由です。認証を伴う共有キャッシュを別途設計するなら、少なくともキャッシュHITの応答を返す前に検証済みのアクセス条件を適用し、同じ企業内のロール差や権限撤回も処理する必要があります。送信者が指定した企業文字列を信用したり、トークンをキーに追加したりするだけで検討を終えません。
Varyは製品の現在の対応方法まで確認する
Cloudflareは2026年7月2日にCache RulesのVary対応を発表しました。 現行文書は、キャッシュルールで有効にし、オリジンがVaryを返す条件を説明しています。過去の資料にある「CloudflareはVaryを無視する」という説明を無条件に適用することも、ヘッダーを追加すればすべての構成で自動的に分かれると考えることも適切ではありません。[5][6]
選択したヘッダーをそのまま区別するか、正規化するか、その応答をキャッシュから除外するかは、オリジンの応答生成方式に合わせます。特に言語・形式の値を正規化するときは、統合されるリクエストが実際に同じ表現を受け取ってよいかを確認します。機能がサポートされていることと、現在のデプロイに正しく適用されていることは別です。
オリジンのヘッダーより優先されるCDN設定を調べる
ブラウザーでCache-Control: privateを確認しても、CDN内の保存ポリシーまで確認できたわけではありません。以下は2026年9月26日に公式文書で確認した、異なる構成要素の例です。2製品の性能比較でも、同じ設定同士の比較でもありません。
| 確認する構成 | 公式文書上の注意点 | 変更前に確認すること |
|---|---|---|
| Cloudflare Cache RulesのEdge TTL | オリジンのCache-Controlを無視して指定TTLを使う選択肢があります。[7] | 実際に一致する範囲、オリジンヘッダーの尊重、後続のルールとエッジコード |
| CloudFrontのキャッシュポリシー | Minimum TTLが0より大きいと、オリジンのno-cache・no-store・privateがあっても、その期間キャッシュできます。[4] | 対象パスに関連付けられたポリシーの3つのTTL値とキャッシュキー |
CloudFrontの管理ポリシーCachingOptimized | Minimum TTLは1秒で、Cookieとクエリ文字列はキーに含まれません。[8] | 個人化されたHTML・APIにこのポリシーを広く関連付けていないか |
CloudFrontはMinimum・Default・Maximum TTLをすべて0にするとキャッシュが無効になると説明しています。管理ポリシーのCachingDisabledも3値を0にしています。[4][8] ただし無効化後も、認証など必要なリクエスト情報がオリジンへ転送されるかは別のポリシーで確認します。
Cloudflareを使う場合は、リクエスト段階だけでなく応答段階の変更も調べます。Cache Response Rulesはキャッシュに入る前にCache-ControlやSet-Cookieなどのヘッダーを変更できます。[5] クライアントに見えるヘッダー、キャッシュ判断に使われたヘッダー、最終的に一致したルールをまとめて確認する理由です。
この表は、そのままコピーして運用に使う設定ではありません。アカウントのプラン、ルールの順序、パス別の関連付け、別のキャッシュ層を確認せずにグローバルルールへ移してはいけません。
認証ヘッダーとCookieを安全装置だと思い込まない
RFC 9111はAuthorizationを含むリクエストの共有キャッシュ再利用を制限しますが、public・s-maxage・must-revalidateなど明示された応答ディレクティブの条件に応じた例外も設けています。「認証ヘッダーがあるので、どの設定でも共有されない」という前提は成り立ちません。[1]
Cookieは別に考えます。CloudFrontは構成に応じてCookieを無視するか、選択したCookieをキーに反映します。Cookieをオリジンへ転送する構成では、オリジンのSet-Cookieをオブジェクトと一緒にキャッシュし、後続の応答で返す場合があると説明しています。[9] セッションを発行する応答をキャッシュに入れていないか、他の利用者に同じセッション設定が再生されないかまで確認します。
CloudflareもOrigin Cache Controlの設定とキャッシュルールによって認証・Cookieの扱いが変わります。[3] 製品名を根拠に安全と断定するより、ログイン前の最初のリクエスト、ログイン直後、ログアウト直後のリクエストと応答を個別に調べる方が適切です。
応答本文の比較だけでも不十分です。本文が同じ画面でも、Set-Cookie、アカウント別のLocation、アクセス範囲を含むメタデータは異なる場合があります。ポリシー表とテストの比較対象を、本文・ステータスコード・セキュリティ関連ヘッダーまで広げます。
サービスの前段でリクエストを分類・防御 — リクエストと遮断記録から防御ルールを調整し、証明書とアクセス制御も管理します。
再検証と障害対応でもアクセス境界を維持する
ETagによる再検証は、同じ表現が変わったかを確認するために使います。アクセス権限を代わりに判定する手段ではありません。RFC 9110は条件付きリクエストの評価前に、通常のリクエスト検査を実施するよう規定しています。[2] テスト設計では、権限を撤回された利用者のリクエストを、以前のETagだけを見て304 Not Modifiedとして処理しないか確認します。
古い応答を許可するポリシーも別に記載します。stale-while-revalidateは新しい応答を確認する間、stale-if-errorはオリジンのエラー時に、期限切れの応答を提供するために使います。[10] 公開記事では可用性のために一定の遅延を受け入れられても、撤回済みのアクセス権限や以前の契約価格まで長く維持してよいという意味ではありません。
上のポリシー表で「追加提供禁止」と決めたなら、その要件が実際のCDNのエラー・再検証ポリシーで実装されているか確認します。CloudFrontの有効期限の文書には、オリジンへの接続失敗時に、設定によって古いオブジェクトを返す場合があることも説明されています。[10] 正常時のTTL検査だけで、障害時の動作まで合格としてはいけません。
再検証を強制するディレクティブと、古い応答を許可するディレクティブをまとめて列挙することも避けます。共有キャッシュのs-maxageにはproxy-revalidateの意味も含まれるため、古い応答の許可設定との関係を確認します。競合・優先順位を利用製品の文書で調べ、実際に期待する結果を障害テストの合格条件に記載します。[3]
誤って保存した応答はヘッダー修正だけでは片付かない
保存してはいけない応答がキャッシュに入ったら、今後適用するポリシーと保存済みのオブジェクトを分けて処理します。以下は、自ら所有するか明示的な許可を受けた環境で適用範囲を決めてから実行する、防御的な復旧手順の提案です。
- 誤った再利用と再流入を先に止めます。 影響するパスを共有キャッシュから除外し、オリジンの応答ポリシーを修正します。ルールが実際に適用されたか確認します。オリジンが誤ったオブジェクトを供給し続ければ、purge後も再び保存される可能性があります。
- 以前のキーとバリエーションも含めて無効化します。 現在のキーだけでなく変更前のキー、言語・クエリ・Cookie別のバリエーション、使用中のキャッシュ層の処理範囲を確認します。Cloudflareの単一URLのpurgeには、ヘッダー・Cookieに基づくカスタムキーで制約があるため、実際のキーに合ったAPIリクエストか、適切な範囲の別のpurge方法を検討します。[11]
- CDN外のコピーと露出の影響を別に処理します。 CloudFrontのinvalidationでブラウザーや企業プロキシのコピーまで削除することはできません。[12] アプリケーションのキャッシュ・画面状態・配信済み情報の影響範囲を確認し、必要なインシデント対応につなげます。
- 内容とアクセス結果で復旧を確認します。 CloudflareのpurgeのHTTP 200はリクエスト受付を意味し、オブジェクトが実在した、あるいは削除された証拠ではありません。[13] 最新の本文バージョンと利用者の分離を再確認します。正常なオブジェクトが別のリクエストで先に保存されればHITになることもあるため、MISSだけを復旧成功条件にしません。
バージョン付きURLへの変更は公開静的アセットのデプロイに役立ちます。ただし以前のURLですでに露出した機微な応答を消したり、アクセスを撤回したりする手順の代わりにはなりません。ファイルのバージョン管理とCDN無効化の役割を分けます。[12]
2人の利用者でキャッシュの正常経路と失敗経路を確認する
以下は未実行のテスト設計例です。許可されたテスト環境で、仮想利用者AとB、異なる仮想顧客企業、合成した注文データを用意します。同じ企業内の権限差も試せるよう、別のロール条件を設けます。実際の個人情報の代わりに識別用の印をデータに入れ、ブラウザープロファイルとCookie保存領域も分離します。
| 検査 | リクエストの順序・条件 | 合格条件 |
|---|---|---|
| 公開キャッシュの正常な再利用 | 同じ公開アセットを繰り返し参照し、キャッシュが保存済みの状態も作ります。 | 許可した経路で正常な再利用が観測され、内容・バージョンが一致します。すべてを遮断した状態を成功としません。 |
| 利用者・顧客企業の分離 | 同じAPI URLにA → B、B → Aの順でリクエストします。同時リクエストも別に確認します。 | 各自に許可されたデータだけを受け取り、本文・ヘッダーに相手の印がありません。機微なパスは共有キャッシュで再利用されません。 |
| ログイン前後・セッション発行 | 匿名で参照後にログインし、新しいBのセッションでも繰り返します。 | 別セッションのSet-Cookieやアカウント別の移動先が再生されません。 |
| 同じ企業内のロール差 | 同じオブジェクトを管理者条件と制限されたロール条件で参照します。 | 同じ企業でも、許可範囲外のフィールド・オブジェクトが渡されません。 |
| 権限撤回・所属企業の移動 | 以前の応答が有効でありそうな時間内に権限を変更し、再リクエストします。条件付きリクエストも含めます。 | 過去の本文や不適切な304で以前の権限が維持されません。正当に許可される操作は引き続き可能です。 |
| ログアウト・アカウント切り替え | ログアウト後の直接再リクエスト、戻る操作、Bでログイン後の同じ画面へのアクセスを分けます。 | HTTP応答とアプリケーション画面状態の両方で、以前のアカウント情報が露出しません。 |
| クエリ・言語・通貨 | 実際の応答を変える条件を1つずつ変更し、正規化される値も比較します。 | 異なるべき応答は分離され、統合してよいリクエストだけが同じ表現を受け取ります。 |
| 期限切れ・再検証 | 期限の前後を比較し、オリジンを変更した条件と変更しない条件をそれぞれ作ります。 | 承認した鮮度・再検証ポリシーどおりに動作し、表現と検証子が混在しません。 |
| 価格・在庫の変更とpurge | オリジンの値を変更し、関連する詳細・一覧・検索を検査します。変更前のキーのオブジェクトも用意します。 | 変更前の値が許容範囲を超えて残らず、注文確定・在庫減算は正となる状態で判断します。 |
| オリジンのエラー・タイムアウト | 管理下のオリジンでエラー・接続失敗を発生させ、キャッシュの有無と期限切れを組み合わせます。 | 機微な応答が古いオブジェクトで置き換えられません。公開応答も、事前合意した期限切れ後の許容範囲を超えません。 |
| エラー・リダイレクト応答 | 成功応答に加え、アカウント別リダイレクト、401・403・404の経路を検査します。 | 別の利用者の状態が再利用されず、エラーページやヘッダーにも機微な情報がありません。 |
キャッシュ状態、応答コード、Cache-Control、Vary、Age、ETag、本文バージョン・合成の印、適用ポリシーのバージョンを一緒に記録します。実際のトークンやセッションCookieを証拠ファイルにそのまま残す必要はありません。利用者別の結果とオリジン・CDNの記録を結び付けつつ、秘密値は除外します。
キャッシュ状態の名称は製品やリクエスト経路によって異なる場合があります。1回のMISSは「保存しない」証明にならず、1回の200は「正しい利用者のデータ」の証明になりません。 異なる利用者、保存済みキャッシュ、期限切れ、無効化、オリジン障害でも期待する結果が維持されるか確認します。
転送・オリジン・切り替えの項目をまとめて調べる際は、CDN・WAF構成チェックリストを参照し、利用者の分離を検証した結果を別途追加できます。
有効化する範囲より責任を持てる範囲を先に決める
公開静的アセットだけをキャッシュし、応答・デプロイ・無効化の担当者が明確なら、小さなポリシー表と回帰検査から自分たちで運用できます。一方、顧客企業別の応答、複数のCDN・プロキシ・アプリケーションキャッシュ、頻繁な権限変更が重なる場合は、各層の担当者が同じアクセス・鮮度基準に合意する必要があります。この場合、初期のヒット率が下がっても不明確な経路を除外する選択は合理的です。
キャッシュ検討の成果物は「キャッシュを有効にした」という状態ではなく、共有する応答、分離するキー、許容する遅延、削除の契機、障害時の動作、それを立証する検査がつながったポリシーです。
共有キャッシュのデータ境界とは別に、オリジンへの接続経路を保護する課題は、CDNとWAFを導入してもオリジンサーバーが露出する理由と防ぎ方で扱います。
外部支援を検討する場合は、IXC CDNサービスの支援範囲を確認し、キャッシュポリシー・無効化・検証のうち必要なレビュー範囲を具体的に相談できます。



