Collecter les journaux Fastly WAF
Présentation
Cet analyseur extrait les champs des journaux JSON Fastly WAF, les transforme et les renomme, puis les mappe à 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 disponibles sur l'adresse IP et le nom d'hôte. Il gère également les éventuels échecs d'analyse et supprime les entrées de journaux mal formées.
Avant de commencer
Assurez-vous de remplir les conditions préalables suivantes :
- Instance Google SecOps.
- Compte Fastly avec accès à la configuration des paramètres WAF.
Configurer des flux
Il existe deux points d'entrée différents pour configurer les flux dans la plate-forme Google SecOps :
- Paramètres SIEM> Flux
- Plate-forme de contenu > Packs de contenu
Configurer des flux à partir de Paramètres SIEM > Flux
Pour configurer un flux, procédez comme suit :
- Accédez à Paramètres SIEM > Flux.
- Cliquez sur Add New Feed (Ajouter un flux).
- Sur la page suivante, cliquez sur Configurer un seul flux.
- Dans le champ Nom du flux, saisissez un nom pour le flux (par exemple, Journaux Fastly WAF).
- Sélectionnez Webhook comme type de source.
- Sélectionnez Fastly WAF comme type de journal.
- Cliquez sur Suivant.
- Facultatif : Spécifiez les valeurs des paramètres d'entrée suivants :
- Délimiteur de fractionnement : délimiteur utilisé pour séparer les lignes de journaux, tel que
\n
.
- Délimiteur de fractionnement : délimiteur utilisé pour séparer les lignes de journaux, tel que
- Cliquez sur Suivant.
- Vérifiez la configuration du flux sur 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 l'ancienne deviendra obsolète.
- Dans l'onglet Détails, copiez l'URL du point de terminaison du flux à partir du champ Informations sur le point de terminaison. Vous devez spécifier cette URL de point de terminaison dans votre application cliente.
- Cliquez sur OK.
Configurer des flux depuis le Hub de contenu
Indiquez les valeurs des champs suivants :
- Délimiteur de fractionnement : délimiteur utilisé pour séparer les lignes de journaux, tel que
\n
.
Options avancées
- Nom du flux : valeur préremplie qui identifie le flux.
- Type de source : méthode utilisée pour collecter les journaux dans Google SecOps.
- Espace de noms de l'élément : espace de noms associé au flux.
Libellés d'ingestion : libellés appliqués à tous les événements de ce flux.
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 l'ancienne deviendra obsolète.
Dans l'onglet Détails, copiez l'URL du point de terminaison du flux à partir du champ Informations sur le point de terminaison. Vous devez spécifier cette URL de point de terminaison dans votre application cliente.
Créer une clé API pour le flux de webhook
Accédez à la consoleGoogle Cloud > Identifiants.
Cliquez sur Créer des identifiants, puis sélectionnez Clé API.
Restreignez l'accès à 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 au lieu de la spécifier dans l'URL.
Si votre client de webhook n'accepte pas 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 pour s'authentifier auprès de Google Security Operations.SECRET
: clé secrète que vous avez générée pour authentifier le flux.
Configurer un webhook dans Fastly
- Connectez-vous à Fastly.
- (Facultatif) Sélectionnez un site dans le menu Sites (si vous en avez plusieurs).
- Sélectionnez Gérer > Intégrations de site.
- Cliquez sur Ajouter une intégration de site.
- Sélectionnez Webhook générique.
- URL du webhook : saisissez ENDPOINT_URL Google SecOps, suivi de API_KEY et SECRET.
- Emplacement des alertes : sélectionnez Toutes les activités 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.
Table 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 ou égal à 0, la valeur anomaly_score est utilisée pour remplir le tableau security_result.detection_fields avec une clé "anomaly" 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 est utilisée pour remplir 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 est utilisée pour remplir 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 est utilisée pour remplir 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 est utilisée pour remplir 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, puis mappées respectivement sur principal.location.region_latitude et principal.location.region_longitude . |
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 est utilisée pour remplir 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 est utilisée pour remplir 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 est utilisée pour remplir 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 est utilisée pour remplir 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 est utilisée pour remplir 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 remplir 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 est utilisée pour remplir 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 est utilisée pour remplir 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 est utilisée pour remplir 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é à metadata.description . |
waf.rule_id |
security_result.rule_id : waf.rule_id |
Si waf.rule_id n'est pas vide, il est mappé à 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 remplir 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 remplir le tableau security_result.detection_fields . |
waf.score.lfi |
security_result.detection_fields[].key : "lfi"security_result.detection_fields[].value : waf.score.lfi |
Logique semblable à celle de 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 semblable à celle de waf.score.http_violation . |
waf.score.rce |
security_result.detection_fields[].key : "rce"security_result.detection_fields[].value : waf.score.rce |
Logique semblable à celle de waf.score.http_violation . |
waf.score.rfi |
security_result.detection_fields[].key : "rfi"security_result.detection_fields[].value : waf.score.rfi |
Logique semblable à 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 semblable à 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 semblable à celle de waf.score.http_violation . |
waf.score.xss |
security_result.detection_fields[].key : "xss"security_result.detection_fields[].value : waf.score.xss |
Logique semblable à celle de waf.score.http_violation . |
waf.severity |
security_result.severity : dérivésecurity_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 : HIGH, >3 et <=6 : MEDIUM, >6 et <=8 : LOW, 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, elle est définie sur "GENERIC_EVENT". Valeur codée en dur. Valeur codée en dur. Valeur codée en dur. |
Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.