Passer au contenu

Comment analyser les journaux AWS WAF dans CloudWatch ?

Lecture de 7 minute(s)
0

Je souhaite analyser et filtrer mes journaux AWS WAF que je stocke dans Amazon CloudWatch.

Résolution

Pour analyser et filtrer des demandes de journaux AWS WAF spécifiques dans CloudWatch, utilisez CloudWatch Logs Insights ou le générateur de requêtes CloudWatch.

Utiliser CloudWatch Log Insights

Vous pouvez utiliser CloudWatch Log Insights dans la console CloudWatch ou dans la console AWS WAF.

Console AWS WAF

Procédez comme suit :

  1. Ouvrez la console AWS WAF.
  2. Dans le volet de navigation, choisissez Packs de protection (ACL Web).
  3. Sélectionnez votre pack de protection.
  4. Choisissez Afficher le tableau de bord, les journaux et les exemples de requêtes.
  5. Dans Explorateur de journaux, choisissez Afficher dans CloudWatch.
  6. Dans l'Éditeur de requête, saisissez votre requête. Utilisez la syntaxe de requête pour concevoir vos requêtes. Vous pouvez également choisir des requêtes dans la liste des requêtes les plus fréquemment utilisées.
  7. Sélectionnez Exécuter la requête.

Console CloudWatch

Procédez comme suit :

  1. Ouvrez la console CloudWatch.
  2. Dans le volet de navigation, sous Journaux, sélectionnez Logs Insights.
  3. Dans Critères de sélection, sélectionnez un ou plusieurs groupes de journaux à interroger. Vous pouvez également sélectionner Parcourir les groupes de journaux, puis sélectionner vos groupes de journaux.
  4. (Facultatif) Choisissez une période pour votre requête.
  5. Utilisez la syntaxe de requête pour concevoir vos requêtes.
  6. Pour consulter vos résultats, sélectionnez Exécuter la requête.

Utiliser le générateur de requêtes CloudWatch

Pour utiliser le langage naturel pour générer des requêtes et analyser vos journaux d'accès, exécutez le générateur de requêtes dans CloudWatch.

Exemples de requêtes 

Pour filtrer des informations spécifiques avec CloudWatch Logs Insights, utilisez les exemples de requêtes suivants.

Principales adresses IP des clients

Pour comptabiliser les principales adresses IP des clients qui accèdent à votre application, exécutez la requête suivante :

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

Principaux pays

Pour comptabiliser les principaux pays source qui adressent des requêtes à votre application, exécutez la requête suivante :

stats count(*) as RequestCount by httpRequest.country as Country
| sort RequestCount desc

Principales méthodes HTTP

Pour comptabiliser les principales méthodes HTTP qui accèdent à votre application, exécutez la requête suivante :

stats count(*)as RequestCount by httpRequest.httpMethod as Method
| sort RequestCount desc

Principales règles de résiliation

Pour comptabiliser les principales règles de résiliation dans vos journaux, exécutez la requête suivante :

stats count(*) as RequestCount by terminatingRuleId
| sort RequestCount desc

Principaux hôtes

Pour comptabiliser les principaux hôtes qui accèdent à votre application, exécutez la requête suivante :

parse @message /\{"name":"[Hh]ost","value":"(?<Host>[^"]*)"/
| stats count(*) as RequestCount by Host
| sort RequestCount desc

Principaux agents utilisateur

Pour comptabiliser les principaux agents utilisateur qui accèdent à votre application, exécutez la requête suivante :

parse @message /\{"name":"[Uu]ser\-[Aa]gent","value":"(?<UserAgent>[^"]*)"/  
| stats count(*) as RequestCount by UserAgent
| sort RequestCount desc

Principales adresses X-forwarded-Ips

Pour comptabiliser les principales adresses IP XFF qui adressent des requêtes à votre application, exécutez la requête suivante :

parse @message /\{"name":"[Xx]-[Ff]orwarded-[Ff]or","value":"(?<XFF_IP>[^"}]*)/
| stats count(*) as RequestCount by XFF
| sort RequestCount desc

Principales adresses IP bloquées par la règle fréquentielle

Pour trouver les adresses IP qui dépassent le seuil et en cas d'attaque par inondation HTTP (DDoS), exécutez la requête suivante :

fields httpRequest.clientIp
| filter terminatingRuleType = "RATE_BASED" ## and webaclId = "<Webacl ARN>" ## uncomment to filter for specific WebACL|
| stats count(*) as requestCount by httpRequest.clientIp, httpRequest.country
| sort requestCount desc
| limit 100

Filtrer en fonction des requêtes bloquées

Pour filtrer toutes les requêtes bloquées, ainsi que la règle de résiliation, le chemin URI et l’adresse IP client respectifs, exécutez la requête suivante :

fields @timestamp, httpRequest.clientIp as ClientIP, httpRequest.uri as URI, terminatingRuleId as rule
| filter action = "BLOCK"
| sort @timestamp desc

Filtrer par hôte

Pour filtrer vos journaux en fonction d'un hôte spécifique, exécutez la requête suivante :

fields terminatingRuleId as Rule, action, httpRequest.country as Country, httpRequest.clientIp as ClientIP, httpRequest.uri as URI
| parse @message /\{"name":"[Hh]ost","value":"(?<Host>[^"]*)"/  
| filter Host = "www.example.com"

Remarque : Remplacez www.example.com par le nom de votre hôte.

Filtrer en fonction d’une chaîne spécifique

Pour filtrer vos journaux selon une chaîne spécifique, exécutez la requête suivante :

fields terminatingRuleId as Rule, action, httpRequest.country as Country, httpRequest.clientIp as ClientIP, httpRequest.httpMethod as Method,httpRequest.uri as URI
| parse @message /\{"name":"[Hh]ost","value":"(?<Host>[^"]*)"/
| parse @message /\{"name":"[Uu]ser\-[Aa]gent","value":"(?<UserAgent>[^"]*)"/  
| filter @message like "{jndi:ldap"
| sort action, URI desc

Remarque : Remplacez {jndi:ldap par votre chaîne.

Filtrer en fonction de requêtes POST

Pour filtrer les requêtes POST, exécutez la requête suivante :

fields terminatingRuleId as Rule, action, httpRequest.country as Country, httpRequest.clientIp as ClientIP, httpRequest.httpMethod as Method, httpRequest.uri as URI
| parse @message /\{"name":"[Uu]ser\-[Aa]gent","value":"(?<UserAgent>[^"]*)"/  
| parse @message /\{"name":"[Hh]ost","value":"(?<Host>[^"]*)"/  
| filter httpRequest.httpMethod ="POST"
| display Rule, action, Country, ClientIP, Method, URI, Host, UserAgent
| sort Rule, action desc

REMARQUE : Vous pouvez utiliser la requête précédente pour filtrer selon d'autres méthodes HTTP. Remplacez POST par GET, Tête ou d'autres méthodes HTTP.

Injection XSS ou SQL

Pour trouver des modèles de scripts inter-site (XSS) qui provoquent une injection SQL dans les règles de résiliation de règles personnalisées ou de groupes de règles gérées par AWS, exécutez la requête suivante.

fields @timestamp  
| parse @message ',"terminatingRuleMatchDetails":[*],' as terminatingRuleMatchData  
| filter (terminatingRuleMatchData like /XSS/ or terminatingRuleMatchData like /SQL/)  
| display @timestamp, httpRequest.clientIp, httpRequest.country, terminatingRuleMatchData, httpRequest.requestId

La requête affiche les entrées avec un horodatage, l'adresse IP du client, le pays d'origine, les détails de la correspondance et l'ID de la requête.

Filtrer par pays

Pour filtrer les requêtes qui ne proviennent pas d'un pays spécifique, exécutez la requête suivante :

fields terminatingRuleId as Rule, action, httpRequest.country as Country, httpRequest.clientIp as ClientIP, httpRequest.uri as URI
| parse @message /\{"name":"[Uu]ser\-[Aa]gent","value":"(?<UserAgent>[^"]*)"/  
| parse @message /\{"name":"[Hh]ost","value":"(?<Host>[^"]*)"/
| filter Country != "US"
| sort Country, action desc

Remarque : Remplacez USA par le code pays que vous souhaitez filtrer.

Filtrer en fonction de requêtes comptabilisées par une règle spécifique dans un groupe de règles

Pour filtrer les entrées de journal des requêtes qu'une règle spécifique d'un groupe de règles comptabilise et résilie par défaut, exécutez la requête suivante :

fields @timestamp
| filter (@message like 'excludedRules":[{"exclusionType":"EXCLUDED_AS_COUNT","ruleId":"NoUserAgent_HEADER"}]}' and @message like 'terminatingRuleId":"Default_Action"')
| parse @message '"ruleId":*}]}' as ruleMatchDetails
| display @timestamp, httpRequest.clientIp, httpRequest.country, ruleMatchDetails, httpRequest.requestId

Remarque : Remplacez ruleId par l’ID de la règle.

Filtrer en fonction de requêtes avec un CAPTCHA non valide

Pour filtrer les 100 principales requêtes avec un CAPTCHA non valide, exécutez la requête suivante :

fields @timestamp, httpRequest.clientIp, httpRequest.requestId, captchaResponse.failureReason, @message
| filter captchaResponse.failureReason ='TOKEN_MISSING'
| sort @timestamp desc| limit 100

Remarque : Remplacez 100 dans la clause limite par le nombre de requêtes pour lesquelles vous souhaitez filtrer.

Cette requête indique l'heure de la requête, l'adresse IP, l'ID de la requête, le code de réponse et l'intégralité du message.

Filtrer toutes les requêtes détectées par les règles gérées ABC, ATP, ACFP et AntiDDOS

Pour filtrer les 100 principales requêtes qui correspondent aux libellés de règles gérées par AWS ABC, ATP, ACFP ou AntiDDOS, exécutez la requête suivante :

fields @timestamp
| filter @message like 'awswaf:managed:aws:bot-control'
| display @timestamp,httpRequest.clientIp, httpRequest.uri,Labels, @message
| sort @timestamp desc
| limit 100

Remarque : Remplacez 100 dans la clause limite par le nombre de requêtes pour lesquelles vous souhaitez filtrer. Remplacez awswaf:managed:aws:bot-control par le libellé du groupe de règles. Pour le groupe de règles ATP, utilisez awswaf:managed:aws:atp. Pour le groupe de règles ACFP, utilisez awswaf:managed:aws:acfp. Pour le groupe de règles AntiDDOS AMR, utilisez awswaf:managed:aws:anti-ddos.

Pour filtrer les journaux avec un libellé spécifique, incluez la ligne suivante dans la requête précédente :

| filter @message like 'awswaf:managed:aws:bot-control:signal:non_browser_user_agent'