Retrieved from Cache

概要

  • 脆弱性の名前: Retrieved from Cache (キャッシュからの取得)
  • どんな問題か: Webサーバーが返すHTTPレスポンスがキャッシュから取得された場合に、意図しない情報漏洩や古いコンテンツの表示が発生する可能性がある状態。
  • よくある発生シーン: キャッシュヘッダーの設定ミス、機密情報を含むページのキャッシュ制御の欠如、CDN (Content Delivery Network) の設定ミス。

背景

  • 問題視されるようになった背景: Webサイトのパフォーマンス改善のためにキャッシュが広く利用されている一方で、キャッシュの設定が不適切であると、セキュリティ上のリスクが生じるため。
  • クラウド設計や設定ミスによる実例: クラウド環境でCDNを使用している場合、Cache-Controlディレクティブの設定が誤っていると、本来キャッシュすべきでない機密情報がCDNにキャッシュされてしまうことがある。

セキュリティ上のリスク

  • どんな攻撃に悪用されるか:
    • 情報漏洩: 機密情報を含むページがキャッシュに保存され、意図しないユーザーに情報が漏洩する可能性がある。
    • 認証バイパス: 認証済みのユーザーのページがキャッシュに保存され、他のユーザーが認証なしにアクセスできる可能性がある。
    • セッション情報の漏洩: セッションIDを含むページがキャッシュに保存され、攻撃者がセッションIDを入手することで、ユーザーのセッションを乗っ取ることができる。
    • 個人情報の第三者アクセス: 個人情報を含むページがキャッシュに保存され、第三者が個人情報にアクセスできる可能性がある。
    • 古いコンテンツの表示: キャッシュの有効期限が切れていない場合、古いコンテンツが表示され、ユーザーが誤った情報を受け取る可能性がある。
  • 実被害が出た具体的なインシデント: 具体的なインシデントは特定できませんでしたが、過去には、ECサイトで顧客のクレジットカード情報がキャッシュに保存され、他のユーザーが閲覧できる状態になった事例が報告されています。

対処方法の具体例

Apache2での対処

# .htaccess
<IfModule mod_headers.c>
    Header set Cache-Control "no-store, no-cache, must-revalidate, max-age=0"
    Header set Pragma "no-cache"
    Header set Expires "Thu, 1 Jan 1970 00:00:00 GMT"
</IfModule>

Nginxでの対処

# nginx.conf
location /secure/ {
    add_header Cache-Control "private, no-cache, no-store, must-revalidate";
    add_header Pragma "no-cache";
    add_header Expires "0";
}

WordPressでの対処

// functions.php
add_action('template_redirect', function() {
    if (is_user_logged_in()) {
        header('Cache-Control: private, no-cache, no-store, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');
    }
});

PHPでの対処

<?php
// キャッシュ制御ヘッダーの設定
function setNoCacheHeaders() {
    header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    header('Pragma: no-cache');
    header('Expires: ' . gmdate('D, d M Y H:i:s', time() - 3600) . ' GMT');
}

// 機密ページ用のキャッシュ制御
function securePageHeaders() {
    header('Cache-Control: private, no-cache, no-store, must-revalidate');
    header('Pragma: no-cache');
    header('Expires: 0');
    session_cache_limiter('nocache');
}

ベストプラクティス

  • 機密情報を含むページはキャッシュしない: Cache-Control: no-store, no-cache, must-revalidateを設定し、キャッシュを無効化する。
  • 認証が必要なページはキャッシュしない: 認証が必要なページは、Cache-Control: privateを設定し、ユーザーごとのキャッシュを有効にする。
  • 適切なCache-Controlディレクティブを設定する: コンテンツの種類や重要度に応じて、max-ages-maxagepublicprivateなどのディレクティブを適切に設定する。
  • CDNのキャッシュ設定を確認する: CDNを使用している場合は、CDNのキャッシュ設定が適切かどうかを確認する。
  • キャッシュの有効期限を適切に設定する: キャッシュの有効期限が長すぎると、古い情報が表示される可能性があるため、適切な有効期限を設定する。

間違った設定例

# 機密情報を含むページをキャッシュする
Header set Cache-Control "public, max-age=3600"

正しい設定例

# 機密情報を含むページのキャッシュを無効化する
Header set Cache-Control "no-store, no-cache, must-revalidate"

検出方法

  • OWASP ZAPでの検出時の出力例: OWASP ZAPでは、Cache-Controlディレクティブの設定が不適切である場合に、警告を表示する。また、キャッシュから取得されたレスポンスであることを示すヘッダー (X-Cacheなど) が存在する場合にも、警告を表示する。
  • 手動での確認: ブラウザの開発者ツールを使用し、HTTPレスポンスヘッダーを確認し、Cache-Controlディレクティブの設定が適切かどうかを確認する。また、キャッシュから取得されたレスポンスであることを示すヘッダー (X-Cacheなど) が存在するかどうかを確認する。curlコマンドを使用して、HTTPレスポンスヘッダーを確認することもできる。

まとめ

  • 重要度: Medium (キャッシュされる情報の種類やWebサイトの構成によって変動します)
  • 運用チームや開発者が意識すべきポイント:
    • 機密情報を含むページはキャッシュしない
    • 認証が必要なページはキャッシュしない
    • 適切なCache-Controlディレクティブを設定する
    • CDNのキャッシュ設定を確認する
    • キャッシュの有効期限を適切に設定する
  • 再発防止の観点:
    • 開発者向けのセキュリティトレーニングを実施する
    • WebサーバーやCDNのキャッシュに関する設定を定期的に見直す
    • CI/CDパイプラインにキャッシュ設定の評価ツールを組み込む

補足資料リンクや参考URL

この解説記事が、脆弱性理解の一助となれば幸いです。