API Gateway/AWS WAF~SQLインジェクションのブロックとログを確認する~

## はじめに
AWS WAFを使って実際にSQLインジェクション攻撃がブロックできるのか？
今回はAPI GatewayにAWS WAF（以降、WAF）のWeb ACLを連携して、リクエストがブロックされるかを検証していきます。
WAFのログの出力設定を行い、実際のブロックのログまで確認します。
※WAFとはなにか？SQLインジェクションとはなにか？の説明は省略します。

## 結論
WAFのWeb ACLをAPI Gatewayに連携することで、設定したルールに基づくSQLインジェクション攻撃と判定されたリクエストをブロックすることが出来る。

また、Web ACLのログ設定を有効化することで、
ブロックしたリクエストの中身（クライアントIPやブロック理由）を確認することが出来る。

## AWS WAFのWebACLとは
今回使うAWS WAFのWeb ACLは、AWS WAFの機能の一つです。
>Web ACLを使用すると、保護されたリソースが応答するすべての HTTP(S) ウェブリクエストをきめ細かく制御できます。

Amazon CloudFront、Amazon API Gateway、Application Load Balancerなどと連携や統合して利用します。
AWSで構築しているWebサイトの保護をするためのサービスの１つです。

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

## 検証方法
どのように検証したか、検証結果を交えながら説明します。

### 今回実施した検証手順
**1. API Gatewayの作成**
APIを作成し、SQLインジェクションを含むリクエストを送信し、レスポンス（正常）を確認    
**2. WAFのWeb ACLの作成/ルールの追加**
Web ACLを作成し、今回はSQLインジェクションに対応するルールを追加
**3.API GatewayにWeb ACLを設定**
事前に作成したAPI GatewayにWeb ACLを設定
**4.リクエストのブロック確認**
事前に確認したSQLインジェクションを含むリクエストを送信し、レスポンス（ブロック）を確認
**5.Web ACLのログの有効化**
ロググループを作成し、Web ACLが評価したリクエスト情報を確認できるよう設定
**6.WebACLの評価ログの確認**
再度APIにリクエストを送り、ログの内容を確認

詳しい内容は個別のセクションで説明します。

### 今回の最終構成図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/cacb29bb-1cd4-1449-ba48-6e5e1380be82.png)

### 1. API Gatewayの作成
WAFの保護対象として、今回はAPI Gatewayを利用します。
ここでの内容は、APIを作成し、正常にレスポンスが返ってくることの確認まで。

今回はバージニア北部リージョンで構築しています。
東京リージョンでも今回の内容は構築/検証可能です。
  
後に設定するWeb ACLのリージョンと統一する必要があるため、API Gatewayのエンドポイントはどこのリージョンで作成したか把握しておいてください。
  （筆者は、Web ACLを東京リージョンで作って連携できず そこで気が付きました...）

  **詳細手順**
* AWSコンソールから「API Gateway」メニューを開く
* 「APIの作成」から「REST API」を構築
* リソース作成
* メソッド（POST）を作成
 統合タイプは「Mock」 （まぁなんでもいい）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/06640079-3a23-eeff-58a5-7b37463d0ddd.png)


* 新しいステージにデプロイ

**作成したAPI情報**
| 項目 | 値 |
|:-:|:-:|
|  API名 |  AWS-WAF-test |
| プロトコル  | REST  |
| APIエンドポイントタイプ  | Regional（バージニア北部） |
|  ステージ名 | WAF-test  |
| リソースパス  |  /waf-test-resource |
| メソッドタイプ  | POST  |
|  統合タイプ | Mock  |

* APIへのリクエスト確認

自身の端末（コマンドプロンプトやPowerShellなど）からAPIへリクエストを送信します。
SQLインジェクションを含むリクエストとしてBodyに`1 OR 1=1`を含めます。

リクエスト先は自身で作成したAPIの情報に合わせてください。
`StatusCode：200`が確認できればOKです！

```py:PowerShell
PS C:\Users> curl -Method POST -Uri "https://<your-api-id>.execute-api.<region>.amazonaws.co/WAF-test/waf-test-resource" -Headers @{ "Content-Type" = "application/json" } -Body '{"input": "1 OR 1=1"}'


StatusCode        : 200
StatusDescription : OK
Content           :
RawContent        : HTTP/1.1 200 OK
                    Connection: keep-alive
#一部省略
                    Content-Length: 0
                    Content-Type: application/json
                    Date: Sat, 09 Nov ...
Forms             : {}
Headers           : {[Connection, keep-alive], [x-amzn-RequestId, 711b4560-2ca1-40e4-b4ae-4cc6315f7f2a], [x-amz-apigw-i
                    d, A954UGRyIAMEvYA=], [Content-Length, 0]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 0

```

### 2. WAFのWeb ACLsの作成/ルールの追加
APIの正常確認が出来たので、APIに設定するWAFのWeb ACLを作成していきます。
ここでの内容は、Web ACLの作成まで。

 **詳細手順**
 * AWSコンソールから「WAF & Shield」メニューを開く
 * 「Web ACLs」からWeb ACLを作成
 * regional resourceでAPI Gatewayと同じリージョンを選択
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/1dd397ff-7aff-202d-31df-569dd94feaf4.png)

 * ルールに「AWS-AWSManagedRulesSQLiRuleSet」を追加
今回はSQLインジェクション攻撃などのリクエストパターンをブロックするルールが含まれる無料のRuleSetを利用します。ルールの中身など詳細は以下を参照ください。

https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-use-case.html#aws-managed-rule-groups-use-case-sql-db

 * Actionはblock
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/77b27a2c-f68f-9aee-ab60-71c920280aee.png)

**作成したWeb ACL情報**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/2675b444-1b61-2f6a-110f-a6c204d12421.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/4bd90be0-d9f7-eb28-e2d9-191630dde222.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/20ce5af6-73ca-1796-a8c4-39662c4a53d5.png)


* Web ACLの作成確認
正常に作成できれば完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/4a34b71b-3f75-8aae-dac3-b120040cff22.png)

### 3.API GatewayにWeb ACLを設定
ここではAPIへWeb ACL設定まで。

 **詳細手順**
 * API Gatewayのステージを編集
 * WAFの項目で作成したWeb ACLを選択
 ※APIのエンドポイントがリージョンの場合、同じリージョンのWeb ACLのみ選択可能
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/7900e166-ae92-759c-4e7c-b648967fd78d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/514ba9df-db77-88d4-a9ac-d93a4a494fd9.png)

Web ACLの項目が設定されていることが確認できればOKです！

### 4.リクエストのブロック確認
これでとりあえずAPIへWAF（Web ACL）を導入することが出来ました！
最初に正常確認ができたリクエストを送信してブロックされるのか試します。

```py:PowerShell
PS C:\Users> curl -Method POST -Uri "https://<your-api-id>.execute-api.<region>.amazonaws.co/WAF-test/waf-test-resource" -Headers @{ "Content-Type" = "application/json" } -Body '{"input": "1 OR 1=1"}'	
curl : {"message":"Forbidden"}	
発生場所 行:1 文字:1	
+ curl -Method POST -Uri "https:// ...	
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~	

PS C:\Users>	

```
お！レスポンスが変わり`{"message":"Forbidden"}`になりました！

AWS WAF＞Web ACLs＞作成したWeb ACLを選択
Traffic overview のタブからblockedのアクセス確認まで出来ればOKです!!
（念のため3回リクエストを送ったので、3件表示されています。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/599dd95c-b26a-ba83-9084-d79e287e2af6.png)

### 5.Web ACLのログの有効化
ここではWeb ACL用のロググループを作成し、評価したリクエスト情報を確認できるよう設定まで。

 **詳細手順**
 * 「CloudWatch」の「ロググループ」からロググループの作成
 ※Web ACLのログ設定からもロググループの新規作成タブに飛べます
<font color="red">ロググループ名は`aws-waf-logs`を先頭に付ける必要有り！</font>
（好きな名前で作成したら、設定するロググループの選択肢に出てきませんでした...）
>The name of any logging destination must start with `aws-waf-logs-`. For additional information and requirements for each destination type, see the AWS WAF documentation for logging web ACL traffic.
 
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/0a97ec32-1b80-32da-7b77-4a5b6aab3474.png)

* Web ACLのログ設定を有効化
* 出力先に作成したロググループを設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/b00458e6-632e-2581-8c13-c794ed9d452e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/0d05fa6b-b3d1-e5c7-1d61-baab263865d2.png)

ログの設定がEnabledの指定したロググループになっていればOKです！

### 6.Web ACLの評価ログの確認
ここでは、再度APIにリクエストを送り、Web ACLのログの中身を確認まで。

同じようにAPIへリクエストを送り`Forbidden`を確認しました。

```py:PowerShell
PS C:\Users> curl -Method POST -Uri "https://<your-api-id>.execute-api.<region>.amazonaws.co/WAF-test/waf-test-resource" -Headers @{ "Content-Type" = "application/json" } -Body '{"input": "1 OR 1=1"}'	
curl : {"message":"Forbidden"}	
発生場所 行:1 文字:1	
+ curl -Method POST -Uri "https:// ...	
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~	

PS C:\Users>	

```

CloudWatchのロググループから、ログを確認します。

ちゃんとログが来てますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3879433/3496f0a7-753e-a5ea-5643-8defd982cf6a.png)

中身を見てみます。（一部「非公開」に置き換えています）
`action": "BLOCK`
`ruleGroupId": "AWS#AWSManagedRulesSQLiRuleSet`
→今回設定したRuleでのブロックが確認できました！

`clientIp`や`User-Agent`情報も確認できましたので、攻撃の送信元IPも確認できます。

```java:CloudWachログ
{
    "timestamp": 1731138337291,
    "formatVersion": 1,
    "webaclId": "非公開",
    "terminatingRuleId": "Default_Action",
    "terminatingRuleType": "REGULAR",
    "action": "BLOCK",
    "terminatingRuleMatchDetails": [],
    "httpSourceName": "APIGW",
    "httpSourceId": "非公開",
    "ruleGroupList": [
        {
            "ruleGroupId": "AWS#AWSManagedRulesSQLiRuleSet",
            "terminatingRule": null,
            "nonTerminatingMatchingRules": [],
            "excludedRules": null,
            "customerConfig": null
        }
    ],
    "rateBasedRuleList": [],
    "nonTerminatingMatchingRules": [],
    "requestHeadersInserted": null,
    "responseCodeSent": null,
    "httpRequest": {
        "clientIp": "非公開",
        "country": "非公開",
        "headers": [
            {
                "name": "X-Forwarded-For",
                "value": "非公開"
            },
            {
                "name": "X-Forwarded-Proto",
                "value": "https"
            },
            {
                "name": "X-Forwarded-Port",
                "value": "443"
            },
            {
                "name": "Host",
                "value": "非公開"
            },
            {
                "name": "X-Amzn-Trace-Id",
                "value": "非公開"
            },
            {
                "name": "Content-Length",
                "value": "21"
            },
            {
                "name": "Content-Type",
                "value": "application/json"
            },
            {
                "name": "User-Agent",
                "value": "非公開"
            }
        ],
        "uri": "/WAF-test/waf-test-resource",
        "args": "",
        "httpVersion": "HTTP/1.1",
        "httpMethod": "POST",
        "requestId": "非公開"
    },
    "requestBodySize": 21,
    "requestBodySizeInspectedByWAF": 21
}

```

## おわりに
今回はAWS WAFのWeb ACLでのSQLインジェクションのブロックとそのログを確認することが出来ました。
（ただし、Bodyを空にしたリクエストでもブロックされ、WebACL設定後の許可リクエストまでは確認未実施。）

今回の内容はブロックされることと、そのログの確認まででしたので以上とします。
あと、もしもこの記事を見て試してみた人が居ましたらリソース（API / Web ACL / ロググループ）の削除をお忘れなく！