🐥

AWS WAFログ分析してみた(CloudWatch Logs Insights)

に公開

はじめに

担当している案件で WAFログを分析する必要があったため、
CloudWatch Logs Insightsを用いて分析してみました。

そもそもWAFログには何が記録されているのか

WAFログ:Web ACLまたはProtection Packで分析されたHTTPリクエストの詳細情報を記録したJSON形式のログ

主要なフィールド:

timestamp: リクエスト処理時刻(ミリ秒単位のタイムスタンプ)
formatVersion: ログフォーマットのバージョン
webaclId: Web ACLまたはProtection Packの識別子(GUID)
terminatingRuleId: マッチした終端ルールのID
terminatingRuleType: ルールのタイプ(REGULAR、RATE_BASED、GROUP、MANAGED_RULE_GROUP)
action: 実行されたアクション(ALLOW、BLOCK、COUNT、CAPTCHA、CHALLENGE)
clientIp: クライアントのIPアドレス(フィールド名はclientIp)
httpRequest: HTTPリクエストの詳細情報

WAFログの分析方法

  • CloudWatch Logs Insights
    手軽に始められる基本ツール
    AWS 標準のログ分析ツールで、SQL 風のクエリ構文でログを検索できます。結果はすぐにテーブルで可視化でき、設定も簡単で低コストです。日常的な監視や報告書の作成に最適で、初心者にもおすすめです。

  • Amazon Athena
    大量データの詳細分析用
    S3に保存された大量のログを詳しく分析できるサービスです。過去数ヶ月分のデータをまとめて処理し、複雑な統計分析が可能です。ただし、リアルタイム性は低く、データが準備されるまで時間がかかります。長期的な傾向分析や年次レポート作成に向いています。

  • OpenSearch Service
    本格的な監視システム用
    高度な検索機能と可視化ダッシュボードを提供する専門ツールです。リアルタイム監視やアラート機能が充実していますが、設定が複雑で運用コストも高くなります。24時間体制でのセキュリティ監視が必要な大規模組織向けです。
    CloudWatch Logs + OpenSearch Service 統合の選択肢もありそうです。

今回はシンプルで簡単なcloudwatchlogs insightを利用することにしました。

CloudWatch Logs Insightsのクエリを使ってログを分析

1.【cloudwatch】コンソールから【ログのインサイト】を選択
2.【期間】や【タイムゾーン】をフィルターし、【ロググループ】を選択
3.クエリ構文を入力して【クエリの実行】を押下

すぐにテーブルを作成してくれます。結果のエクスポートも可能です。

基本的なクエリ構文

CloudWatch Logs Insightsでは以下の基本構文を使用します:

fields [フィールド名1], [フィールド名2]
| filter [条件]
| stats [集計関数] by [グループ化フィールド]
| sort [ソート条件]
| limit [行数制限]

ブロックされたリクエストの詳細情報を時系列で取得する

fields 
  @timestamp,
  terminatingRuleId,
  httpRequest.httpMethod as method,
  httpRequest.uri as uri,
  httpRequest.country as country,
  httpRequest.clientIp as clientIp
| parse @message '{"name":"User-Agent","value":"*"}' as userAgent
| parse @message '"ruleId":"*",' as ruleId
| filter action='BLOCK'
| sort @timestamp desc
| display @timestamp, terminatingRuleId, ruleId, method, uri, country, clientIp, userAgent
| limit 100

取得するフィールド:
@timestamp: ブロックされた日時
terminatingRuleId: ブロックしたルールのID
httpRequest.httpMethod: HTTPメソッド(GET、POSTなど)
httpRequest.uri: アクセス先のURL
httpRequest.country: アクセス元の国
httpRequest.clientIp: アクセス元のIPアドレス

parse @message '{"name":"User-Agent","value":"*"}' as userAgent
:ログメッセージからUser-Agent情報を抽出

parse @message '"ruleId":"*",' as ruleId
:ログメッセージから詳細なルールIDを抽出

条件・並び順
filter action='BLOCK': ブロックされたリクエストのみに絞り込み
sort @timestamp desc: 新しい順(降順)で並び替え
limit: 取得数制限

最もアクセスが多いURL(リクエスト先)のランキングを取得する

fields httpRequest.uri
| stats count(*) as requestCount by httpRequest.uri
| sort requestCount desc
| limit 10

クエリの詳細:
処理の流れ
fields httpRequest.uri: URIフィールド(アクセス先URL)を選択
stats count(*) as requestCount by httpRequest.uri: URI別にリクエスト数をカウント
sort requestCount desc: リクエスト数の多い順で並び替え
limit 10: 上位10件のみ表示

取得できる情報:
人気のページ・エンドポイント: 最もアクセスされているURL
攻撃対象の傾向: 攻撃者が狙いやすいパス
トラフィック分析: サイト全体のアクセスパターン

国別のリクエスト数ランキング取得

fields httpRequest.country
| stats count(*) as requestCount by httpRequest.country
| sort requestCount desc
| limit 10

IPアドレス別のリクエスト数ランキング取得

fields clientIp
| stats count(*) as requestCount by httpRequest.clientIp
| sort requestCount desc
| limit 10

参考

https://dev.classmethod.jp/articles/aws-waf-cloudwatch-logs-insights/
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/CWL_QuerySyntax.html

Discussion