Recopila registros de la WAF de Signal Sciences
En este documento, se explica cómo transferir los registros de la WAF de Signal Sciences a Google Security Operations con Google Cloud Storage. El analizador transforma los registros de Signal Sciences de su formato JSON en el modelo de datos unificado (UDM) de Chronicle. Controla dos estructuras de mensajes principales: los mensajes "RPC.PreRequest/PostRequest" se analizan con patrones de Grok, mientras que otros mensajes se procesan como objetos JSON, extraen campos relevantes y los asignan al esquema de UDM.
Antes de comenzar
Asegúrate de cumplir con los siguientes requisitos previos:
- Instancia de Google SecOps
- El flujo de VPC está configurado y activo en tu Google Cloud entorno
- Acceso con privilegios a la WAF de Signal Sciences
Crea un Google Cloud bucket de almacenamiento
- Accede a la Google Cloud consola.
Ve a la página Buckets de Cloud Storage.
Haz clic en Crear.
En la página Crear un bucket, ingresa la información de tu bucket. Después de cada uno de los siguientes pasos, haz clic en Continuar para avanzar al siguiente:
En la sección Primeros pasos, haz lo siguiente:
- Ingresa un nombre único que cumpla con los requisitos de nombre de bucket (por ejemplo, vpcflow-logs).
- Para habilitar el espacio de nombres jerárquico, haz clic en la flecha de expansión para expandir la sección Optimizar las cargas de trabajo orientadas a archivos y con uso intensivo de datos y, luego, selecciona Habilitar el espacio de nombres jerárquico en este bucket.
- Para agregar una etiqueta de bucket, haz clic en la flecha de expansión para expandir la sección Etiquetas.
- Haz clic en Agregar etiqueta y especifica una clave y un valor para tu etiqueta.
En la sección Eligir dónde almacenar tus datos, haz lo siguiente:
- Selecciona un tipo de ubicación
- Usa el menú del tipo de ubicación para seleccionar una Ubicación en la que se almacenarán de forma permanente los datos de objetos de tu bucket.
- Para configurar la replicación entre bucket, expande la sección Configurar la bucket entre buckets.
En la sección Elige una clase de almacenamiento para tus datos, selecciona una clase de almacenamiento predeterminada para el bucket o selecciona Autoclass para la administración automática de clases de almacenamiento de los datos de tu bucket.
En la sección Elige cómo controlar el acceso a los objetos, selecciona no para aplicar la prevención del acceso público y elige un modelo de control de acceso para los objetos de tu bucket.
En la sección Elige cómo proteger los datos de objetos, haz lo siguiente:
- Selecciona cualquiera de las opciones de Protección de datos que desees configurar para tu bucket.
- Para elegir cómo se encriptarán los datos de tus objetos, haz clic en la flecha desplegable etiquetada como Encriptación de datos y selecciona un método de encriptación de datos.
Haz clic en Crear.
Configura una clave de API de WAF de Signal Sciences
- Accede a la IU web de la WAF de Signal Sciences.
- Ve a Mi perfil > Tokens de acceso a la API.
- Haz clic en Agregar token de acceso a la API.
- Proporciona un nombre descriptivo único (por ejemplo,
Google SecOps
). - Haz clic en Crear token de acceso a la API.
- Copia y guarda el token en una ubicación segura.
- Haz clic en Entiendo para terminar de crear el token.
Implementa una secuencia de comandos en un host de Linux para extraer registros de Signal Sciences y almacenarlos en Google Cloud
- Accede al host de Linux con SSH.
Instala la biblioteca de Python para almacenar el archivo JSON de la WAF de Signal Sciences en un bucket de Cloud Storage:
pip install google-cloud-storage
Establece esta variable de entorno para llamar al archivo JSON que tiene las credenciales de Google Cloud:
export GOOGLE_APPLICATION_CREDENTIALS="path/to/your/service-account-key.json"
Configura las siguientes variables de entorno porque esta información no debe estar codificada:
export SIGSCI_EMAIL=<Signal_Sciences_account_email> export SIGSCI_TOKEN=<Signal_Sciences_API_token> export SIGSCI_CORP=<Corporation_name_in_Signal_Sciences>
Ejecuta la siguiente secuencia de comandos:
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 = '[email protected]' # 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)
Cómo configurar feeds
Existen dos puntos de entrada diferentes para configurar feeds en la plataforma de Google SecOps:
- Configuración de SIEM > Feeds
- Centro de contenido > Paquetes de contenido
Configura los feeds desde Configuración de SIEM > Feeds
Para configurar un feed, sigue estos pasos:
- Ve a Configuración de SIEM > Feeds.
- Haz clic en Agregar feed nuevo.
- En la página siguiente, haz clic en Configurar un solo feed.
- En el campo Nombre del feed, ingresa un nombre para el feed (por ejemplo,
Signal Sciences WAF Logs
). - Selecciona Google Cloud Storage como el Tipo de fuente.
- Selecciona WAF de Signal Sciences como el Tipo de registro.
- Haz clic en Obtener cuenta de servicio como la cuenta de servicio de Chronicle.
- Haz clic en Siguiente.
Especifica valores para los siguientes parámetros de entrada:
- URI del bucket de almacenamiento: Google Cloud URL del bucket de almacenamiento en formato
gs://my-bucket/<value>
. - URI Is A: Selecciona Directorio que incluye subdirectorios.
Opciones de eliminación de fuentes: Selecciona la opción de eliminación según tu preferencia.
- URI del bucket de almacenamiento: Google Cloud URL del bucket de almacenamiento en formato
Haz clic en Siguiente.
Revisa la configuración de tu nuevo feed en la pantalla Finalizar y, luego, haz clic en Enviar.
Cómo configurar feeds desde el Content Hub
Especifica valores para los siguientes campos:
- URI del bucket de almacenamiento: Google Cloud URL del bucket de almacenamiento en formato
gs://my-bucket/<value>
. - URI Is A: Selecciona Directorio que incluye subdirectorios.
Opciones de eliminación de fuentes: Selecciona la opción de eliminación según tu preferencia.
Opciones avanzadas
- Nombre del feed: Es un valor prepropagado que identifica el feed.
- Tipo de fuente: Es el método que se usa para recopilar registros en Google SecOps.
- Espacio de nombres del activo: Es el espacio de nombres asociado con el feed.
- Etiquetas de transferencia: Son las etiquetas que se aplican a todos los eventos de este feed.
Tabla de asignación de la UDM
Campo de registro | Asignación de UDM | Lógica |
---|---|---|
CLIENT-IP | target.ip | Se extrae del campo de encabezado CLIENT-IP . |
CLIENT-IP | target.port | Se extrae del campo de encabezado CLIENT-IP . |
Conexión | security_result.about.labels | El valor se toma del campo Connection de registro sin procesar y se asigna a security_result.about.labels . |
Content-Length | security_result.about.labels | El valor se toma del campo Content-Length de registro sin procesar y se asigna a security_result.about.labels . |
Content-Type | security_result.about.labels | El valor se toma del campo Content-Type de registro sin procesar y se asigna a security_result.about.labels . |
created | metadata.event_timestamp | El valor se toma del campo created de registro sin procesar y se asigna a metadata.event_timestamp . |
details.headersIn | security_result.about.resource.attribute.labels | El valor se toma del campo details.headersIn de registro sin procesar y se asigna a security_result.about.resource.attribute.labels . |
details.headersOut | security_result.about.resource.attribute.labels | El valor se toma del campo details.headersOut de registro sin procesar y se asigna a security_result.about.resource.attribute.labels . |
details.id | principal.process.pid | El valor se toma del campo details.id de registro sin procesar y se asigna a principal.process.pid . |
details.method | network.http.method | El valor se toma del campo details.method de registro sin procesar y se asigna a network.http.method . |
details.protocol | network.application_protocol | El valor se toma del campo details.protocol de registro sin procesar y se asigna a network.application_protocol . |
details.remoteCountryCode | principal.location.country_or_region | El valor se toma del campo details.remoteCountryCode de registro sin procesar y se asigna a principal.location.country_or_region . |
details.remoteHostname | target.hostname | El valor se toma del campo details.remoteHostname de registro sin procesar y se asigna a target.hostname . |
details.remoteIP | target.ip | El valor se toma del campo details.remoteIP de registro sin procesar y se asigna a target.ip . |
details.responseCode | network.http.response_code | El valor se toma del campo details.responseCode de registro sin procesar y se asigna a network.http.response_code . |
details.responseSize | network.received_bytes | El valor se toma del campo details.responseSize de registro sin procesar y se asigna a network.received_bytes . |
details.serverHostname | principal.hostname | El valor se toma del campo details.serverHostname de registro sin procesar y se asigna a principal.hostname . |
details.serverName | principal.asset.network_domain | El valor se toma del campo details.serverName de registro sin procesar y se asigna a principal.asset.network_domain . |
details.tags | security_result.detection_fields | El valor se toma del campo details.tags de registro sin procesar y se asigna a security_result.detection_fields . |
details.tlsCipher | network.tls.cipher | El valor se toma del campo details.tlsCipher de registro sin procesar y se asigna a network.tls.cipher . |
details.tlsProtocol | network.tls.version | El valor se toma del campo details.tlsProtocol de registro sin procesar y se asigna a network.tls.version . |
details.userAgent | network.http.user_agent | El valor se toma del campo details.userAgent de registro sin procesar y se asigna a network.http.user_agent . |
details.uri | network.http.referral_url | El valor se toma del campo details.uri de registro sin procesar y se asigna a network.http.referral_url . |
eventType | metadata.product_event_type | El valor se toma del campo eventType de registro sin procesar y se asigna a metadata.product_event_type . |
headersIn | security_result.about.labels | El valor se toma del campo headersIn de registro sin procesar y se asigna a security_result.about.labels . |
headersOut | security_result.about.labels | El valor se toma del campo headersOut de registro sin procesar y se asigna a security_result.about.labels . |
id | principal.process.pid | El valor se toma del campo id de registro sin procesar y se asigna a principal.process.pid . |
mensaje | metadata.description | El valor se toma del campo message de registro sin procesar y se asigna a metadata.description . |
método | network.http.method | El valor se toma del campo method de registro sin procesar y se asigna a network.http.method . |
ModuleVersion | metadata.ingestion_labels | El valor se toma del campo ModuleVersion de registro sin procesar y se asigna a metadata.ingestion_labels . |
msgData.actions | security_result.action | El valor se toma del campo msgData.actions de registro sin procesar y se asigna a security_result.action . |
msgData.changes | target.resource.attribute.labels | El valor se toma del campo msgData.changes de registro sin procesar y se asigna a target.resource.attribute.labels . |
msgData.conditions | security_result.description | El valor se toma del campo msgData.conditions de registro sin procesar y se asigna a security_result.description . |
msgData.detailLink | network.http.referral_url | El valor se toma del campo msgData.detailLink de registro sin procesar y se asigna a network.http.referral_url . |
msgData.name | target.resource.name | El valor se toma del campo msgData.name de registro sin procesar y se asigna a target.resource.name . |
msgData.reason | security_result.summary | El valor se toma del campo msgData.reason de registro sin procesar y se asigna a security_result.summary . |
msgData.sites | network.http.user_agent | El valor se toma del campo msgData.sites de registro sin procesar y se asigna a network.http.user_agent . |
protocol | network.application_protocol | El valor se toma del campo protocol de registro sin procesar y se asigna a network.application_protocol . |
remoteCountryCode | principal.location.country_or_region | El valor se toma del campo remoteCountryCode de registro sin procesar y se asigna a principal.location.country_or_region . |
remoteHostname | target.hostname | El valor se toma del campo remoteHostname de registro sin procesar y se asigna a target.hostname . |
remoteIP | target.ip | El valor se toma del campo remoteIP de registro sin procesar y se asigna a target.ip . |
responseCode | network.http.response_code | El valor se toma del campo responseCode de registro sin procesar y se asigna a network.http.response_code . |
responseSize | network.received_bytes | El valor se toma del campo responseSize de registro sin procesar y se asigna a network.received_bytes . |
serverHostname | principal.hostname | El valor se toma del campo serverHostname de registro sin procesar y se asigna a principal.hostname . |
serverName | principal.asset.network_domain | El valor se toma del campo serverName de registro sin procesar y se asigna a principal.asset.network_domain . |
tags | security_result.detection_fields | El valor se toma del campo tags de registro sin procesar y se asigna a security_result.detection_fields . |
timestamp | metadata.event_timestamp | El valor se toma del campo timestamp de registro sin procesar y se asigna a metadata.event_timestamp . |
tlsCipher | network.tls.cipher | El valor se toma del campo tlsCipher de registro sin procesar y se asigna a network.tls.cipher . |
tlsProtocol | network.tls.version | El valor se toma del campo tlsProtocol de registro sin procesar y se asigna a network.tls.version . |
URI | target.url | El valor se toma del campo URI de registro sin procesar y se asigna a target.url . |
userAgent | network.http.user_agent | El valor se toma del campo userAgent de registro sin procesar y se asigna a network.http.user_agent . |
uri | network.http.referral_url | El valor se toma del campo uri de registro sin procesar y se asigna a network.http.referral_url . |
X-ARR-SSL | network.tls.client.certificate.issuer | El valor se extrae del campo de encabezado X-ARR-SSL con los filtros grok y kv. |
metadata.event_type | El analizador determina el tipo de evento según la presencia de información de destino y principal. Si están presentes el objetivo y el principal, el tipo de evento es NETWORK_HTTP . Si solo está presente el principal, el tipo de evento es STATUS_UPDATE . De lo contrario, el tipo de evento es GENERIC_EVENT . |
|
metadata.log_type | El valor está codificado en SIGNAL_SCIENCES_WAF . |
|
metadata.product_name | El valor está codificado en Signal Sciences WAF . |
|
metadata.vendor_name | El valor está codificado en Signal Sciences . |
|
principal.asset.hostname | El valor se toma del campo principal.hostname . |
|
target.asset.hostname | El valor se toma del campo target.hostname . |
|
target.asset.ip | El valor se toma del campo target.ip . |
|
target.user.user_display_name | El valor se extrae del campo message_data con un filtro grok. |
|
target.user.userid | El valor se extrae del campo message_data con un filtro grok. |
¿Necesitas más ayuda? Obtén respuestas de miembros de la comunidad y profesionales de Google SecOps.