76
59

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WAFでブロックしたはずなのに200 OKが返ってくる謎を解く

Posted at

はじめに

AWS CloudFront と WAF を組み合わせてセキュリティを強化していたところ、奇妙な現象に遭遇しました。

「WAF でリクエストを BLOCK しているはずなのに、なぜか 200 OK が返ってくる...?」

ログを見ると確かに WAF で BLOCK されているのに、ブラウザには白いページが表示され、レスポンスコードは 200。一体何が起きているのでしょうか?

この記事では、この謎現象の原因と仕組みを詳しく解説します。

🔍 問題の現象

観測された症状

  • WAF ログ: action: "BLOCK"と記録されている
  • CloudFront ログ: sc-status: "200"となっている
  • ブラウザ: 白いページが表示される(コンテンツは空)
  • Lambda@Edge: なぜか実行されている

設定状況

CloudFront設定:
  - カスタムエラーページ設定あり
    - HTTP error code: 403 Forbidden
    - Response page path: /index.html
    - HTTP Response code: 200 OK  # ←ここが重要

AWS WAF設定:
  - IPアドレス制限ルールでBLOCK
  - カスタムレスポンス設定なし

Lambda@Edge設定:
  - Viewer Requestイベントで動作
  - Cognitoリダイレクト処理

📊 ログから見る時系列

実際のログタイムスタンプを分析すると、以下の順序で処理されていることが判明:

CloudFront がリクエスト受信
↓
WAF がリクエストをBLOCK(ログ記録時刻)
CloudFrontがカスタムエラーページ処理開始
↓ 403→200変換により内部リクエスト生成
Lambda@Edge (Viewer Request) 実行開始
CloudFront最終レスポンス記録(200 OK)
Lambda@Edge処理完了

待って...WAF で BLOCK されてるのになんで Lambda@Edge が動いてるの?

🔧 謎解き:CloudFront カスタムエラーページの仕組み

真相

実は、CloudFront には 「オリジンからの 403 エラー」と「WAF からの 403 エラー」を区別できない という仕様があります。この区別できない仕様のため、WAF でブロックされたリクエストでも内部リクエストで Lambda@Edge が実行され、結果として 200 OK が返されることになります。

CloudFront は、オリジンから返された HTTP ステータスコード 403 と AWS WAF がリクエストをブロックしたときに返された HTTP ステータスコード 403 を区別できません

AWS 公式ドキュメントより

処理の流れ

  1. WAF が 403 エラーを返す

    • リクエストが IP アドレス制限ルールにヒット
    • WAF: action: "BLOCK"
  2. CloudFront が「これはオリジンからの 403 だ」と誤認

    • 実際は WAF からの 403 だが、CloudFront には区別できない
  3. カスタムエラーページ設定が動作

    • 設定: 403 → 200 OK + /index.html
    • この「403→200 変換」設定が新しい内部リクエストを生成
  4. 内部リクエストで Lambda@Edge が実行される

    • /index.htmlへリクエスト
    • Viewer Request イベントで Lambda@Edge が動作
  5. 結果として 200 OK が返される

    • 実際のコンテンツは取得できないため空ページ

📋 2 つの動作パターン比較

パターン A: CloudFront カスタムエラー設定のみ

WAF-a.png

サービス 動作 ログ結果
WAF リクエストを BLOCK action: "BLOCK", responseCodeSent: null
CloudFront カスタムエラー処理実行 sc-status: "200", x-edge-result-type: "Error"
Lambda@Edge 実行される Cognito リダイレクト処理が動作
エンドユーザー 200 OK(空ページ)受信 白いページが表示される

用途: SPA(Single Page Application)対応

パターン B: WAF カスタムレスポンス + CloudFront カスタムエラー併用

WAF-b.png

サービス 動作 ログ結果
WAF カスタムレスポンス返却 action: "BLOCK", responseCodeSent: 403
CloudFront WAF レスポンスをそのまま転送 sc-status: "403", x-edge-result-type: "Error"
Lambda@Edge 実行されない ログなし
エンドユーザー 403 Forbidden 受信 アクセス拒否ページ

用途: セキュリティ重視

🏗️ AWS 公式の優先順位ルール

AWS 公式ドキュメントによると、レスポンスの優先順位は以下の通り:

  1. WAF カスタムレスポンス(最優先)
  2. CloudFront カスタムエラーページ
  3. WAF デフォルトレスポンス(403 Forbidden)

今回の現象は、WAF カスタムレスポンス未設定のため、CloudFront カスタムエラーページが動作

⚡ 解決策と推奨設定

🎯 SPA + セキュリティを両立させたい場合

  1. WAF カスタムレスポンス設定
    • 不正アクセスのブロックは確実に 403 を返す
  2. CloudFront カスタムエラーページ
    • S3 オリジンの 404/403(ルーティング用)は 200+index.html を返す
  3. Lambda@Edge での追加制御
    • リクエストヘッダーや IP アドレスでより細かい判定

💰 コスト最適化を重視する場合

WAF カスタムレスポンスを設定することで、不要な Lambda@Edge 実行を防げます。

⚠️ 注意点

  • セキュリティ考慮: WAF で BLOCK されても Lambda@Edge が実行される可能性があるため、Lambda@Edge 内でもセキュリティ制御を実装する
  • コスト面: 不要な Lambda@Edge 実行を避けたい場合は、WAF カスタムレスポンスを設定する

🔍 デバッグのポイント

この現象に遭遇した際の調査方法:

  1. WAF ログの確認

    • responseCodeSentnullなら、CloudFront カスタムエラーが動作する可能性あり
  2. CloudFront ログの確認

    • x-edge-result-type: "Error"なのにsc-status: "200"なら、カスタムエラーページが動作
  3. Lambda@Edge ログの確認

    • WAF で BLOCK されているのにログがあるなら、内部リクエストが生成されている
  4. リクエスト ID の突合

    • 同一request-idでサービス間のログを追跡

まとめ

「WAF で BLOCK したのに 200 OK が返ってくる」 という現象は、CloudFront の仕様による正常な動作でした。

キーポイント:

  • CloudFront は WAF の 403 とオリジンの 403 を区別できない
  • 「403→200 変換」設定が内部リクエストを生成する
  • WAF カスタムレスポンス設定で動作を制御可能

この仕様を理解することで、SPA 対応とセキュリティ対策を適切に両立できるようになります。

同じような現象に遭遇した方の参考になれば幸いです!


参考資料

76
59
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
76
59

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?