

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 查詢 AWS WAF 日誌
<a name="waf-logs"></a>

AWS WAF 是一種 Web 應用程式防火牆，可讓您監控和控制受保護 Web 應用程式從用戶端收到的 HTTP 和 HTTPS 請求。您可以透過在 Web 存取控制清單 (ACL) 中設定規則來定義如何處理 AWS WAF Web 請求。然後，您可以透過將 Web ACL 與 Web 應用程式建立關聯來保護 Web 應用程式。您可以使用 保護的 Web 應用程式資源範例 AWS WAF 包括 Amazon CloudFront 分佈、Amazon API Gateway REST APIs 和 Application Load Balancer。如需 的詳細資訊 AWS WAF，請參閱《 *AWS WAF 開發人員指南*[AWS WAF](https://docs.aws.amazon.com/waf/latest/developerguide/waf-chapter.html)》中的 。

AWS WAF 日誌包含 Web ACL 所分析流量的相關資訊，例如從您的 AWS 資源 AWS WAF 接收請求的時間、請求的詳細資訊，以及每個請求相符之規則的動作。

您可以設定 AWS WAF Web ACL 將日誌發佈到多個目的地之一，您可以在其中查詢和檢視它們。如需有關設定 Web ACL 記錄和 AWS WAF 日誌內容的詳細資訊，請參閱*AWS WAF 《 開發人員指南*》中的[記錄 AWS WAF Web ACL 流量](https://docs.aws.amazon.com/waf/latest/developerguide/logging.html)。

如需有關如何使用 Athena 分析 AWS WAF 日誌以深入了解威脅偵測和潛在安全攻擊的資訊，請參閱 AWS 網路與內容交付部落格文章[如何使用 Amazon Athena 查詢來分析 AWS WAF 日誌並提供威脅偵測所需的可見性](https://aws.amazon.com/blogs/networking-and-content-delivery/how-to-use-amazon-athena-queries-to-analyze-aws-waf-logs-and-provide-the-visibility-needed-for-threat-detection/)。

如需如何將 AWS WAF 日誌彙總到中央資料湖儲存庫並使用 Athena 查詢日誌的範例，請參閱 AWS 大數據部落格文章[使用 OpenSearch Service、Amazon Athena 和 Quick 分析 AWS WAF 日誌](https://aws.amazon.com/blogs/big-data/analyzing-aws-waf-logs-with-amazon-es-amazon-athena-and-amazon-quicksight/)。

本主題提供分割區投影、手動分割以及不使用任何分割的範例 `CREATE TABLE` 陳述式。

**注意**  
所以本主題中的 `CREATE TABLE` 陳述式可同時用於 v1 和 v2 AWS WAF 日誌。在 v1 中，`webaclid` 欄位含有一個 ID。在 v2 中，`webaclid` 欄位含有一個完整的 ARN。此 `CREATE TABLE` 陳述式藉由使用 `string` 資料類型，以不可知的方式處理此內容。

**Topics**
+ [使用分割區投影在 Athena 中建立 AWS WAF S3 日誌的資料表](create-waf-table-partition-projection.md)
+ [使用手動分割區在 Athena 中建立 AWS WAF S3 日誌的資料表](create-waf-table-manual-partition.md)
+ [建立 AWS WAF 日誌的資料表而不分割](create-waf-table.md)
+ [AWS WAF 日誌的範例查詢](query-examples-waf-logs.md)

# 使用分割區投影在 Athena 中建立 AWS WAF S3 日誌的資料表
<a name="create-waf-table-partition-projection"></a>

由於 AWS WAF 日誌具有已知的結構，您可以預先指定其分割區配置，因此您可以使用 Athena 分割區[投影功能來減少查詢執行時間並自動化分割區](partition-projection.md)管理。分割區投影會在新增資料時自動新增分割區。因此您無需使用 `ALTER TABLE ADD PARTITION` 手動新增分割區。

下列範例`CREATE TABLE`陳述式會自動在 AWS WAF 指定日期到四個不同 AWS 區域的 日誌上使用分割區投影。本範例中的 `PARTITION BY` 子句按區域和日期進行分割，但您可以根據自己的要求進行修改。視需要修改欄位，以符合您的日誌輸出。在 `LOCATION`和 `storage.location.template`子句中，將 *amzn-s3-demo-bucket* 和 *AWS\$1ACCOUNT\$1NUMBER* 預留位置取代為可識別 AWS WAF 日誌 Amazon S3 儲存貯體位置的值。對於 `projection.day.range`，請用您要使用的開始日期取代 *2021*/*01*/*01*。成功執行查詢之後，您可以查詢資料表。您無須執行 `ALTER TABLE ADD PARTITION` 就能載入分割區。

```
CREATE EXTERNAL TABLE `waf_logs_partition_projection`(
  `timestamp` bigint, 
  `formatversion` int, 
  `webaclid` string, 
  `terminatingruleid` string, 
  `terminatingruletype` string, 
  `action` string, 
  `terminatingrulematchdetails` array<struct<conditiontype:string,sensitivitylevel:string,location:string,matcheddata:array<string>>>, 
  `httpsourcename` string, 
  `httpsourceid` string, 
  `rulegrouplist` array<struct<rulegroupid:string,terminatingrule:struct<ruleid:string,action:string,rulematchdetails:array<struct<conditiontype:string,sensitivitylevel:string,location:string,matcheddata:array<string>>>>,nonterminatingmatchingrules:array<struct<ruleid:string,action:string,overriddenaction:string,rulematchdetails:array<struct<conditiontype:string,sensitivitylevel:string,location:string,matcheddata:array<string>>>,challengeresponse:struct<responsecode:string,solvetimestamp:string>,captcharesponse:struct<responsecode:string,solvetimestamp:string>>>,excludedrules:string>>, 
  `ratebasedrulelist` array<struct<ratebasedruleid:string,limitkey:string,maxrateallowed:int>>, 
  `nonterminatingmatchingrules` array<struct<ruleid:string,action:string,rulematchdetails:array<struct<conditiontype:string,sensitivitylevel:string,location:string,matcheddata:array<string>>>,challengeresponse:struct<responsecode:string,solvetimestamp:string>,captcharesponse:struct<responsecode:string,solvetimestamp:string>>>, 
  `requestheadersinserted` array<struct<name:string,value:string>>, 
  `responsecodesent` string, 
  `httprequest` struct<clientip:string,country:string,headers:array<struct<name:string,value:string>>,uri:string,args:string,httpversion:string,httpmethod:string,requestid:string,fragment:string,scheme:string,host:string>,
  `labels` array<struct<name:string>>, 
  `captcharesponse` struct<responsecode:string,solvetimestamp:string,failurereason:string>, 
  `challengeresponse` struct<responsecode:string,solvetimestamp:string,failurereason:string>, 
  `ja3fingerprint` string, 
  `ja4fingerprint` string, 
  `oversizefields` string, 
  `requestbodysize` int, 
  `requestbodysizeinspectedbywaf` int)
  PARTITIONED BY ( 
   `log_time` string)
ROW FORMAT SERDE 
  'org.openx.data.jsonserde.JsonSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://amzn-s3-demo-bucket/AWSLogs/AWS_ACCOUNT_NUMBER/WAFLogs/cloudfront/testui/'
TBLPROPERTIES (
 'projection.enabled'='true',
  'projection.log_time.format'='yyyy/MM/dd/HH/mm',
  'projection.log_time.interval'='1',
  'projection.log_time.interval.unit'='minutes',
  'projection.log_time.range'='2025/01/01/00/00,NOW',
  'projection.log_time.type'='date',
  'storage.location.template'='s3://amzn-s3-demo-bucket/AWSLogs/AWS_ACCOUNT_NUMBER/WAFLogs/cloudfront/testui/${log_time}')
```

**注意**  
範例中 `LOCATION`子句中的路徑格式是標準格式，但可能會根據您實作的 AWS WAF 組態而有所不同。例如，下列範例 AWS WAF 日誌路徑適用於 CloudFront 分佈：  

```
s3://amzn-s3-demo-bucket/AWSLogs/AWS_ACCOUNT_NUMBER/WAFLogs/cloudfront/cloudfronyt/2025/01/01/00/00/
```
如果您在建立或查詢 AWS WAF 日誌資料表時遇到問題，請確認日誌資料或[聯絡人 支援](https://console.aws.amazon.com/support/home/)的位置。

如需有關分割區投影的詳細資訊，請參閱[透過 Amazon Athena 使用分割區投影](partition-projection.md)。

# 使用手動分割區在 Athena 中建立 AWS WAF S3 日誌的資料表
<a name="create-waf-table-manual-partition"></a>

本節說明如何使用手動分割區為 AWS WAF 日誌建立資料表。

在 `LOCATION`和 `storage.location.template`子句中，將 *amzn-s3-demo-bucket* 和 *AWS\$1ACCOUNT\$1NUMBER* 預留位置取代為可識別 AWS WAF 日誌 Amazon S3 儲存貯體位置的值。

```
CREATE EXTERNAL TABLE `waf_logs_manual_partition`(
  `timestamp` bigint, 
  `formatversion` int, 
  `webaclid` string, 
  `terminatingruleid` string, 
  `terminatingruletype` string, 
  `action` string, 
  `terminatingrulematchdetails` array<struct<conditiontype:string,sensitivitylevel:string,location:string,matcheddata:array<string>>>, 
  `httpsourcename` string, 
  `httpsourceid` string, 
  `rulegrouplist` array<struct<rulegroupid:string,terminatingrule:struct<ruleid:string,action:string,rulematchdetails:array<struct<conditiontype:string,sensitivitylevel:string,location:string,matcheddata:array<string>>>>,nonterminatingmatchingrules:array<struct<ruleid:string,action:string,overriddenaction:string,rulematchdetails:array<struct<conditiontype:string,sensitivitylevel:string,location:string,matcheddata:array<string>>>,challengeresponse:struct<responsecode:string,solvetimestamp:string>,captcharesponse:struct<responsecode:string,solvetimestamp:string>>>,excludedrules:string>>, 
  `ratebasedrulelist` array<struct<ratebasedruleid:string,limitkey:string,maxrateallowed:int>>, 
  `nonterminatingmatchingrules` array<struct<ruleid:string,action:string,rulematchdetails:array<struct<conditiontype:string,sensitivitylevel:string,location:string,matcheddata:array<string>>>,challengeresponse:struct<responsecode:string,solvetimestamp:string>,captcharesponse:struct<responsecode:string,solvetimestamp:string>>>, 
  `requestheadersinserted` array<struct<name:string,value:string>>, 
  `responsecodesent` string, 
  `httprequest` struct<clientip:string,country:string,headers:array<struct<name:string,value:string>>,uri:string,args:string,httpversion:string,httpmethod:string,requestid:string,fragment:string,scheme:string,host:string>, 
  `labels` array<struct<name:string>>, 
  `captcharesponse` struct<responsecode:string,solvetimestamp:string,failurereason:string>, 
  `challengeresponse` struct<responsecode:string,solvetimestamp:string,failurereason:string>, 
  `ja3fingerprint` string, 
  `ja4fingerprint` string, 
  `oversizefields` string, 
  `requestbodysize` int, 
  `requestbodysizeinspectedbywaf` int)
  PARTITIONED BY ( `year` string, `month` string, `day` string, `hour` string, `min` string)
ROW FORMAT SERDE 
  'org.openx.data.jsonserde.JsonSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://amzn-s3-demo-bucket/AWSLogs/AWS_ACCOUNT_NUMBER/WAFLogs/cloudfront/webacl/'
```

# 建立 AWS WAF 日誌的資料表而不分割
<a name="create-waf-table"></a>

本節說明如何為 AWS WAF 日誌建立資料表，而無需分割或分割投影。

**注意**  
出於效能和成本考量，我們不建議使用非分割結構描述進行查詢。如需詳細資訊，請參閱 AWS 大數據部落格中的 [Amazon Athena 的前 10 個效能調校秘訣](https://aws.amazon.com/blogs/big-data/top-10-performance-tuning-tips-for-amazon-athena/)。

**建立 AWS WAF 資料表**

1. 複製下列 DDL 陳述式，並將其貼到 Athena 主控台。視需要修改欄位，以符合您的日誌輸出。修改 Amazon S3 儲存貯體的 `LOCATION` 以與存放日誌的儲存貯體相對應。

   此查詢會使用 [OpenX JSON SerDe](openx-json-serde.md)。
**注意**  
SerDe 預期每筆 JSON 文件都以單行文字表示，而且沒有行終止字元分隔記錄中的欄位。如果 JSON 文字是美化過的列印格式，則在建立資料表後嘗試在其中查詢時可能會收到下列錯誤訊息：HIVE\$1CURSOR\$1ERROR: Row is not a valid JSON Object (HIVE\$1CURSOR\$1ERROR：資料列不是有效的 JSON 物件) 或 HIVE\$1CURSOR\$1ERROR: JsonParseException: Unexpected end-of-input: expected close marker for OBJECT (HIVE\$1CURSOR\$1ERROR：JsonParseException：非預期的輸入結束：預期為 OBJECT 的關閉標記)。如需詳細資訊，請參閱 GitHub 上 OpenX SerDe 文件中的 [JSON 資料檔案](https://github.com/rcongiu/Hive-JSON-Serde#json-data-files)。

   ```
   CREATE EXTERNAL TABLE `waf_logs`(
     `timestamp` bigint,
     `formatversion` int,
     `webaclid` string,
     `terminatingruleid` string,
     `terminatingruletype` string,
     `action` string,
     `terminatingrulematchdetails` array <
                                       struct <
                                           conditiontype: string,
                                           sensitivitylevel: string,
                                           location: string,
                                           matcheddata: array < string >
                                             >
                                        >,
     `httpsourcename` string,
     `httpsourceid` string,
     `rulegrouplist` array <
                         struct <
                             rulegroupid: string,
                             terminatingrule: struct <
                                                 ruleid: string,
                                                 action: string,
                                                 rulematchdetails: array <
                                                                      struct <
                                                                          conditiontype: string,
                                                                          sensitivitylevel: string,
                                                                          location: string,
                                                                          matcheddata: array < string >
                                                                             >
                                                                       >
                                                   >,
                             nonterminatingmatchingrules: array <
                                                                 struct <
                                                                     ruleid: string,
                                                                     action: string,
                                                                     overriddenaction: string,
                                                                     rulematchdetails: array <
                                                                                          struct <
                                                                                              conditiontype: string,
                                                                                              sensitivitylevel: string,
                                                                                              location: string,
                                                                                              matcheddata: array < string >
                                                                                                 >
                                                                      >,
                                                                     challengeresponse: struct <
                                                                               responsecode: string,
                                                                               solvetimestamp: string
                                                                                 >,
                                                                     captcharesponse: struct <
                                                                               responsecode: string,
                                                                               solvetimestamp: string
                                                                                 >
                                                                       >
                                                                >,
                             excludedrules: string
                               >
                          >,
   `ratebasedrulelist` array <
                            struct <
                                ratebasedruleid: string,
                                limitkey: string,
                                maxrateallowed: int
                                  >
                             >,
     `nonterminatingmatchingrules` array <
                                       struct <
                                           ruleid: string,
                                           action: string,
                                           rulematchdetails: array <
                                                                struct <
                                                                    conditiontype: string,
                                                                    sensitivitylevel: string,
                                                                    location: string,
                                                                    matcheddata: array < string >
                                                                       >
                                                                >,
                                           challengeresponse: struct <
                                                               responsecode: string,
                                                               solvetimestamp: string
                                                                >,
                                           captcharesponse: struct <
                                                               responsecode: string,
                                                               solvetimestamp: string
                                                                >
                                             >
                                        >,
     `requestheadersinserted` array <
                                   struct <
                                       name: string,
                                       value: string
                                         >
                                    >,
     `responsecodesent` string,
     `httprequest` struct <
                       clientip: string,
                       country: string,
                       headers: array <
                                   struct <
                                       name: string,
                                       value: string
                                         >
                                    >,
                       uri: string,
                       args: string,
                       httpversion: string,
                       httpmethod: string,
                       requestid: string
                         >,
     `labels` array <
                  struct <
                      name: string
                        >
                   >,
     `captcharesponse` struct <
                           responsecode: string,
                           solvetimestamp: string,
                           failureReason: string
                             >,
     `challengeresponse` struct <
                           responsecode: string,
                           solvetimestamp: string,
                           failureReason: string
                           >,
     `ja3Fingerprint` string,
     `oversizefields` string,
     `requestbodysize` int,
     `requestbodysizeinspectedbywaf` int
   )
   ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
   STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'
   OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
   LOCATION 's3://amzn-s3-demo-bucket/prefix/'
   ```

1. 在 Athena 主控台查詢編輯器中執行 `CREATE EXTERNAL TABLE` 陳述式。這會註冊 `waf_logs` 資料表，並讓其中的資料可用於從 Athena 進行查詢。

# AWS WAF 日誌的範例查詢
<a name="query-examples-waf-logs"></a>

本節中有許多範例查詢使用先前建立的分割區投影資料表。請根據您的需求修改範例中的資料表名稱、資料欄值及其他變數。若要改善查詢的效能並降低成本，請在篩選條件中新增分割區資料欄。

**Topics**
+ [計數推薦網站、IP 位址或相符規則](query-examples-waf-logs-count.md)
+ [使用日期和時間的查詢](query-examples-waf-logs-date-time.md)
+ [查詢封鎖的請求或地址](query-examples-waf-logs-blocked-requests.md)

# 計數推薦網站、IP 位址或相符規則
<a name="query-examples-waf-logs-count"></a>

本節中的範例會查詢感興趣的日誌項目計數。
+ [Count the number of referrers that contain a specified term](#waf-example-count-referrers-with-specified-term)
+ [Count all matched IP addresses in the last 10 days that have matched excluded rules](#waf-example-count-matched-ip-addresses)
+ [Group all counted managed rules by the number of times matched](#waf-example-group-managed-rules-by-times-matched)
+ [Group all counted custom rules by number of times matched](#waf-example-group-custom-rules-by-times-matched)

**Example – 計算包含指定字詞的 Referrer 數量**  
以下查詢會計算在指定的日期範圍內包含 "amazon" 一詞的 Referrer 數量。  

```
WITH test_dataset AS 
  (SELECT header FROM waf_logs
    CROSS JOIN UNNEST(httprequest.headers) AS t(header) WHERE "date" >= '2021/03/01'
    AND "date" < '2021/03/31')
SELECT COUNT(*) referer_count 
FROM test_dataset 
WHERE LOWER(header.name)='referer' AND header.value LIKE '%amazon%'
```

**Example – 計算過去 10 天內符合排除規則的所有相符 IP 地址**  
以下查詢會計算過去 10 天內 IP 地址符合規則群組中排除規則的次數。  

```
WITH test_dataset AS 
  (SELECT * FROM waf_logs 
    CROSS JOIN UNNEST(rulegrouplist) AS t(allrulegroups))
SELECT 
  COUNT(*) AS count, 
  "httprequest"."clientip", 
  "allrulegroups"."excludedrules",
  "allrulegroups"."ruleGroupId"
FROM test_dataset 
WHERE allrulegroups.excludedrules IS NOT NULL AND from_unixtime(timestamp/1000) > now() - interval '10' day
GROUP BY "httprequest"."clientip", "allrulegroups"."ruleGroupId", "allrulegroups"."excludedrules"
ORDER BY count DESC
```

**Example – 依相符的次數對所有計數的受管規則進行分組**  
如果您在 2022 年 10 月 27 日之前將規則群組規則動作設定為 Web ACL 組態中的計數，則 會將 Web ACL JSON 中的覆寫 AWS WAF 儲存為 `excludedRules`。現在，將規則覆寫為計數的 JSON 設定位於 `ruleActionOverrides` 設定中。如需詳細資訊，請參閱《*AWS WAF 開發人員指南*》中的[規則群組中的動作覆寫](https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-rule-group-override-options.html)。若要從新的日誌結構擷取「計數」模式下的受管規則，請查詢 `ruleGroupList` 區段中的 `nonTerminatingMatchingRules` 而非 `excludedRules` 欄位，如下列範例所示。  

```
SELECT
 count(*) AS count,
 httpsourceid,
 httprequest.clientip,
 t.rulegroupid, 
 t.nonTerminatingMatchingRules
FROM "waf_logs" 
CROSS JOIN UNNEST(rulegrouplist) AS t(t) 
WHERE action <> 'BLOCK' AND cardinality(t.nonTerminatingMatchingRules) > 0 
GROUP BY t.nonTerminatingMatchingRules, action, httpsourceid, httprequest.clientip, t.rulegroupid 
ORDER BY "count" DESC 
Limit 50
```

**Example – 依相符的次數對所有計數的自訂規則進行分組**  
下列查詢會依符合的次數，將所有計數的自訂規則分組。  

```
SELECT
  count(*) AS count,
         httpsourceid,
         httprequest.clientip,
         t.ruleid,
         t.action
FROM "waf_logs" 
CROSS JOIN UNNEST(nonterminatingmatchingrules) AS t(t) 
WHERE action <> 'BLOCK' AND cardinality(nonTerminatingMatchingRules) > 0 
GROUP BY t.ruleid, t.action, httpsourceid, httprequest.clientip 
ORDER BY "count" DESC
Limit 50
```

如需有關自訂規則和受管規則群組的日誌位置的資訊，請參閱《*AWS WAF 開發人員指南*》中的[監控和調校](https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-testing-activities.html)。

# 使用日期和時間的查詢
<a name="query-examples-waf-logs-date-time"></a>

本節中的範例包括使用日期和時間值的查詢。
+ [Return the timestamp field in human-readable ISO 8601 format](#waf-example-return-human-readable-timestamp)
+ [Return records from the last 24 hours](#waf-example-return-records-last-24-hours)
+ [Return records for a specified date range and IP address](#waf-example-return-records-date-range-and-ip)
+ [For a specified date range, count the number of IP addresses in five minute intervals](#waf-example-count-ip-addresses-in-date-range)
+ [Count the number of X-Forwarded-For IP in the last 10 days](#waf-example-count-x-forwarded-for-ip)

**Example – 以人類看得懂的 ISO 8601 格式傳回時間戳記欄位**  
以下查詢會使用 `from_unixtime` 和 `to_iso8601` 函數，以人類看得懂的 ISO 8601 格式傳回 `timestamp` 欄位 (例如 `2019-12-13T23:40:12.000Z`，而非 `1576280412771`) 查詢也會傳回 HTTP 來源名稱、來源 ID 和請求。  

```
SELECT to_iso8601(from_unixtime(timestamp / 1000)) as time_ISO_8601,
       httpsourcename,
       httpsourceid,
       httprequest
FROM waf_logs
LIMIT 10;
```

**Example – 傳回過去 24 小時的記錄**  
以下查詢會使用 `WHERE` 子句中的篩選條件，傳回過去 24 小時記錄的 HTTP 來源名稱、HTTP 來源 ID 和 HTTP 請求欄位。  

```
SELECT to_iso8601(from_unixtime(timestamp/1000)) AS time_ISO_8601, 
       httpsourcename, 
       httpsourceid, 
       httprequest 
FROM waf_logs
WHERE from_unixtime(timestamp/1000) > now() - interval '1' day
LIMIT 10;
```

**Example – 傳回指定日期範圍和 IP 地址的記錄**  
以下查詢會列出指定用戶端 IP 地址的指定日期範圍內的記錄。  

```
SELECT * 
FROM waf_logs 
WHERE httprequest.clientip='53.21.198.66' AND "date" >= '2021/03/01' AND "date" < '2021/03/31'
```

**Example – 如果是指定的日期範圍，則會計算每隔五分鐘的 IP 地址數量**  
以下查詢會針對特定日期範圍，計算每隔五分鐘的 IP 地址數量。  

```
WITH test_dataset AS 
  (SELECT 
     format_datetime(from_unixtime((timestamp/1000) - ((minute(from_unixtime(timestamp / 1000))%5) * 60)),'yyyy-MM-dd HH:mm') AS five_minutes_ts,
     "httprequest"."clientip" 
     FROM waf_logs 
     WHERE "date" >= '2021/03/01' AND "date" < '2021/03/31')
SELECT five_minutes_ts,"clientip",count(*) ip_count 
FROM test_dataset 
GROUP BY five_minutes_ts,"clientip"
```

**Example – 計算過去 10 天內的 X-Forwarded-For IP 數量**  
以下查詢會篩選請求標頭，並計算過去 10 天內的 X-Forwarded-For IP 數量。  

```
WITH test_dataset AS
  (SELECT header
   FROM waf_logs
   CROSS JOIN UNNEST (httprequest.headers) AS t(header)
   WHERE from_unixtime("timestamp"/1000) > now() - interval '10' DAY) 
SELECT header.value AS ip,
       count(*) AS COUNT 
FROM test_dataset 
WHERE header.name='X-Forwarded-For' 
GROUP BY header.value 
ORDER BY COUNT DESC
```

如需有關日期和時間函數的詳細資訊，請參閱 Trino 文件中的 [Date and time functions and operators](https://trino.io/docs/current/functions/datetime.html) (日期和時間函數和運算子)。

# 查詢封鎖的請求或地址
<a name="query-examples-waf-logs-blocked-requests"></a>

本節中的範例會查詢封鎖的請求或地址。
+ [Extract the top 100 IP addresses blocked by a specified rule type](#waf-example-extract-top-100-blocked-ip-by-rule)
+ [Count the number of times a request from a specified country has been blocked](#waf-example-count-request-blocks-from-country)
+ [Count the number of times a request has been blocked, grouping by specific attributes](#waf-example-count-request-blocks-by-attribute)
+ [Count the number of times a specific terminating rule ID has been matched](#waf-example-count-terminating-rule-id-matches)
+ [Retrieve the top 100 IP addresses blocked during a specified date range](#waf-example-top-100-ip-addresses-blocked-for-date-range)

**Example – 擷取遭到指定規則類型封鎖的前 100 個 IP 地址**  
以下查詢會擷取並計算在指定日期範圍內，已遭到 `RATE_BASED` 終止規則封鎖的前 100 個 IP 地址。  

```
SELECT COUNT(httpRequest.clientIp) as count,
httpRequest.clientIp
FROM waf_logs
WHERE terminatingruletype='RATE_BASED' AND action='BLOCK' and "date" >= '2021/03/01'
AND "date" < '2021/03/31'
GROUP BY httpRequest.clientIp
ORDER BY count DESC
LIMIT 100
```

**Example – 計算來自指定國家/地區遭到封鎖的請求次數**  
以下查詢會計算來自愛爾蘭 (IE) 的 IP 地址，並遭 `RATE_BASED` 終止規則封鎖的請求次數。  

```
SELECT 
  COUNT(httpRequest.country) as count, 
  httpRequest.country 
FROM waf_logs
WHERE 
  terminatingruletype='RATE_BASED' AND 
  httpRequest.country='IE'
GROUP BY httpRequest.country
ORDER BY count
LIMIT 100;
```

**Example – 計算遭封鎖的請求次數 (依特定屬性分組)**  
以下查詢會計算遭封鎖的請求次數，並以 WebACL、RuleId、ClientIP 和 HTTP Request URI 分組。  

```
SELECT 
  COUNT(*) AS count,
  webaclid,
  terminatingruleid,
  httprequest.clientip,
  httprequest.uri
FROM waf_logs
WHERE action='BLOCK'
GROUP BY webaclid, terminatingruleid, httprequest.clientip, httprequest.uri
ORDER BY count DESC
LIMIT 100;
```

**Example – 計算與特定終止規則 ID 相符的次數。**  
以下查詢會計算與特定終止規則 ID (`WHERE terminatingruleid='e9dd190d-7a43-4c06-bcea-409613d9506e'`) 相符的次數。查詢接著會以 WebACL、Action、ClientIP 和 HTTP Request URI 將結果分組。  

```
SELECT 
  COUNT(*) AS count,
  webaclid,
  action,
  httprequest.clientip,
  httprequest.uri
FROM waf_logs
WHERE terminatingruleid='e9dd190d-7a43-4c06-bcea-409613d9506e'
GROUP BY webaclid, action, httprequest.clientip, httprequest.uri
ORDER BY count DESC
LIMIT 100;
```

**Example – 擷取指定日期範圍內遭到封鎖的前 100 個 IP 地址**  
以下查詢會擷取在指定日期範圍內，已遭到封鎖的前 100 個 IP 地址。該查詢也會列出 IP 地址遭到封鎖的次數。  

```
SELECT "httprequest"."clientip", "count"(*) "ipcount", "httprequest"."country"
FROM waf_logs
WHERE "action" = 'BLOCK' and "date" >= '2021/03/01'
AND "date" < '2021/03/31'
GROUP BY "httprequest"."clientip", "httprequest"."country"
ORDER BY "ipcount" DESC limit 100
```