- バックエンド
- PdM
- フロントエンドエンジニア
- Other occupations (23)
- Development
- Business
AWS WAF実運用で学んだルール設計・運用・改善のコツ
Photo by Dustin Commer on Unsplash
こんにちは。ウォンテッドリーのInfra Squadでエンジニアをしている笠井(@takayukikasai)です。
昨今サービス事業者を狙った様々なセキュリティ脅威が増加しています。DoS/DDoS攻撃やスクレイピングによる情報収集、Webアプリケーションの脆弱性を狙った攻撃など攻撃手法は多様化・高度化しています。IPアドレスベースのアクセスブロックなど静的情報を用いた防御だけでは工夫を凝らした攻撃に対応しきれず、サービスの可用性・信頼性を守ることが困難になってきています。このため、常に変化する状況に対応するための動的な防御が重要です。
AWS WAFはマネージドサービスとして既存のALB/CloudFrontに比較的容易に適用できますが、効果を出す運用設計は別の難易度があります。ウォンテッドリーでは約2年前からAWS WAFを実運用し、ルールの設計・運用・継続的改善を行ってきました。本記事では実運用から得たルール設計のノウハウを紹介します。
想定読者
この記事はAWS WAFをある程度触ったことがある人を想定しています。基本的な設定から一歩進んでより効果的なWAF運用を目指している方の参考になればと考えています。
この記事で得られること
この記事ではWAFルールの設計・運用・改善方法について詳しく解説します。また実際の運用で遭遇しがちなルール設計のハマりどころとそれらを回避するテクニックも紹介します。
なおセキュリティ上の観点から具体的なルールの詳細については記載しません。
目次
ルール設計で意識すること・段階的な改善プロセス
1. ブロック対象の設計
2. どうやってルールを`count`から`block`へ移行するのか
実際にハマったポイントとその回避策
1. ネストの制限
2. Rate Limitの評価ウィンドウは固定ではなく常に動いている
まとめ
ルール設計で意識すること・段階的な改善プロセス
1. ブロック対象の設計
WAFルールを設計する際最も重要なのは「何をブロックするか」を明確にすることです。闇雲にルールを作るのではなく以下のように考えていきます。
Step 1: 防ぐべき攻撃を決める
まず自社のサービスに対するどのような攻撃を防ぐべきかを整理します。例えば大量のリクエストによってサービス停止を狙うDoS/DDoS攻撃、サービスの情報を大量取得するスクレイピング、SQLインジェクションやXSSなどの脆弱性攻撃、認証回避や権限昇格を狙った不正アクセスなどが考えられます。
Step 2: 防ぐべき攻撃の特徴を洗い出してブロック条件を整理する
ブロック条件を整理する前に防ぐべき攻撃の特徴を洗い出します。例えばDoS/DDoS攻撃であればホストやパスの偏りやリクエストの流速はどのくらいであるとかIPアドレスやユーザーエージェントなど特徴を洗い出します。
その上で共通項でグルーピングし、どういう組み合わせでブロックするのかを検討します。例えばホワイトボードなどに書き起こしてどの範囲をブロックするのかを考察します。
Step 3: ルールへの落とし込み方法を検討する
整理した条件を実際のWAFルールに変換します。例えばAWSが未検証と判定したBotに対してはBot Controlのbot:unverified
ラベルを参照し、高頻度アクセスにはRateBasedStatement
で閾値を設定し、特定の攻撃パターンに対してはAWSマネージドルールを活用します。
ルールを作る際はTerraformのAWS WAFプロバイダーでは論理ステートメント(And/Or/Not)のネストが最大3レベルという制約がある点や条件が複雑すぎると運用が困難になる点に注意が必要です。
Step 4: 実際にルールを作ってcount
で検証する
設計したルールを実装しまずはcount
モードで動作検証します。ここでは誤検知が無いか期待通りのブロックができているかを慎重に検証します。検証にはCloudWatch Logs Insightsが使えます。「2. どうやってルールをcount
からblock
へ移行するのか」で詳しく解説します。
# 例:未検証Bot対策ルール(Terraform)
rule {
name = "unverified-bot-count"
priority = 100
action {
count {} # まずはcountで様子見
}
statement {
# awswaf:managed:aws:bot-control ラベルを使いたい場合は AWSManagedRulesBotControlRuleSet をこれ以前に評価する必要がある
label_match_statement {
scope = "LABEL"
key = "awswaf:managed:aws:bot-control:bot:unverified"
}
}
}
2. どうやってルールを`count`から`block`へ移行するのか
正常なトラフィックまでブロックしてしまう可能性があるため、新しいルールをいきなりblock
モードで有効化するのは危険です。count
モードから検証を始めることはAWSも推奨しており以下のように段階的にblock
モードへ移行していきます。
Step 1: count
モードでの検証(数週間)
新しいルールは必ずcount
モードから始めます。この期間にはどれくらいのリクエストがルールにマッチするか、誤検知(false positive)がないか、想定通りのパターンを検出できているかという3つのポイントを重点的に観察します。
これらの調査にはCloudWatch Logsに記録されるWAFのログや関連情報を集めたDatadog Dashboardを参照します。
CloudWatch Logs Insightsの活用
CloudWatch LogsにWAFのログを記録してクエリします。例えば以下のようなクエリで特定のルールにマッチしたリクエストを絞り込んで検索結果に表示されるリクエストの分布を観察します。
fields httpRequest.clientIp, httpRequest.country, nonTerminatingMatchingRules.0.ruleId
| filter nonTerminatingMatchingRules.0.ruleId = 'rate-limit-rule'
| stats count(*) as requestCount by httpRequest.clientIp, httpRequest.country
| sort requestCount desc
count
モードの場合はnonTerminatingMatchingRulesにルール名が現れるためクエリはそちらにマッチさせるようにしています。また配列のindexをハードコーディングしているのはCloudWatch Logs Insightsのクエリの表現力が限られており任意のindex位置を検索しにくいためですが、適切にparseすることでより柔軟な検索も可能かもしれません。
Datadogダッシュボードの活用
継続的なモニタリングのために、ルールごとのマッチ数推移、ブロック率の変化、地域別・User-Agent別の統計などを可視化したDatadogダッシュボードを作成しています。
意識するポイントとしてはルールに指定した条件とそのしきい値が確認できるようにすることです。例えばRateBasedStatement
を条件として利用しているならリクエストの流速を表示するなどしておくと誤検知に気づくことができ、上手くブロックできていないときにどこまでしきい値を調整するべきかが明らかになります。
Step 2: データ分析とチューニング
ログデータを分析し、ルールの精度を高めます。具体的にはマッチしたリクエストの詳細(User-Agent、パス、地域など)を確認することで誤検知パターンを特定し、除外条件の追加を検討します。Rate Limitの場合はしきい値の調整も行います。
Step 3: 段階的なブロック化
リスクの低いものから順次block
モードに移行します。まず明らかに悪意のあるパターン(既知の攻撃ツール等)から始め次に不審なアクセス、最後に広範囲なルールという順序で段階的に移行していきます。
実際にハマったポイントとその回避策
1. ネストの制限
TerraformのAWS WAFプロバイダーには条件文のネストレベル制限(最大 3 レベル)があり、複雑な条件を実現しようとするとすぐにこの制約にぶつかります。例えば以下のような複雑な条件は、そのままでは実装できません。
もしBot判定が「未検証」かつ
(地域が「海外」または
(User-Agentが「特定パターン」かつ
(パスが「/api」または...)))
このようなときはラベルを活用したグルーピングで回避します。複雑な条件を複数のルールグループに分割しラベルで抽象化します。
1. Bot判定用ルールグループでBotを分類してラベルを付与
wantedly:bot:harmless
wantedly:bot:potential-harmful
wantedly:bot:harmful
2. Rate Limit用ルールグループでラベルを参照して制御
wantedly:bot:rate-limit-target:count
wantedly:bot:rate-limit-target:block
この方法により条件の再利用性も高まりメンテナンスも容易になります。
2. Rate Limitの評価ウィンドウは固定ではなく常に動いている
Rate Limitの仕組みについて筆者は誤解していたのですが、実際の挙動を観察すると「100リクエスト/分」の制限は毎分0秒にリセットされるのではなく評価ウィンドウは連続的にスライドしています。なおAWS WAF のレートベースルールは評価ウィンドウ長を1/2/5/10分から選択でき(既定は5分)ユースケースに応じて使い分け可能です。
これにより59秒目に50リクエスト、次の1秒目に50リクエストという場合合計100リクエストでもブロックされない、攻撃者が評価ウィンドウの境界を狙って攻撃することが可能、といった問題が発生する可能性があります。
これらの問題に対しては、複数の評価ウィンドウを組み合わせる(60秒、300秒など異なる期間のRate Limitを併用する)、しきい値に余裕を持たせる(実際に防ぎたい値の70-80%程度に設定する)、他の条件と組み合わせる(Bot判定、地域情報などと組み合わせて、より精密な制御を実現する)といった対策が有効です。
まとめ
AWS WAFの効果的な運用において最も重要なのはブロック対象の設計と継続的なログ監視・改善の2つです。ルール設計の具体例としてIP制御やBot判定、Rate Limitを組み合わせた運用を紹介しました。WAFは一度設定して終わりではなく、攻撃パターンの変化に合わせて運用を続けていくことでサービスを守る効果的なセキュリティ対策になります。まずは基本的なルールから始めて、運用を通じて自分たちの環境に合わせて改善していくことをおすすめします。
(おまけ)ウォンテッドリーのルールの概要
セキュリティ上の観点から具体的な設定値は記載できませんがウォンテッドリーでは以下のような多段階フィルタリング構造を実装しています。この構造により正常なトラフィックへの影響を最小限に抑えながら効果的に攻撃を防御できています。
リクエスト受信
↓
[第1段階] IPアドレスベース制御
├─ 信頼できるIP → 許可
└─ 悪意のあるIP → ブロック
↓
[第2段階] Bot判定とラベリング
├─ AWS Bot Controlによる判定
└─ 独自ルールによる詳細分類
↓
[第3段階] 動的Rate Limit制御
├─ Bot分類に応じた柔軟な閾値設定
└─ エンドポイント特性に応じた調整
↓
[第4段階] 脆弱性対策
├─ SQLインジェクション等の攻撃パターン検知
├─ 一般的なWebアプリケーション脆弱性対策
└─ AWSマネージドルールの活用
↓
[第5段階] 監視・分析
├─ 異常パターンの記録
├─ 攻撃トレンドの分析
└─ 緊急時対応ルールの動的適用