Collecter les journaux du WAF Fastly
Présentation
Cet analyseur extrait des champs des journaux JSON du WAF Fastly, les transforme et les renomme, puis les met en correspondance avec l'UDM. Il gère différents types de données, convertit les niveaux de gravité et catégorise les événements en fonction des informations d'adresse IP et de nom d'hôte disponibles. Il gère également les échecs d'analyse potentiels et supprime les entrées de journal mal formées.
Avant de commencer
- Assurez-vous de disposer d'une instance Google SecOps.
- Un compte Fastly avec accès à la configuration des paramètres du WAF
Configurer un flux dans Google SecOps pour ingérer les journaux du WAF Fastly
- Accédez à Paramètres du SIEM > Flux.
- Cliquez sur Ajouter.
- Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple, Journaux du WAF Fastly).
- Sélectionnez Webhook comme type de source.
- Sélectionnez Fastly WAF comme type de journal.
- Cliquez sur Suivant.
- Facultatif: spécifiez des valeurs pour les paramètres d'entrée suivants :
- Délimiteur de fractionnement: délimiteur utilisé pour séparer les lignes de journal, par exemple
\n
. - Espace de noms des éléments: espace de noms des éléments.
- Libellés d'ingestion: libellé appliqué aux événements de ce flux.
- Délimiteur de fractionnement: délimiteur utilisé pour séparer les lignes de journal, par exemple
- Cliquez sur Suivant.
- Vérifiez la configuration du flux dans l'écran Finaliser, puis cliquez sur Envoyer.
- Cliquez sur Générer une clé secrète pour générer une clé secrète permettant d'authentifier ce flux.
- Copiez et stockez la clé secrète. Vous ne pourrez plus afficher cette clé secrète. Si nécessaire, vous pouvez générer une nouvelle clé secrète, mais cette action rend l'ancienne clé secrète obsolète.
- Dans l'onglet Détails, copiez l'URL du point de terminaison du flux dans le champ Informations sur le point de terminaison. Vous devez spécifier cette URL de point de terminaison dans votre application cliente.
- Cliquez sur OK.
Créer une clé API pour le flux webhook
Accédez à la console Google Cloud > Identifiants.
Cliquez sur Créer des identifiants, puis sélectionnez Clé API.
Limitez l'accès de la clé API à l'API Google Security Operations.
Spécifier l'URL du point de terminaison
- Dans votre application cliente, spécifiez l'URL du point de terminaison HTTPS fournie dans le flux de webhook.
Activez l'authentification en spécifiant la clé API et la clé secrète dans l'en-tête personnalisé au format suivant:
X-goog-api-key = API_KEY X-Webhook-Access-Key = SECRET
Recommandation: Spécifiez la clé API en tant qu'en-tête plutôt que dans l'URL.
Si votre client webhook n'est pas compatible avec les en-têtes personnalisés, vous pouvez spécifier la clé API et la clé secrète à l'aide de paramètres de requête au format suivant:
ENDPOINT_URL?key=API_KEY&secret=SECRET
Remplacez les éléments suivants :
ENDPOINT_URL
: URL du point de terminaison du flux.API_KEY
: clé API permettant de s'authentifier auprès de Google Security Operations.SECRET
: clé secrète que vous avez générée pour authentifier le flux.
Configurer le webhook dans Fastly
- Connectez-vous à Fastly.
- (Facultatif) Sélectionnez un site dans le menu Sites (si vous possédez plusieurs sites).
- Sélectionnez Gérer > Intégrations de sites.
- Cliquez sur Ajouter une intégration de site.
- Sélectionnez Webhook générique.
- URL du webhook: saisissez l'ENDPOINT_URL Google SecOps, suivi de API_KEY et de SECRET.
- Emplacement de l'alerte: sélectionnez Toute activité ou Activité spécifique.
- Facultatif: Si vous avez sélectionné Activité spécifique, accédez au menu Activité et sélectionnez les types d'activités que vous souhaitez que le webhook envoie.
- Cliquez sur Créer une intégration de site.
Tableau de mappage UDM
Champ de journal | Mappage UDM | Logique |
---|---|---|
anomaly_score |
security_result.detection_fields[].key : "anomaly"security_result.detection_fields[].value : anomaly_score |
Si waf.score.anomaly est égal à 0 ou vide, et que anomaly_score n'est pas vide ni égal à 0, la valeur anomaly_score est utilisée pour renseigner le tableau security_result.detection_fields avec une clé "anomaly" (anomalie) et la valeur du champ anomaly_score . |
cache_status |
additional.fields[].key : "cache_status"additional.fields[].value.string_value : cache_status |
La valeur cache_status permet de renseigner le tableau additional.fields avec une clé "cache_status" et la valeur du champ cache_status . |
client_ip |
principal.ip : client_ip |
Le champ client_ip est mappé sur principal.ip . |
connection.fastly_is_edge |
additional.fields[].key : "fastly_is_edge"additional.fields[].value.bool_value : connection.fastly_is_edge |
La valeur connection.fastly_is_edge permet de renseigner le tableau additional.fields avec une clé "fastly_is_edge" et la valeur du champ connection.fastly_is_edge . |
connection.fastly_is_shield |
additional.fields[].key : "fastly_is_shield"additional.fields[].value.bool_value : connection.fastly_is_shield |
La valeur connection.fastly_is_shield permet de renseigner le tableau additional.fields avec une clé "fastly_is_shield" et la valeur du champ connection.fastly_is_shield . |
connection.request_tls_version |
network.tls.version : connection.request_tls_version |
Le champ connection.request_tls_version est mappé sur network.tls.version . |
fastly.server |
target.hostname : fastly.server |
Le champ fastly.server est mappé sur target.hostname . |
fastly.service_id |
additional.fields[].key : "service_id"additional.fields[].value.string_value : fastly.service_id |
La valeur fastly.service_id permet de renseigner le tableau additional.fields avec une clé "service_id" et la valeur du champ fastly.service_id . |
geo.city |
principal.location.city : geo.city |
Le champ geo.city est mappé sur principal.location.city . |
geo.country |
principal.location.country_or_region : geo.country |
Le champ geo.country est mappé sur principal.location.country_or_region . |
geo.location |
principal.location.region_latitude : extrait de geo.location principal.location.region_longitude : extrait de geo.location |
La latitude et la longitude sont extraites du champ geo.location à l'aide d'une expression régulière et mappées sur principal.location.region_latitude et principal.location.region_longitude , respectivement. |
geo.region |
principal.location.state : geo.region |
Le champ geo.region est mappé sur principal.location.state . |
host |
principal.hostname : host |
Le champ host est mappé sur principal.hostname . |
request_headers.accept_charset |
additional.fields[].key : "accept_charset"additional.fields[].value.string_value : request_headers.accept_charset |
La valeur request_headers.accept_charset permet de renseigner le tableau additional.fields avec une clé "accept_charset" et la valeur du champ request_headers.accept_charset . |
request_headers.accept_language |
additional.fields[].key : "accept_language"additional.fields[].value.string_value : request_headers.accept_language |
La valeur request_headers.accept_language permet de renseigner le tableau additional.fields avec une clé "accept_language" et la valeur du champ request_headers.accept_language . |
request_headers.referer |
network.http.referral_url : request_headers.referer |
Le champ request_headers.referer est mappé sur network.http.referral_url . |
request_headers.user_agent |
network.http.user_agent : request_headers.user_agent |
Le champ request_headers.user_agent est mappé sur network.http.user_agent . |
request_id |
metadata.product_log_id : request_id |
Le champ request_id est mappé sur metadata.product_log_id . |
request_method |
network.http.method : request_method |
Le champ request_method est mappé sur network.http.method . |
response_headers.cache_control |
additional.fields[].key : "cache_control"additional.fields[].value.string_value : response_headers.cache_control |
La valeur response_headers.cache_control permet de renseigner le tableau additional.fields avec une clé "cache_control" et la valeur du champ response_headers.cache_control . |
response_headers.content_type |
additional.fields[].key : "content_type"additional.fields[].value.string_value : response_headers.content_type |
La valeur response_headers.content_type permet de renseigner le tableau additional.fields avec une clé "content_type" et la valeur du champ response_headers.content_type . |
response_state |
additional.fields[].key : "response_state"additional.fields[].value.string_value : response_state |
La valeur response_state permet de renseigner le tableau additional.fields avec une clé "response_state" et la valeur du champ response_state . |
response_status |
network.http.response_code : response_status |
Le champ response_status est mappé sur network.http.response_code si le champ status est vide. |
rule_id |
security_result.rule_id : rule_id |
Si waf.rule_id est vide, la valeur rule_id est utilisée pour renseigner security_result.rule_id . |
severity |
waf.severity : severity |
La valeur du champ severity est copiée dans waf.severity . |
size_bytes.request_header |
network.sent_bytes : size_bytes.request_header |
Le champ size_bytes.request_header est mappé sur network.sent_bytes . |
size_bytes.response_header |
network.received_bytes : size_bytes.response_header |
Le champ size_bytes.response_header est mappé sur network.received_bytes . |
status |
network.http.response_code : status |
Le champ status est mappé sur network.http.response_code . |
timestamp |
metadata.event_timestamp : timestamp |
Le champ timestamp est analysé et mappé sur metadata.event_timestamp . |
url |
target.url : url |
Le champ url est mappé sur target.url . |
waf.blocked |
security_result.action : dérivé |
Si waf.blocked est défini sur "false", security_result.action est défini sur "ALLOW". Si waf.blocked est défini sur "true", security_result.action est défini sur "BLOCK". |
waf.executed |
security_result.detection_fields[].key : "executed"security_result.detection_fields[].value : waf.executed |
La valeur waf.executed permet de renseigner le tableau security_result.detection_fields avec une clé "executed" et la valeur du champ waf.executed . |
waf.failures |
security_result.detection_fields[].key : "failures"security_result.detection_fields[].value : waf.failures |
La valeur waf.failures permet de renseigner le tableau security_result.detection_fields avec une clé "failures" et la valeur du champ waf.failures . |
waf.logged |
security_result.detection_fields[].key : "logged"security_result.detection_fields[].value : waf.logged |
La valeur waf.logged permet de renseigner le tableau security_result.detection_fields avec une clé "logged" et la valeur du champ waf.logged . |
waf.message |
metadata.description : waf.message |
Si waf.message n'est pas vide, il est mappé sur metadata.description . |
waf.rule_id |
security_result.rule_id : waf.rule_id |
Si waf.rule_id n'est pas vide, il est mappé sur security_result.rule_id . |
waf.score.anomaly |
security_result.detection_fields[].key : "anomaly"security_result.detection_fields[].value : waf.score.anomaly |
Si waf.score.anomaly n'est pas égal à 0 et n'est pas vide, la valeur est utilisée pour renseigner le tableau security_result.detection_fields avec une clé "anomaly" et la valeur du champ waf.score.anomaly . |
waf.score.http_violation |
security_result.detection_fields[].key : "http_violation"security_result.detection_fields[].value : waf.score.http_violation |
Si waf.score.http_violation n'est pas égal à 0 et n'est pas vide, la valeur est utilisée pour renseigner le tableau security_result.detection_fields . |
waf.score.lfi |
security_result.detection_fields[].key : "lfi"security_result.detection_fields[].value : waf.score.lfi |
Logique similaire à waf.score.http_violation . |
waf.score.php_injection |
security_result.detection_fields[].key : "php_injection"security_result.detection_fields[].value : waf.score.php_injection |
Logique similaire à waf.score.http_violation . |
waf.score.rce |
security_result.detection_fields[].key : "rce"security_result.detection_fields[].value : waf.score.rce |
Logique similaire à celle de waf.score.http_violation . |
waf.score.rfi |
security_result.detection_fields[].key : "rfi"security_result.detection_fields[].value : waf.score.rfi |
Logique similaire à celle de waf.score.http_violation . |
waf.score.session_fixation |
security_result.detection_fields[].key : "session_fixation"security_result.detection_fields[].value : waf.score.session_fixation |
Logique similaire à celle de waf.score.http_violation . |
waf.score.sql_injection |
security_result.detection_fields[].key : "sql_injection"security_result.detection_fields[].value : waf.score.sql_injection |
Logique similaire à celle de waf.score.http_violation . |
waf.score.xss |
security_result.detection_fields[].key : "xss"security_result.detection_fields[].value : waf.score.xss |
Logique similaire à celle de waf.score.http_violation . |
waf.severity |
security_result.severity : derivedsecurity_result.severity_details : waf.severity |
Si waf.severity n'est pas vide, il détermine la valeur de security_result.severity en fonction des plages (<=3: ÉLEVÉ, >3 et <=6: MOYEN, >6 et <=8: BAS, sinon: UNKNOWN_SEVERITY). La valeur waf.severity d'origine est également mappée sur security_result.severity_details . |
waf_message |
metadata.description : waf_message |
Si waf.message est vide et que waf_message ne l'est pas, il est mappé sur metadata.description . Si client_ip ou host et fastly.server ne sont pas vides, metadata.event_type est défini sur "NETWORK_HTTP". Sinon, si client_ip ou host ne sont pas vides, metadata.event_type est défini sur "STATUS_UPDATE". Sinon, il est défini sur "GENERIC_EVENT". Valeur codée en dur. Valeur codée en dur. Valeur codée en dur. |
Modifications
2022-06-06
- Analyseur nouvellement créé.