Logs abfragen AWS WAF - Amazon Athena

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Logs abfragen AWS WAF

AWS WAF ist eine Firewall für Webanwendungen, mit der Sie die HTTP- und HTTPS-Anfragen überwachen und steuern können, die Ihre geschützten Webanwendungen von Clients erhalten. Sie definieren, wie die Webanfragen behandelt werden sollen, indem Sie Regeln in einer AWS WAF Web Access Control List (ACL) konfigurieren. Anschließend schützen Sie eine Webanwendung, indem Sie ihr eine Web-ACL zuordnen. Beispiele für Webanwendungsressourcen, mit denen Sie sich schützen können, AWS WAF sind CloudFront Amazon-Distributionen, Amazon API Gateway-REST-APIs und Application Load Balancers. Weitere Informationen zu AWS WAF finden Sie AWS WAFim AWS WAF Entwicklerhandbuch.

AWS WAF Protokolle enthalten Informationen über den Traffic, der von Ihrer Web-ACL analysiert wird, z. B. die Uhrzeit, zu der die Anfrage von Ihrer AWS Ressource AWS WAF eingegangen ist, detaillierte Informationen zu der Anfrage und die Aktion für die Regel, der jede Anfrage entsprach.

Sie können eine AWS WAF Web-ACL so konfigurieren, dass sie Protokolle an einem von mehreren Zielen veröffentlicht, wo Sie sie abfragen und anzeigen können. Weitere Informationen zur Konfiguration der Web-ACL-Protokollierung und zum Inhalt der AWS WAF Protokolle finden Sie unter Logging AWS WAF Web ACL Traffic im AWS WAF Entwicklerhandbuch.

Ein Beispiel dafür, wie AWS WAF Logs in einem zentralen Data Lake-Repository zusammengefasst und mit Athena abgefragt werden können, finden Sie im AWS Big-Data-Blogbeitrag Analyzing AWS WAF logs with OpenSearch Service, Amazon Athena, and Amazon. QuickSight

In diesem Thema finden Sie zwei CREATE TABLE-Beispielanweisungen: eine, die Partitionierung verwendet, und eine, die keine Partitionierung verwendet.

Anmerkung

Die CREATE TABLE-Anweisungen in diesem Thema können sowohl für Version 1 als auch für Version 2 der AWS WAF -Protokolle verwendet werden. In Version 1 enthält das webaclid-Feld eine ID. In Version 2 enthält das webaclid-Feld einen vollständigen ARN. Die CREATE TABLE-Anweisungen behandeln diesen Inhalt agnostisch, indem sie den string-Datentyp verwenden.

Erstellen einer Tabelle für AWS WAF -S3-Protokolle in Athena mithilfe der Partitionsprojektion

Da AWS WAF Protokolle eine bekannte Struktur haben, deren Partitionsschema Sie im Voraus angeben können, können Sie die Abfragelaufzeit reduzieren und die Partitionsverwaltung automatisieren, indem Sie die Athena-Partitionsprojektionsfunktion verwenden. Partitionsprojektion fügt automatisch neue Partitionen hinzu, wenn neue Daten hinzugefügt werden. Dadurch entfällt die Notwendigkeit, Partitionen manuell mithilfe von ALTER TABLE ADD PARTITION hinzuzufügen.

Die folgende CREATE TABLE Beispielanweisung verwendet automatisch die Partitionsprojektion für AWS WAF Protokolle von einem bestimmten Datum bis heute für vier verschiedene AWS Regionen. Die PARTITION BY-Klausel in diesem Beispiel partitioniert nach Region und Datum, aber Sie können diesen Vorgang entsprechend Ihren Anforderungen ändern. Ändern Sie die Felder nach Bedarf, damit diese mit Ihrer Protokollausgabe übereinstimmen. Ersetzen Sie in den storage.location.template Klauseln LOCATION und die Platzhalter Bucket und accountID durch Werte, die den Amazon S3 S3-Bucket-Speicherort Ihrer Logs angeben. AWS WAF Ersetzen Sie für projection.day.range den 01.01.2021 durch das Startdatum, das Sie verwenden möchten. Nach dem erfolgreichen Ausführen der Abfrage können Sie die Tabelle abfragen. Sie müssen ALTER TABLE ADD PARTITION nicht ausführen, um die Partitionen zu laden.

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 ) PARTITIONED BY ( `region` string, `date` 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://DOC-EXAMPLE-BUCKET/AWSLogs/accountID/WAFLogs/region/DOC-EXAMPLE-WEBACL/' TBLPROPERTIES( 'projection.enabled' = 'true', 'projection.region.type' = 'enum', 'projection.region.values' = 'us-east-1,us-west-2,eu-central-1,eu-west-1', 'projection.date.type' = 'date', 'projection.date.range' = '2021/01/01,NOW', 'projection.date.format' = 'yyyy/MM/dd', 'projection.date.interval' = '1', 'projection.date.interval.unit' = 'DAYS', 'storage.location.template' = 's3://DOC-EXAMPLE-BUCKET/AWSLogs/accountID/WAFLogs/${region}/DOC-EXAMPLE-WEBACL/${date}/')
Anmerkung

Das Format des Pfads in der LOCATION Klausel im Beispiel ist Standard, kann aber je nach der AWS WAF Konfiguration, die Sie implementiert haben, variieren. Der folgende AWS WAF Beispielprotokollpfad bezieht sich beispielsweise auf eine CloudFront Distribution:

s3://DOC-EXAMPLE-BUCKET/AWSLogs/12345678910/WAFLogs/cloudfront/cloudfronyt/2022/08/08/17/55/

Wenn beim Erstellen oder Abfragen Ihrer AWS WAF Protokolltabelle Probleme auftreten, überprüfen Sie den Speicherort Ihrer Protokolldaten oder Ihres Kontakts AWS Support.

Weitere Informationen zur Partitionsprojektion finden Sie unter Partitionsprojektion mit Amazon Athena.

Eine Tabelle für AWS WAF Protokolle ohne Partitionierung erstellen

In diesem Abschnitt wird beschrieben, wie Sie eine Tabelle für AWS WAF Protokolle ohne Partitionierung oder Partitionsprojektion erstellen.

Anmerkung

Aus Leistungs- und Kostengründen empfehlen wir nicht, ein nicht partitioniertes Schema für Abfragen zu verwenden. Weitere Informationen finden Sie im AWS Big Data-Blog unter Die 10 besten Tipps zur Leistungsoptimierung für Amazon Athena.

Um die Tabelle zu erstellen AWS WAF

  1. Kopieren Sie die folgende DDL-Anweisung in die Athena-Konsole. Ändern Sie die Felder nach Bedarf, damit diese mit Ihrer Protokollausgabe übereinstimmen. Ändern Sie den LOCATION des Amazon-S3-Bucket, in dem die Protokolle gespeichert werden.

    Diese Abfrage verwendet die OpenX JSON SerDe.

    Anmerkung

    Das SerDe erwartet, dass sich jedes JSON-Dokument in einer einzigen Textzeile ohne Zeilenabschlusszeichen befindet, die die Felder im Datensatz trennen. Wenn der JSON-Text ein hübsches Druckformat hat, erhalten Sie möglicherweise eine Fehlermeldung wie HIVE_CURSOR_ERROR: Row is not a valid JSON Object oder HIVE_CURSOR_ERROR:: Unerwartet JsonParseException end-of-input: erwarteter Schließpunkt für OBJECT, wenn Sie versuchen, die Tabelle nach ihrer Erstellung abzufragen. Weitere Informationen finden Sie unter JSON-Datendateien in der SerDe OpenX-Dokumentation unter GitHub.

    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://DOC-EXAMPLE-BUCKET/prefix/'
  2. Führen Sie die CREATE EXTERNAL TABLE-Anweisung im Abfrage-Editor der Athena-Konsole aus. Dadurch wird die waf_logs-Tabelle registriert und die darin enthaltenen Daten für Abfragen von Athena verfügbar gemacht.

Beispielabfragen für Logs AWS WAF

Viele der folgenden Beispielabfragen fragen die zuvor in diesem Dokument erstellte Partitionsprojektionstabelle ab. Ändern Sie den Tabellennamen, die Spaltenwerte und andere Variablen in den Beispielen entsprechend Ihren Anforderungen. Um die Leistung Ihrer Abfragen zu verbessern und Kosten zu senken, fügen Sie die Partitionsspalte in der Filterbedingung hinzu.

 

 

 

Beispiel
– Zählt die Anzahl der Referrer, die einen bestimmten Begriff enthalten

Die folgende Abfrage zählt die Anzahl der Referrer, die den Begriff „amazon“ für den angegebenen Datumsbereich enthalten.

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%'
Beispiel
– Zählt alle übereinstimmenden IP-Adressen in den letzten 10 Tagen, die mit ausgeschlossenen Regeln übereinstimmen

Mit der folgenden Abfrage wird die Anzahl der Male in den letzten 10 Tagen gezählt, die die IP-Adresse der ausgeschlossenen Regel in der Regelgruppe entspricht.

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
Beispiel
– Gruppiert alle gezählten verwalteten Regeln nach der Anzahl der Treffer

Wenn Sie in Ihrer Web-ACL-Konfiguration vor dem 27. Oktober 2022 Regelaktionen für Regelgruppen auf Anzahl gesetzt AWS WAF haben, haben Sie Ihre Überschreibungen in der Web-ACL-JSON unter gespeichert. excludedRules Jetzt befindet sich die JSON-Einstellung zum Überschreiben einer Regel zum Zählen in den ruleActionOverrides-Einstellungen. Weitere Informationen finden Sie unter Aktionsüberschreibungen in Regelgruppen im AWS WAF -Entwicklerhandbuch. Um verwaltete Regeln im Zähl-Modus aus der neuen Protokollstruktur zu extrahieren, fragen Sie den Wert nonTerminatingMatchingRules im Abschnitt ruleGroupList statt im Feld excludedRules ab, wie im folgenden Beispiel.

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
Beispiel
– Gruppiert alle gezählten benutzerdefinierten Regeln nach der Anzahl der Treffer

Die folgende Abfrage gruppiert alle gezählten benutzerdefinierten Regeln nach der Anzahl der Übereinstimmungen.

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

Informationen zu den Protokollspeicherorten für benutzerdefinierte Regeln und verwaltete Regelgruppen finden Sie unter Überwachung und Optimierung im AWS WAF -Entwicklerhandbuch.

Arbeiten mit Datum und Uhrzeit

Beispiel
– Gibt das Zeitstempelfeld im menschenlesbaren ISO-8601-Format zurück

Die folgende Abfrage verwendet die from_unixtime- und to_iso8601-Funktionen, um das timestamp-Feld im menschenlesbaren ISO 8601-Format zurückzugeben (z. B. 2019-12-13T23:40:12.000Z statt 1576280412771). Die Abfrage gibt auch den HTTP-Quellnamen, die Quell-ID und die Anforderung zurück.

SELECT to_iso8601(from_unixtime(timestamp / 1000)) as time_ISO_8601, httpsourcename, httpsourceid, httprequest FROM waf_logs LIMIT 10;
Beispiel
– Gibt Datensätze der letzten 24 Stunden zurück

Die folgende Abfrage verwendet einen Filter in der WHERE-Klausel, um den HTTP-Quellnamen, die HTTP-Quell-ID und die HTTP-Anforderungsfelder für Datensätze der letzten 24 Stunden zurückzugeben.

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;
Beispiel
– Gibt Datensätze für einen angegebenen Datumsbereich und eine IP-Adresse zurück

Die folgende Abfrage listet die Datensätze in einem angegebenen Datumsbereich für eine angegebene Client-IP-Adresse auf.

SELECT * FROM waf_logs WHERE httprequest.clientip='53.21.198.66' AND "date" >= '2021/03/01' AND "date" < '2021/03/31'
Beispiel
– Zählt Sie für einen angegebenen Datumsbereich die Anzahl der IP-Adressen in 5-Minuten-Intervallen

Die folgende Abfrage zählt für einen bestimmten Datumsbereich die Anzahl der IP-Adressen in fünf Minuten Intervallen.

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"
Beispiel
– Zählt die Anzahl der X-Forwarded-For-IP in den letzten zehn Tagen

Die folgende Abfrage filtert die Anforderungsheader und zählt die Anzahl der X-Forwarded-For-IPs in den letzten zehn Tagen.

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

Weitere Informationen zu Datums- und Uhrzeitfunktionen finden Sie unter Datums- und Uhrzeitfunktionen und Operatoren in der Trino-Dokumentation.

Arbeiten mit blockierten Anforderungen und Adressen

Beispiel
– Extrahiert die Top-100-IP-Adressen, die von einem angegebenen Regeltyp blockiert werden

Die folgende Abfrage extrahiert und zählt die 100 häufigsten IP-Adressen, die während des angegebenen Datumsbereichs durch die RATE_BASED-Beendigungsregel blockiert wurden.

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
Beispiel
– Zählt, wie oft eine Anfrage aus einem bestimmten Land blockiert wurde

Die folgende Abfrage zählt, wie oft die Anforderung von einer IP-Adresse angekommen ist, die zu Irland (IE) gehört und von der RATE_BASED-Beendigungsregel gesperrt wurde.

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;
Beispiel
– Zählt, wie oft eine Anforderung blockiert wurde, gruppiert nach bestimmten Attributen

Die folgende Abfrage zählt, wie oft die Anfrage blockiert wurde, wobei die Ergebnisse nach WebACL RuleId, ClientIP und HTTP-Anforderungs-URI gruppiert sind.

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;
Beispiel
– Zählt, wie oft eine bestimmte beendende Regel-ID abgeglichen wurde

Die folgende Abfrage zählt, wie oft eine bestimmte Beendigungsregel-ID vorkam (WHERE terminatingruleid='e9dd190d-7a43-4c06-bcea-409613d9506e'). Die Abfrage gruppiert dann die Ergebnisse nach WebACL, Action, ClientIP und HTTP-Anforderungs-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;
Beispiel
– Abrufen der Top-100-IP-Adressen, die während eines angegebenen Datumsbereichs blockiert wurden

Die folgende Abfrage extrahiert die Top-100-IP-Adressen, die für einen angegebenen Datumsbereich gesperrt wurden. Die Abfrage listet auch auf, wie oft die IP-Adressen gesperrt wurden.

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