AWS WAFで実現するボット対策とユースケース

# はじめに
先日、ラスベガスで開催されたAWS re:Inventに参加してきました。業務で利用しているAWS WAFに関するセッションがあったのですが、他のセッションとの時間が重なり、残念ながら現地では参加できませんでした。帰国後、YouTubeで視聴する機会を得たため、その内容をこちらにまとめます。YouTubeのリンクは以下になりますので、興味のあるかたは見ていただければと思います。

**セッション：I didn’t know AWS WAF did this (CDN303)**

https://youtu.be/iTBfSgCXBZA?feature=shared

# 導入
### ボットトラフィックの増加
- 全トラフィックの47%がボットトラフィックである
- AIボットやAIツールにより、増加が加速している

### 良いボットと悪いボットとは？
| **良いボット**                           | **悪いボット**                              |
|-----------------------------------------------|--------------------------------------------------|
| **オンライン体験の向上**: ユーザーを支援し、便利でスムーズな体験を提供 | **脆弱性の悪用とシステム操作**: セキュリティホールを狙い、システムを混乱させる |
| **検索エンジン結果の改善**: 正確で関連性の高い情報を提供する           | **偽レビューの生成**: 製品やサービスの評価を不正に操作する               |
| **AIアシスタントのデータ収集**: 必要な情報を取得し、AIを強化           | **スクレイピングによる在庫枯渇**: 転売目的で商品を大量に購入し、一般消費者に影響 |
| **ウェブサイトのパフォーマンスモニタリング**: 可用性や速度を監視       | **メトリクスの歪曲とDDoS攻撃**: 業績データを歪曲し、サイトの可用性を低下させる |
| **オンラインショッピングの促進**: 在庫情報や商品検索を効率化           | **アカウント乗っ取りやフィッシング**: 認証情報を不正に取得し、悪意ある行動を実行 |


### AIボットは何を狙っているのか？
####  例1.ニュースサイトの記事
- 目的：最新ニュースや記事をスクレイピングして学習データとして利用
- 影響：ユーザーが元のウェブサイトを訪れる必要がなくなり、広告収入が減少する
####  例2.ECサイトの商品ページ
- 目的：競合の価格調査や市場分析や、転売業者によるチケットやスニーカーなどの在庫情報の収集
- 影響：転売業者による在庫枯渇や、価格競争の激化
#### 例3.ソーシャルメディアなどのプロフィール情報
- 目的：個人のペルソナを作成するためや広告のターゲティングを精密化するために利用
- 影響：個人情報の無断収集によりプライバシーが侵害される可能性

### robots.txtを無視するAIボットの増加
一部のAIボットはrobots.txtを遵守しているが、多くのAIボットが遵守していない状況
一方で、SEO向上のためにボットにスクレイピングを許可させた方が良いケースもあり、ただブロックをすれば良いものでもない

:::note info
Cloudflareでも最近、robots.txtを守らないAI系のボットを可視化/ルール化する機能がリリースされましたね。
:::

https://blog.cloudflare.com/ai-audit-enforcing-robots-txt/

# ボット対策に有効なAWS WAFの機能やルール
- Rate-basedルール
- リクエストやレスポンスのカスタマイズ
- ラベル機能
- AWS マネージドルール
    - Bot Control
    - アカウント乗っ取り防止 (ATP)
    - Account Creation Fraud Prevention (ACFP)
:::note info
色々用意はされてるものの、どう使えば良いのかが、なかなか難しいですよね。後述のユースケースでいくつか使用パターンが挙げられてますので、参考にして下さい。
:::

https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-bot.html

https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-atp.html

https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-acfp.html

# Dから始まる4つのボット緩和のアプローチ
- **Diversion（≒ 迂回、進路変更）**
    - 悪意のあるトラフィックを貴重なリソースから遠ざけることで、攻撃の影響を最小化する
        - 例）悪意のあるエージェントや攻撃者からのトラフィックを特定してブロックする
- **Distortion（≒ 歪曲）**
    - 正規のトラフィックと潜在的な脅威を区別するために、トラフィックを識別する仕組みを導入する
        - 例）既知の正常なトラフィックを許可するポジティブセキュリティを実装する
- **Deception（≒ 欺瞞、欺く）**
    - 攻撃を意図的に受け入れ、攻撃者の戦術や技術を分析する
        - 例）意図的にハニーポットに誘導する
- **Depletion（≒ 枯渇、無力化）**
    - 脅威を排除するための高度な脅威インテリジェンスと対策を活用する
        - 例）コマンド＆コントロール（C2）サーバーを特定し、パートナーと協力して攻撃基盤を解体・排除する

:::note info
日本語訳だといまいちイメージしづらいですね...例を参考にして下さい。
:::

## Deception（≒ 欺瞞、欺く）の具体例

### Fake Success（偽の成功）
- **目的：** 攻撃が成功したと攻撃者に思わせることで、検知されていることに気づかせない
- **手法：**
  - HTTPステータスコードやレスポンスボディをカスタマイズし、攻撃者に正常なレスポンスが返されたと誤認させる
  - ボットが期待するデータ形式を返しつつ、実際のアプリケーションには到達させない
  - 例えば、CloudFrontでボットにラベルを付与し、カスタムヘッダーを加えることで、後続のロードバランサやAPI Gatewayでハニーポットへルーティングする

### Fake Failure（偽の失敗）
- **目的：** 攻撃者に攻撃が失敗したと思わせて、行動を変えるよう誘導する
- **手法：**
  - ステータスコード429（Too Many Requests）でリクエスト速度を遅らせる
  - ステータスコード301（リダイレクト）を返し、攻撃者を無関係な場所に誘導する
  - 攻撃者がレスポンスを詳細に調査し、攻撃手法を変更することを想定

### Fake Execute（偽の実行）
- **目的：** 攻撃者を意図的にハニーポット環境に誘導し、その行動や戦術を分析する
- **手法：**
  - ラベルを使用して特定のリクエストをハニーポットにルーティング
  - 攻撃者の動きを追跡することで、脅威インテリジェンスを強化し、将来的な防御策を改善


# ユースケース
### パターン1：偽アカウント作成への対応
#### 前提
以下キャンペーンを実施しているが、大量のフェイクアカウント登録やアカウントの乗っ取りに悩まされている。
- 新規ユーザー登録で$10クーポン
- 紹介した既存ユーザーにも$10クーポン

#### ルールのステップ
1. **CFPとATPのルールを「カウント」で入れ、ラベルを付与する**
1. **カスタムWAFルールを作成してラベルをトリガーにアクションを定義**
1. **アクションの設定パターン：**
    1. カウントとカスタムヘッダーの追加
        1. 特定のHTTPヘッダを付与し、アプリケーション側で受け取ってビジネスロジックを切り替える
            --> ロジック側での不正検知の目印とする
        2. もしくは、特定のHTTPヘッダをALBへ渡し、特定の値を含むリクエストをハニーポットへ誘導する 
--> ハニーポット内での動きを追跡する
    1. ブロックし、カスタムレスポンスで200を返す
        1. 実際にはWAFでブロックするが、レスポンスとしては200 OKを返して攻撃者を欺く
--> 例えば、偽のクーポン番号をカスタムレスポンスで配布して、そのクーポンが使用された時を追跡する

:::note info
Deception（≒ 欺瞞、欺く）のパターンですね
:::

### パターン2：期間限定サイトへの動的DDoS対策
#### 前提
キャンペーンのため短期的に公開される静的サイトであり、期間中にWebサイトが利用可能であることの可用性が重要視される
#### ルールのステップ
1. **レートベースルールを「カウント」で入れる**
    1. レートベースルールを設定し、一定時間内のアクセス数が閾値を超えたものを「カウント」アクションにして、例えば「volumetric-traffic」というラベルを付与。これにより、「通常より多いリクエストが来ている」状況を他のルールが認識できるようにする
※ ここではIPや特定のヘッダーなどの条件は付与せず、リクエスト全量を対象とする。
1. **「volumetric-traffic」ラベル付きリクエストに対する追加ルール**
    1. volumetric-trafficラベルが付いているリクエストのみを対象にするルールを設定する：
        1. 再度のレートベースルール
            1. IPアドレス単位でリクエストを制限する
        1. IPレピュテーションルール
            1. 既知の悪意あるIP、匿名プロキシなどをブロックするAWSやサードパーティのマネージドルールを、volumetric-trafficに該当するリクエストだけに適用する
        1. Bot Controlの検査を限定的に適用
            1. volumetric-trafficのラベル付きのアクセスだけBot判定をすることで、コストの節約にもなる

1. **攻撃が収まれば通常モードに戻る**
    1. ラベルが付与されるほどの大量アクセスが落ち着けば、WAFは再び緩やかなルールに従い、不要なブロックや検査が減る

:::note info
全てのリクエストにBot Controlを検査するのではなく、異常値の時のみ検査をすることでコスト削減に繋がると
:::


### パターン3：リスクベースのWeb ACL構築
#### 前提
- 静的コンテンツ（画像、HTML、CSS、JS）を含む
- データ取得や送信用のAPIエンドポイントを含む
- ブラウザやモバイルデバイスなど異なるデバイスからアクセスされる
- コスト効率の良い方法でトラフィックを制御したい

#### ルールのステップ
1. **以下すべてのルールをカウントで入れ、ラベルが付与されるようにする**
    1. **信頼済みIP**
        1. 社内ネットワーク、テスター、許可済みの自動化エージェントなど、信頼できるIPをホワイトリストとして追加
    1. **マネージドルール**
        1. CoreRuleSet、SQLインジェクションルール、IPレピュテーションルールなどのマネージドルールを使用
    1. **地理的一致ルール**
        1. 特定の国や地域からのトラフィックに対してラベル付与
    1. **機密性の高いURI**
        1. ログインページやパスワードリセットページなど、機密性の高いURIを対象に設定
    1. **APIエンドポイント**
        1. JavaScriptやCAPTCHAのようなチャレンジが利用できないAPIエンドポイント
    1. **Bot Control**
        1. Bot Controlの「common」カテゴリでラベル付与し、悪意のあるボットやクローラーを識別
            1. 必要に応じて「Targeted」カテゴリでより厳格に識別も可能
1. **最終的なBlockルール**
    1. 複数ラベルの組み合わせを条件にしてブロック
        1. 例えば、SQLインジェクションのラベルと、機密性の高いURIのラベルが付いていない、かつ信頼済みIPのラベルが付いていない場合にリクエストをブロックする、など

:::note info
複数ラベルの条件を組み合わせてルールを慎重に適用することで、誤検知による影響を最小限に抑えつつ、高リスクなリクエストを確実に防ぐことができそうですね。
気になったのは「6.Bot Control」でマネコンだとBot ControlはcommonもしくはTargetedのいずれかを選択するしかなく、どちらかしかルール設定ができないんですが、AWS CLIやTerraformだと複数入れることができるらしいです。やってみます。
:::

# Bot Controlを複数設定してみる

### まずはマネコンではBot Controlを複数設定できないことを確認

1. Bot Controlを一つルールに追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28783/6b822982-f5d3-cfbc-3c48-8172988a6e61.png)

2. もう一つ追加しようとしても、Edit画面に遷移させられてしてしまい、追加はできません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28783/1deff914-2b54-d7d7-bf86-d7149d80faa8.png)

### Terraformでルールを追加してみる

以下Terraformコードの抜粋です。`inspection_level`で`COMMON`と`TARGETED`をそれぞれ設定したBot Controlルールを作成してみます。
```terraform
statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesBotControlRuleSet"
        vendor_name = "AWS"

        managed_rule_group_configs {
            aws_managed_rules_bot_control_rule_set{
                enable_machine_learning = true
                inspection_level = "COMMON"
            }
        }
      }
    }
```
```terraform
statement {
  managed_rule_group_statement {
    name        = "AWSManagedRulesBotControlRuleSet"
    vendor_name = "AWS"

    managed_rule_group_configs {
        aws_managed_rules_bot_control_rule_set{
            enable_machine_learning = true
            inspection_level = "TARGETED"
        }
    }
  }
```

<details>
<summary>Terraformコード全量</summary>

```terraform

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.0.0"
    }
  }
  required_version = ">= 1.4.0"
}

provider "aws" {
  profile = "default"
  region  = "ap-northeast-1"
  default_tags {
    tags = {
      Terraform = true
    }
  }
}

resource "aws_wafv2_web_acl" "botcontrol-example" {
  name        = "managed-botcontrol-example"
  description = "Example of a managed rule created by Terraform."
  scope       = "REGIONAL"

  default_action {
    allow {}
  }

  rule {
    name     = "botcontrol-common"
    priority = 100

    override_action {
      count {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesBotControlRuleSet"
        vendor_name = "AWS"

        managed_rule_group_configs {
            aws_managed_rules_bot_control_rule_set{
                enable_machine_learning = true
                inspection_level = "COMMON"
            }
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "botcontrol-common"
      sampled_requests_enabled   = false
    }
  }

  rule {
    name     = "botcontrol-targeted"
    priority = 200

    override_action {
      count {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesBotControlRuleSet"
        vendor_name = "AWS"

        managed_rule_group_configs {
            aws_managed_rules_bot_control_rule_set{
                enable_machine_learning = true
                inspection_level = "TARGETED"
            }
        }
      }
      
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "botcontrol-targeted"
      sampled_requests_enabled   = false
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = false
    metric_name                = "friendly-metric-name"
    sampled_requests_enabled   = false
  }
}

```
</details>

1. Terraform実行後の状態
![スクリーンショット 2024-12-26 12.02.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28783/f06c7521-b065-fa09-d310-7a152d71cd9d.png)

:::note info
Bot Controlがちゃんと複数入っていました。これで、BotContolの使い分けは確かにできそうです。
:::

# まとめ
ユースケースが3つありましたが、共通して強調されていたのは、**前半でルールをカウントで入れて、ラベルを付与すること。後半でラベルに応じたブロックルールを入れる。** ということでした。確かにAWSのマネージドルールはすべてラベルが付与されるため、さらに細かな調整ができますね。さらにCloudWatchでラベルごとにメトリクス監視ができますので、ラベルを使いこなすことで一段階上のルールを構成することができそうです。

# 参考資料

https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/bot-control/optimizing-costs.html

https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/waf-labels.html