要点: あらゆるDDoSを一つの設定だけで防ぐことはできません。各層が得意な攻撃を担当する必要があります。
この記事の用語: レート制限:一定時間内のリクエスト数を制限する仕組み。配信元サーバー:CDNの背後にあるアプリケーション サーバー。
現場の課題
アプリケーションでのレート制限は、帯域や接続を枯渇させる攻撃には遅すぎます。一方、すべてのルールを一か所へ集めると、正規利用者の誤検知や新たなボトルネックを招きます。
単純な対策だけでは不十分な理由
DDoSは攻撃者より防御側に高いコストを払わせる非対称な問題です。CDNは帯域、プロキシは接続、アプリケーションはアイデンティティと業務コストを使い、安い層からトラフィックを落とします。
処理フロー
未信頼の通信→CDN / WAF
大規模通信を除外→Reverse プロキシ
TimeoutとIP制限→アプリ
APIグループ別制限
アーキテクチャ上の判断
最も安価な層で落とす
Volumetric攻撃にはAnycast CDNまたはScrubbingを、既知パターンにはWAFを使います。配信元サーバー Allow-listにより、Edgeを経由しない直接接続も防ぎます。
接続とBodyに予算を設ける
Reverse プロキシでヘッダー・Bodyサイズ、ヘッダー読取・Idle Timeout、送信元別の接続数、同時リクエスト数を制限します。低速クライアントが配信元サーバー Socketを占有し続けないようにします。
コストとアイデンティティでレート制限する
Routeを処理コスト別に分け、Account、API キー、Trusted プロキシ由来のIP、端末 Signalを組み合わせます。Login、Search、データ出力には、それぞれ異なるトークン コストとBurstを設定します。
さらに深く考える
Threat モデルからControlを設計する
まず、攻撃者が枯渇させ得るResourceを列挙します。Bandwidth、TLS Handshake、Socket、リクエスト Body バッファ、認証のHash、キャッシュ Miss、DBクエリ、高コストな業務処理などです。各Resourceを、それを保護できる最も外側の層に割り当て、計測可能なBudgetを設定します。Carrier NAT、企業プロキシ、IPv6 Privacy Addressの背後では、IPだけの識別は弱い点に注意します。ネットワーク SignalにAccount、API キー、端末 Cookie、行動履歴を組み合わせます。そのうえで、Supportやユーザーへ失敗扱い理由を説明できる、理解可能なルールに保ちます。
障害対応中に運用できるMitigationにする
Severity Level、担当者、可逆な操作を事前に定義します。初期段階では匿名Burstを厳しくし、後段で疑わしいクライアントへのChallenge、高コスト エンドポイントの停止、重要外部連携のAllow-listを適用します。設定変更にはバージョン管理、Peer Review、自動失効を持たせ、緊急ルールを恒久的なTechnical 技術的負債にしません。機密Bodyは残さず、Sampling 検証結果を保存します。障害対応 ダッシュボードとEnforcementで同じTrusted クライアント IP解析を使い、調査対象と制限対象のアイデンティティを一致させます。
実装手順
- CDNとWAFで大規模トラフィックと既知の攻撃パターンを先に除きます。
- Reverse プロキシで接続数、本文サイズ、ヘッダー待ち時間を制限します。
- 認証や重いDBクエリの前に、エンドポイントの処理コストに応じたレート制限を適用します。
コード例: 重み付きトークン Bucket ポリシー
policy['read'] = { rate: 60/min, burst: 30, cost: 1 }
policy['login'] = { rate: 10/min, burst: 5, cost: 3 }
policy['export'] = { rate: 2/min, burst: 1, cost: 20 }
identity = accountId ?? apiKeyId ?? trustedClientIp
bucket = `${routeGroup}:${identity}`
allowed = tokenBucket.consume(bucket, policy[group].cost)
if (!allowed) return 429 with Retry-AfterForwarding ヘッダーは既知プロキシからのみ受け入れます。そうしないと、攻撃者がX-Forwarded-Forを偽装・変更し、IP制限を回避できます。
想定しておく障害
- 配信元サーバー DNSまたはIPが公開され、CDNを迂回されます。Edge IP範囲、または認証済み配信元サーバー接続だけをIngressで許可します。
- 中央Rate-上限 Storeが停止します。低コスト 読み取りはFail-open、高コスト・セキュリティに関わるRouteは有限のLocal FallbackまたはFail-closedを選びます。
- 正規キャンペーンが攻撃に見えます。段階的なMitigation、顧客別Quota、そして有効期限とAudit付きのEmergency Overrideを用意します。
監視すべきこと
| 指標 | 何が分かるか |
|---|---|
| Edge受付数と配信元サーバー到達数 | 配信元サーバー資源を使う前に除去できた悪性Volumeを示します。 |
| 接続数・Handshake失敗・Timeout | リクエスト Countでは見えない接続枯渇とSlow-クライアントを検出します。 |
| Route・アイデンティティ種別ごとの429率 | 小さすぎるQuotaと、集中した不正利用とを区別します。 |
| 配信元サーバー飽和度と顧客エラー率 | Mitigationが正規利用者へ障害を移さず、可用性を守っているかを確認します。 |
設計の検証方法
- Volumetric、Slow 接続、アプリケーション-コストの各Scenarioを分けて実施し、各層への負荷を再現します。
- Login開始時、キャンペーン、Partner バッチなど、正規のBurst Profileを送信します。
- 全Trusted プロキシ範囲の外から、配信元サーバー直接アクセスとForwarding ヘッダーの偽装を試します。
- Distributed Counterを停止し、RouteごとにFail-open、Fallback、Fail-closed ポリシーが守られるか確認します。
- 失敗扱い件数だけでなく、False-positive率と上限緩和後の復旧 Timeを測ります。
本番導入の進め方
新しいルールはカウントのみで開始し、誰がなぜ遮断されるかを確認します。認証済み利用者やキャンペーン トラフィックと照合し、少数の明確な悪用から段階的に強制します。
本番前チェックリスト
- ログイン集中やキャンペーンなど、正当な急増は許容できる必要があります。
- カウンター障害時にfail openとするかfail closedとするかを明示します。
- 拒否数、配信元サーバー負荷、顧客エラー率をまとめて監視します。
まとめ
多層防御は処理コストの低い場所から攻撃トラフィックを除き、アプリケーション資源を正規利用者へ残します。
