【実務・中級編】 DDoS対策:AWS Shield / Azure DDoS Protectionの活用 – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

お疲れ。最近、夜中にインフラのアラートが鳴り響いて冷や汗をかいた経験はないか?
「またボットネットからのL7リクエストか……」なんて思いながらダッシュボードを開いたら、オリジンのNginxが完全に沈黙していた――なんて悪夢は、我々の業界では日常茶飯事だ。

教科書には「DDoS対策にはAWS ShieldやAzure DDoS Protectionを入れましょう」と綺麗事が書かれているが、じゃあ実際に大規模なSYNフラッドや、CloudFront/ALBの裏側を直撃する巧妙なHTTPリクエスト・フラッドが飛んできた時、クラウドのデフォルト設定だけで耐えられると本気で思っているか? 答えはノーだ。

今日は、数々の修羅場をくぐってきた私が、クラウドネイティブなDDoS対策の本当の勘所と、現場でそのまま使える実践的な設定を叩き込んでやる。綺麗事抜きのエッジ防御のリアルを覗いていこう。

—

1. クラウド型DDoS対策の盲点:L3/L4とL7の戦いは全く別物だ

まず、大前提を叩き込んでおく。AWS Shield StandardはすべてのAWSユーザーに無料で提供されているが、これはあくまでL3/L4(ネットワーク層・トランスポート層)の基本的なボリュームベースド攻撃(UDP反射やSYNフラッドなど)をAWSのエッジネットワークで自動的にいなしてくれるものだ。

しかし、攻撃者はバカではない。彼らは「金にならないL3/L4」を諦め、より厄介なL7(アプリケーション層)攻撃、すなわち、正常なTCPコネクションを確立した上で、キャッシュをバイパスする巧妙なURLへ数万IPから秒間何万ものリクエストを送りつける「Slowloris」や「HTTP GET/POSTフラッド」にシフトしている。

L7の領域では、クラウドの基盤側は「それが正当なユーザーのリクエストなのか、悪意あるボットの総攻撃なのか」をデフォルトでは判断できない。ここで必要になるのが、AWS WAFやAzure WAFとの密な連携、そしてオリジンサーバー(Nginx等)側のレートリミットによる多層防御(ディフェンス・イン・ディープ)だ。

—

2. 現場で使える! AWS WAF (JSON) によるL7レートリミティング設定

エッジ(CloudFrontやALB)の手前で悪意あるトラフィックを綺麗に刈り取るために、AWS WAFのレートベースルール(Rate-based rule)をTerraformやAWS CLIでデプロイしていることだろう。

以下に、実務で即座に使える、特定のAPIエンドポイントに対する厳格なレートリミット(5分間に100リクエストを超えたIPを自動ブロック)のAWS WAFルール定義(JSONサンプル)を示す。

{
  "Name": "StrictApiRateLimitRule",
  "Priority": 10,
  "Statement": {
    "RateBasedStatement": {
      "Limit": 100, // 5分間の同一IPからの許容リクエスト数
      "AggregateKeyType": "IP",
      "ScopeDownStatement": {
        "ByteMatchStatement": {
          "SearchString": "/api/v1/expensive-query", // 攻撃者が好んで狙う重いAPIエンドポイント
          "FieldToMatch": {
            "UriPath": {}
          },
          "TextTransformations": [
            {
              "Priority": 0,
              "Type": "NONE"
            }
          ],
          "PositionalConstraint": "STARTS_WITH"
        }
      }
    }
  },
  "Action": {
    "Block": {
      "CustomResponse": {
        "ResponseCode": 429,
        "CustomResponseBodyKey": "TooManyRequestsKey"
      }
    }
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "StrictApiRateLimitMetric"
  }
}

この設定のミソは、サイト全体ではなく「最もDB負荷が高く、DDoSで最初に枯渇する重いAPIエンドポイント(/api/v1/expensive-query)」に絞ってスコープダウンしている点だ。全体を一律に制限するとUXが落ちるが、急所だけをピンポイントでガードするのがプロの技だ。

—

3. クラウドをすり抜けた攻撃を受け止める! Nginx要塞化の設定

もし、何らかの理由でCDNやWAFをバイパスされ、オリジンのNginxに直接パケットやHTTPリクエストが到達したとしたら? そこでサーバーが全ダウンしたら、あなたのインフラ設計の負けだ。

オリジンを守るためのNginx設定ファイル(nginx.confの抜粋)を公開する。これを見れば、単に「動く」だけのサーバーがいかに無防備であるかが痛感できるはずだ。

http {
    # 1. IPアドレス単位でのレートリミット用ゾーンを定義 (10MBのメモリで約16万IPを追跡)
    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

    # 2. 同時接続数(コネクション数)の制限ゾーン
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    # クライアントからのリクエストボディやヘッダーの読み取りタイムアウトを極端に短くする(Slowloris対策)
    client_body_timeout 5s;
    client_header_timeout 5s;
    send_timeout 10s;
    keepalive_timeout 15s;

    server {
        listen 80;
        server_name example.com;

        # 3. サーバー全体での同時接続数をIPあたり20に制限
        limit_conn addr 20;

        location / {
            # 4. レートリミットの適用 (バースト許容数を20に設定。超過分は遅延させず即座に503を返す)
            limit_req zone=one burst=20 nodelay;

            # プロキシ設定や通常のルーティング
            proxy_pass http://backend_cluster;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }

        # 5. ログイン画面や重い処理のエンドポイントはさらに厳しく制限
        location /api/login {
            limit_req zone=one burst=5 nodelay;
            proxy_pass http://backend_cluster;
        }
    }
}

この設定が防ぐ具体的な脅威

  • Slowloris攻撃: client_header_timeout 5s により、ダラダラと遅いHTTPヘッダーを送りつけてスレッドを占有しようとする行儀の悪いクライアントを即座に切断する。
  • HTTPフラッド: limit_req により、秒間10回を超える異常なリクエストをバースト分も含めて容赦なく弾き、オリジンサーバーのCPUとプロセス枯渇を防ぐ。

—

4. インシデント発生時の初動:ログ解析と「真のIP」の特定

DDoSの最中、アクセスログ(NginxやCloudWatch)には大量のIPが並ぶ。ここで初心者がやりがちなミスが、ロードバランサー(ALB/CloudFront)のIPアドレスをブロックしてしまうことだ。

必ず X-Forwarded-For ヘッダーや、Nginxであれば $remote_addr ではなく $http_x_forwarded_for を確認し、真のクライアントIPを特定すること。

もしPythonでリアルタイムにアクセスログを監視し、特定の閾値を超えたIPをAWS WAFのIPセットに自動追加するインシデントレスポンススクリプトを書くなら、以下のようなロジックが現場で重宝する。

import boto3
import re
from collections import Counter

# 簡易的なログ解析と自動遮断の概念実習コード
def analyze_logs_and_mitigate(log_file_path):
    ip_counter = Counter()
    
    # NginxのアクセスログからIPアドレスを抽出 (簡易パース)
    ip_pattern = re.compile(r'^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
    
    with open(log_file_path, 'r') as f:
        for line in f:
            match = ip_pattern.match(line)
            if match:
                ip_counter[match.group(1)] += 1

    # 直近のログで秒間リクエスト数に換算して異常なIPを検出
    suspicious_ips = [ip for ip, count in ip_counter.items() if count > 500]
    
    if suspicious_ips:
        print(f"[!] 異常なトラフィックを検出しました: {suspicious_ips}")
        # ここで boto3 を使って AWS WAF の IP Set に動的に追加する処理を呼び出す
        # update_waf_ip_set(suspicious_ips)

if __name__ == "__main__":
    # 実運用ではCloudWatch Logs Insightsのクエリ結果やKinesis Data Firehoseからストリーム処理する
    print("Security Chief: インシデント自動防御スクリプト待機中...")

—

5. チーフエンジニアからの教訓

DDoS対策に「これさえ入れれば絶対に落ちない」という銀の弾丸(シルバー・バレット)はない。AWS ShieldやAzure DDoS Protectionは強力な盾だが、それはあくまでL3/L4の荒波を防ぐ防波堤に過ぎない。

アプリケーションの脆弱性、DBの非効率なクエリ、そしてエッジからオリジンに至るまでの設定の隙をついて、攻撃者は常に新しい手口を試してくる。

「クラウドに金を払っているから安心」ではなく、「クラウドの機能を理解し、自社のコードとNginx等のミドルウェアで何重にも網を張る」。

この泥臭い多層防御の思想こそが、深夜の緊急アラートからあなたを解放し、チームの平穏を守る唯一の確実な手段だ。次のデプロイの前に、もう一度インフラの設定ファイルを見直してほしい。セキュリティは細部に宿る。

コメント

タイトルとURLをコピーしました