Raccogliere i log WAF di Signal Sciences
Questo documento spiega come importare i log WAF di Signal Sciences in Google Security Operations utilizzando Google Cloud Storage. Il parser trasforma i log di Signal Sciences dal formato JSON nel modello Unified Data Model (UDM) di Chronicle. Gestisce due strutture di messaggi principali: i messaggi "RPC.PreRequest/PostRequest" vengono analizzati utilizzando i pattern Grok, mentre gli altri messaggi vengono elaborati come oggetti JSON, estraendo i campi pertinenti e mappandoli allo schema UDM.
Prima di iniziare
Assicurati di soddisfare i seguenti prerequisiti:
- Istanza Google SecOps
- Il flusso VPC è configurato e attivo nel tuo ambiente Google Cloud
- Accesso con privilegi al WAF di Signal Sciences
Crea un Google Cloud bucket di archiviazione
- Accedi alla Google Cloud console.
Vai alla pagina Bucket Cloud Storage.
Fai clic su Crea.
Nella pagina Crea un bucket, inserisci le informazioni del bucket. Dopo ogni passaggio riportato di seguito, fai clic su Continua per passare al passaggio successivo:
Nella sezione Inizia:
- Inserisci un nome univoco che soddisfi i requisiti per il nome del bucket (ad esempio, vpcflow-logs).
- Per attivare lo spazio dei nomi gerarchico, fai clic sulla freccia di espansione per espandere la sezione Ottimizza per workload orientati ai file e con uso intensivo dei dati, poi seleziona Abilita uno spazio dei nomi gerarchico in questo bucket.
- Per aggiungere un'etichetta del bucket, fai clic sulla freccia di espansione per espandere la sezione Etichette.
- Fai clic su Aggiungi etichetta e specifica una chiave e un valore per l'etichetta.
Nella sezione Scegli dove archiviare i tuoi dati, segui questi passaggi:
- Seleziona un Tipo di località.
- Utilizza il menu del tipo di località per selezionare una località in cui verranno archiviati in modo permanente i dati degli oggetti all'interno del bucket.
- Per configurare la replica tra bucket, espandi la sezione Configura replica tra bucket.
Nella sezione Scegli una classe di archiviazione per i tuoi dati, seleziona una classe di archiviazione predefinita per il bucket oppure Autoclass per la gestione automatica della classe di archiviazione dei dati del bucket.
Nella sezione Scegli come controllare l'accesso agli oggetti, seleziona No per applicare la prevenzione dell'accesso pubblico e seleziona un modello di controllo dell'accesso per gli oggetti del bucket.
Nella sezione Scegli come proteggere i dati degli oggetti, segui questi passaggi:
- Seleziona una delle opzioni in Protezione dei dati che vuoi impostare per il bucket.
- Per scegliere come criptare i dati degli oggetti, fai clic sulla freccia di espansione con l'etichetta Crittografia dei dati e seleziona un metodo di crittografia dei dati.
Fai clic su Crea.
Configurare una chiave API WAF di Signal Sciences
- Accedi alla UI web di Signal Sciences WAF.
- Vai a Il mio profilo > Token di accesso API.
- Fai clic su Aggiungi token di accesso all'API.
- Fornisci un nome univoco e descrittivo (ad esempio,
Google SecOps
). - Fai clic su Crea token di accesso API.
- Copia e salva il token in un luogo sicuro.
- Fai clic su Ho capito per completare la creazione del token.
Esegui il deployment di uno script su un host Linux per estrarre i log da Signal Sciences e archiviarli in Google Cloud
- Accedi all'host Linux utilizzando SSH.
Installa la libreria Python per archiviare il file JSON del WAF Signal Sciences in un bucket Cloud Storage:
pip install google-cloud-storage
Imposta questa variabile di ambiente per chiamare il file JSON contenente le credenziali da Google Cloud:
export GOOGLE_APPLICATION_CREDENTIALS="path/to/your/service-account-key.json"
Configura le seguenti variabili di ambiente perché queste informazioni non devono essere codificate in modo permanente:
export SIGSCI_EMAIL=<Signal_Sciences_account_email> export SIGSCI_TOKEN=<Signal_Sciences_API_token> export SIGSCI_CORP=<Corporation_name_in_Signal_Sciences>
Esegui questo script:
import sys import requests import os import calendar import json from datetime import datetime, timedelta from google.cloud import storage # Check if all necessary environment variables are set if 'SIGSCI_EMAIL' not in os.environ or 'SIGSCI_TOKEN' not in os.environ or 'SIGSCI_CORP' not in os.environ: print("ERROR: You need to define SIGSCI_EMAIL, SIGSCI_TOKEN, and SIGSCI_CORP environment variables.") print("Please fix and run again. Existing...") sys.exit(1) # Exit if environment variables are not set # Define the Google Cloud Storage bucket name and output file name bucket_name = 'Your_GCS_Bucket' # Replace with your GCS bucket name output_file_name = 'signal_sciences_logs.json' # Initialize Google Cloud Storage client storage_client = storage.Client() # Function to upload data to Google Cloud Storage def upload_to_gcs(bucket_name, data, destination_blob_name): bucket = storage_client.bucket(bucket_name) blob = bucket.blob(destination_blob_name) blob.upload_from_string(data, content_type='application/json') print(f"Data uploaded to {destination_blob_name} in bucket {bucket_name}") # Signal Sciences API information api_host = 'https://dashboard.signalsciences.net' # email = 'user@domain.com' # Signal Sciences account email # token = 'XXXXXXXX-XXXX-XXX-XXXX-XXXXXXXXXXXX' # API token for authentication # corp_name = 'Domain' # Corporation name in Signal Sciences # site_names = ['testenv'] # Replace with your actual site names # List of comma-delimited sites that you want to extract data from site_names = [ 'site123', 'site345' ] # Define all sites to pull logs from email = os.environ.get('SIGSCI_EMAIL') # Signal Sciences account email token = os.environ.get('SIGSCI_TOKEN') # API token for authentication corp_name = os.environ.get('SIGSCI_CORP') # Corporation name in Signal Sciences # Calculate the start and end timestamps for the previous hour in UTC until_time = datetime.utcnow().replace(minute=0, second=0, microsecond=0) from_time = until_time - timedelta(hours=1) until_time = calendar.timegm(until_time.utctimetuple()) from_time = calendar.timegm(from_time.utctimetuple()) # Prepare HTTP headers for the API request headers = { 'Content-Type': 'application/json', 'x-api-user': email, 'x-api-token': token } # Collect logs for each site collected_logs = [] for site_name in site_names: url = f"{api_host}/api/v0/corps/{corp_name}/sites/{site_name}/feed/requests?from={from_time}&until={until_time}" while True: response = requests.get(url, headers=headers) if response.status_code != 200: print(f"Error fetching logs: {response.text}", file=sys.stderr) break # Parse the JSON response data = response.json() collected_logs.extend(data['data']) # Add the log messages to our list # Pagination: check if there is a next page next_url = data.get('next', {}).get('uri') if not next_url: break url = api_host + next_url # Convert the collected logs to a newline-delimited JSON string json_data = '\n'.join(json.dumps(log) for log in collected_logs) # Save the newline-delimited JSON data to a GCS bucket upload_to_gcs(bucket_name, json_data, output_file_name)
Configurare i feed
Esistono due diversi punti di accesso per configurare i feed nella piattaforma Google SecOps:
- Impostazioni SIEM > Feed
- Hub dei contenuti > Pacchetti di contenuti
Configura i feed da Impostazioni SIEM > Feed
Per configurare un feed:
- Vai a Impostazioni SIEM > Feed.
- Fai clic su Aggiungi nuovo feed.
- Nella pagina successiva, fai clic su Configura un singolo feed.
- Nel campo Nome feed, inserisci un nome per il feed (ad esempio,
Signal Sciences WAF Logs
). - Seleziona Google Cloud Storage come Tipo di origine.
- Seleziona Signal Sciences WAF come Tipo di log.
- Fai clic su Ottieni account di servizio come Account di servizio Chronicle.
- Fai clic su Avanti.
Specifica i valori per i seguenti parametri di input:
- URI bucket di archiviazione: Google Cloud URL del bucket di archiviazione nel formato
gs://my-bucket/<value>
. - URI Is A: seleziona Directory which includes subdirectories (Directory che include sottodirectory).
Opzioni di eliminazione dell'origine: seleziona l'opzione di eliminazione in base alle tue preferenze.
- URI bucket di archiviazione: Google Cloud URL del bucket di archiviazione nel formato
Fai clic su Avanti.
Controlla la nuova configurazione del feed nella schermata Finalizza e poi fai clic su Invia.
Configurare i feed dall'hub dei contenuti
Specifica i valori per i seguenti campi:
- URI bucket di archiviazione: Google Cloud URL del bucket di archiviazione nel formato
gs://my-bucket/<value>
. - URI Is A: seleziona Directory which includes subdirectories (Directory che include sottodirectory).
Opzioni di eliminazione dell'origine: seleziona l'opzione di eliminazione in base alle tue preferenze.
Opzioni avanzate
- Nome feed: un valore precompilato che identifica il feed.
- Tipo di origine: metodo utilizzato per raccogliere i log in Google SecOps.
- Spazio dei nomi dell'asset: lo spazio dei nomi associato al feed.
- Etichette di importazione: etichette applicate a tutti gli eventi di questo feed.
Tabella di mappatura UDM
Campo log | Mappatura UDM | Logic |
---|---|---|
CLIENT-IP | target.ip | Estratto dal campo di intestazione CLIENT-IP . |
CLIENT-IP | target.port | Estratto dal campo di intestazione CLIENT-IP . |
Connessione | security_result.about.labels | Il valore viene estratto dal campo Connection del log non elaborato e mappato a security_result.about.labels . |
Content-Length | security_result.about.labels | Il valore viene estratto dal campo Content-Length del log non elaborato e mappato a security_result.about.labels . |
Content-Type | security_result.about.labels | Il valore viene estratto dal campo Content-Type del log non elaborato e mappato a security_result.about.labels . |
creato | metadata.event_timestamp | Il valore viene estratto dal campo created del log non elaborato e mappato a metadata.event_timestamp . |
details.headersIn | security_result.about.resource.attribute.labels | Il valore viene estratto dal campo details.headersIn del log non elaborato e mappato a security_result.about.resource.attribute.labels . |
details.headersOut | security_result.about.resource.attribute.labels | Il valore viene estratto dal campo details.headersOut del log non elaborato e mappato a security_result.about.resource.attribute.labels . |
details.id | principal.process.pid | Il valore viene estratto dal campo details.id del log non elaborato e mappato a principal.process.pid . |
details.method | network.http.method | Il valore viene estratto dal campo details.method del log non elaborato e mappato a network.http.method . |
details.protocol | network.application_protocol | Il valore viene estratto dal campo details.protocol del log non elaborato e mappato a network.application_protocol . |
details.remoteCountryCode | principal.location.country_or_region | Il valore viene estratto dal campo details.remoteCountryCode del log non elaborato e mappato a principal.location.country_or_region . |
details.remoteHostname | target.hostname | Il valore viene estratto dal campo details.remoteHostname del log non elaborato e mappato a target.hostname . |
details.remoteIP | target.ip | Il valore viene estratto dal campo details.remoteIP del log non elaborato e mappato a target.ip . |
details.responseCode | network.http.response_code | Il valore viene estratto dal campo details.responseCode del log non elaborato e mappato a network.http.response_code . |
details.responseSize | network.received_bytes | Il valore viene estratto dal campo details.responseSize del log non elaborato e mappato a network.received_bytes . |
details.serverHostname | principal.hostname | Il valore viene estratto dal campo details.serverHostname del log non elaborato e mappato a principal.hostname . |
details.serverName | principal.asset.network_domain | Il valore viene estratto dal campo details.serverName del log non elaborato e mappato a principal.asset.network_domain . |
details.tags | security_result.detection_fields | Il valore viene estratto dal campo details.tags del log non elaborato e mappato a security_result.detection_fields . |
details.tlsCipher | network.tls.cipher | Il valore viene estratto dal campo details.tlsCipher del log non elaborato e mappato a network.tls.cipher . |
details.tlsProtocol | network.tls.version | Il valore viene estratto dal campo details.tlsProtocol del log non elaborato e mappato a network.tls.version . |
details.userAgent | network.http.user_agent | Il valore viene estratto dal campo details.userAgent del log non elaborato e mappato a network.http.user_agent . |
details.uri | network.http.referral_url | Il valore viene estratto dal campo details.uri del log non elaborato e mappato a network.http.referral_url . |
eventType | metadata.product_event_type | Il valore viene estratto dal campo eventType del log non elaborato e mappato a metadata.product_event_type . |
headersIn | security_result.about.labels | Il valore viene estratto dal campo headersIn del log non elaborato e mappato a security_result.about.labels . |
headersOut | security_result.about.labels | Il valore viene estratto dal campo headersOut del log non elaborato e mappato a security_result.about.labels . |
ID | principal.process.pid | Il valore viene estratto dal campo id del log non elaborato e mappato a principal.process.pid . |
messaggio | metadata.description | Il valore viene estratto dal campo message del log non elaborato e mappato a metadata.description . |
metodo | network.http.method | Il valore viene estratto dal campo method del log non elaborato e mappato a network.http.method . |
ModuleVersion | metadata.ingestion_labels | Il valore viene estratto dal campo ModuleVersion del log non elaborato e mappato a metadata.ingestion_labels . |
msgData.actions | security_result.action | Il valore viene estratto dal campo msgData.actions del log non elaborato e mappato a security_result.action . |
msgData.changes | target.resource.attribute.labels | Il valore viene estratto dal campo msgData.changes del log non elaborato e mappato a target.resource.attribute.labels . |
msgData.conditions | security_result.description | Il valore viene estratto dal campo msgData.conditions del log non elaborato e mappato a security_result.description . |
msgData.detailLink | network.http.referral_url | Il valore viene estratto dal campo msgData.detailLink del log non elaborato e mappato a network.http.referral_url . |
msgData.name | target.resource.name | Il valore viene estratto dal campo msgData.name del log non elaborato e mappato a target.resource.name . |
msgData.reason | security_result.summary | Il valore viene estratto dal campo msgData.reason del log non elaborato e mappato a security_result.summary . |
msgData.sites | network.http.user_agent | Il valore viene estratto dal campo msgData.sites del log non elaborato e mappato a network.http.user_agent . |
protocollo | network.application_protocol | Il valore viene estratto dal campo protocol del log non elaborato e mappato a network.application_protocol . |
remoteCountryCode | principal.location.country_or_region | Il valore viene estratto dal campo remoteCountryCode del log non elaborato e mappato a principal.location.country_or_region . |
remoteHostname | target.hostname | Il valore viene estratto dal campo remoteHostname del log non elaborato e mappato a target.hostname . |
remoteIP | target.ip | Il valore viene estratto dal campo remoteIP del log non elaborato e mappato a target.ip . |
responseCode | network.http.response_code | Il valore viene estratto dal campo responseCode del log non elaborato e mappato a network.http.response_code . |
responseSize | network.received_bytes | Il valore viene estratto dal campo responseSize del log non elaborato e mappato a network.received_bytes . |
serverHostname | principal.hostname | Il valore viene estratto dal campo serverHostname del log non elaborato e mappato a principal.hostname . |
serverName | principal.asset.network_domain | Il valore viene estratto dal campo serverName del log non elaborato e mappato a principal.asset.network_domain . |
tags | security_result.detection_fields | Il valore viene estratto dal campo tags del log non elaborato e mappato a security_result.detection_fields . |
timestamp | metadata.event_timestamp | Il valore viene estratto dal campo timestamp del log non elaborato e mappato a metadata.event_timestamp . |
tlsCipher | network.tls.cipher | Il valore viene estratto dal campo tlsCipher del log non elaborato e mappato a network.tls.cipher . |
tlsProtocol | network.tls.version | Il valore viene estratto dal campo tlsProtocol del log non elaborato e mappato a network.tls.version . |
URI | target.url | Il valore viene estratto dal campo URI del log non elaborato e mappato a target.url . |
userAgent | network.http.user_agent | Il valore viene estratto dal campo userAgent del log non elaborato e mappato a network.http.user_agent . |
uri | network.http.referral_url | Il valore viene estratto dal campo uri del log non elaborato e mappato a network.http.referral_url . |
X-ARR-SSL | network.tls.client.certificate.issuer | Il valore viene estratto dal campo dell'intestazione X-ARR-SSL utilizzando i filtri grok e kv. |
metadata.event_type | Il tipo di evento viene determinato dal parser in base alla presenza di informazioni su target e principal. Se sono presenti sia il target che il principale, il tipo di evento è NETWORK_HTTP . Se è presente solo l'entità, il tipo di evento è STATUS_UPDATE . In caso contrario, il tipo di evento è GENERIC_EVENT . |
|
metadata.log_type | Il valore è codificato in modo permanente su SIGNAL_SCIENCES_WAF . |
|
metadata.product_name | Il valore è codificato in modo permanente su Signal Sciences WAF . |
|
metadata.vendor_name | Il valore è codificato in modo permanente su Signal Sciences . |
|
principal.asset.hostname | Il valore viene estratto dal campo principal.hostname . |
|
target.asset.hostname | Il valore viene estratto dal campo target.hostname . |
|
target.asset.ip | Il valore viene estratto dal campo target.ip . |
|
target.user.user_display_name | Il valore viene estratto dal campo message_data utilizzando un filtro grok. |
|
target.user.userid | Il valore viene estratto dal campo message_data utilizzando un filtro grok. |
Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.