Recopila registros del WAF de Signal Sciences
En este documento, se explica cómo transferir registros del WAF de Signal Sciences a las Operaciones de seguridad de Google con Google Cloud Storage. El analizador transforma los registros de Signal Sciences de su formato JSON al modelo de datos unificado (UDM) de Chronicle. Maneja 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, lo que permite extraer los campos pertinentes y asignarlos al esquema del 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 entorno de Google Cloud .
- Acceso privilegiado al WAF de Signal Sciences
Crea un Google Cloud bucket de Storage
- Accede a la consola de Google Cloud .
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 paso:
En la sección Primeros pasos, haz lo siguiente:
- Ingresa un nombre único que cumpla con los requisitos de nombres 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 Configura 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 selecciona un modelo de control de acceso para los objetos del 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 del WAF de Signal Sciences
- Accede a la IU web del 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 único y descriptivo (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 del WAF de Signal Sciences en un bucket de Cloud Storage:
pip install google-cloud-storage
Configura 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, ya que esta información no debe estar codificada de forma rígida:
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 = '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)
Configura 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 feeds en Configuración del SIEM > Feeds
Para configurar un feed, sigue estos pasos:
- Ve a Configuración del SIEM > Feeds.
- Haz clic en Agregar feed nuevo.
- En la siguiente página, 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 Signal Sciences WAF 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:URL del bucket de almacenamiento en formato
gs://my-bucket/<value>
Google Cloud - URI Is A: Selecciona Directory which includes subdirectories.
Opciones de borrado de la fuente: Selecciona la opción de borrado según tu preferencia.
- URI del bucket de almacenamiento:URL del bucket de almacenamiento en formato
Haz clic en Siguiente.
Revisa la nueva configuración del feed en la pantalla Finalizar y, luego, haz clic en Enviar.
Configura feeds desde el Centro de contenido
Especifica valores para los siguientes campos:
- URI del bucket de almacenamiento:URL del bucket de almacenamiento en formato
gs://my-bucket/<value>
Google Cloud - URI Is A: Selecciona Directory which includes subdirectories.
Opciones de borrado de la fuente: Selecciona la opción de borrado según tu preferencia.
Opciones avanzadas
- Nombre del feed: Es un valor completado previamente 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 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 del 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 del 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 del registro sin procesar y se asigna a security_result.about.labels . |
created | metadata.event_timestamp | El valor se toma del campo created del 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 del 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 del 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 del registro sin procesar y se asigna a principal.process.pid . |
details.method | network.http.method | El valor se toma del campo details.method del registro sin procesar y se asigna a network.http.method . |
details.protocol | network.application_protocol | El valor se toma del campo details.protocol del 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 del registro sin procesar y se asigna a principal.location.country_or_region . |
details.remoteHostname | target.hostname | El valor se toma del campo details.remoteHostname del registro sin procesar y se asigna a target.hostname . |
details.remoteIP | target.ip | El valor se toma del campo details.remoteIP del registro sin procesar y se asigna a target.ip . |
details.responseCode | network.http.response_code | El valor se toma del campo details.responseCode del registro sin procesar y se asigna a network.http.response_code . |
details.responseSize | network.received_bytes | El valor se toma del campo details.responseSize del registro sin procesar y se asigna a network.received_bytes . |
details.serverHostname | principal.hostname | El valor se toma del campo details.serverHostname del registro sin procesar y se asigna a principal.hostname . |
details.serverName | principal.asset.network_domain | El valor se toma del campo details.serverName del 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 del registro sin procesar y se asigna a security_result.detection_fields . |
details.tlsCipher | network.tls.cipher | El valor se toma del campo details.tlsCipher del registro sin procesar y se asigna a network.tls.cipher . |
details.tlsProtocol | network.tls.version | El valor se toma del campo details.tlsProtocol del registro sin procesar y se asigna a network.tls.version . |
details.userAgent | network.http.user_agent | El valor se toma del campo details.userAgent del 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 del registro sin procesar y se asigna a network.http.referral_url . |
eventType | metadata.product_event_type | El valor se toma del campo eventType del registro sin procesar y se asigna a metadata.product_event_type . |
headersIn | security_result.about.labels | El valor se toma del campo headersIn del registro sin procesar y se asigna a security_result.about.labels . |
headersOut | security_result.about.labels | El valor se toma del campo headersOut del registro sin procesar y se asigna a security_result.about.labels . |
id | principal.process.pid | El valor se toma del campo id del registro sin procesar y se asigna a principal.process.pid . |
mensaje | metadata.description | El valor se toma del campo message del registro sin procesar y se asigna a metadata.description . |
método | network.http.method | El valor se toma del campo method del registro sin procesar y se asigna a network.http.method . |
ModuleVersion | metadata.ingestion_labels | El valor se toma del campo ModuleVersion del registro sin procesar y se asigna a metadata.ingestion_labels . |
msgData.actions | security_result.action | El valor se toma del campo msgData.actions del registro sin procesar y se asigna a security_result.action . |
msgData.changes | target.resource.attribute.labels | El valor se toma del campo msgData.changes del registro sin procesar y se asigna a target.resource.attribute.labels . |
msgData.conditions | security_result.description | El valor se toma del campo msgData.conditions del registro sin procesar y se asigna a security_result.description . |
msgData.detailLink | network.http.referral_url | El valor se toma del campo msgData.detailLink del registro sin procesar y se asigna a network.http.referral_url . |
msgData.name | target.resource.name | El valor se toma del campo msgData.name del registro sin procesar y se asigna a target.resource.name . |
msgData.reason | security_result.summary | El valor se toma del campo msgData.reason del registro sin procesar y se asigna a security_result.summary . |
msgData.sites | network.http.user_agent | El valor se toma del campo msgData.sites del registro sin procesar y se asigna a network.http.user_agent . |
protocolo | network.application_protocol | El valor se toma del campo protocol del registro sin procesar y se asigna a network.application_protocol . |
remoteCountryCode | principal.location.country_or_region | El valor se toma del campo remoteCountryCode del registro sin procesar y se asigna a principal.location.country_or_region . |
remoteHostname | target.hostname | El valor se toma del campo remoteHostname del registro sin procesar y se asigna a target.hostname . |
remoteIP | target.ip | El valor se toma del campo remoteIP del registro sin procesar y se asigna a target.ip . |
responseCode | network.http.response_code | El valor se toma del campo responseCode del registro sin procesar y se asigna a network.http.response_code . |
responseSize | network.received_bytes | El valor se toma del campo responseSize del registro sin procesar y se asigna a network.received_bytes . |
serverHostname | principal.hostname | El valor se toma del campo serverHostname del registro sin procesar y se asigna a principal.hostname . |
serverName | principal.asset.network_domain | El valor se toma del campo serverName del registro sin procesar y se asigna a principal.asset.network_domain . |
tags | security_result.detection_fields | El valor se toma del campo tags del registro sin procesar y se asigna a security_result.detection_fields . |
timestamp | metadata.event_timestamp | El valor se toma del campo timestamp del registro sin procesar y se asigna a metadata.event_timestamp . |
tlsCipher | network.tls.cipher | El valor se toma del campo tlsCipher del registro sin procesar y se asigna a network.tls.cipher . |
tlsProtocol | network.tls.version | El valor se toma del campo tlsProtocol del registro sin procesar y se asigna a network.tls.version . |
URI | target.url | El valor se toma del campo URI del registro sin procesar y se asigna a target.url . |
userAgent | network.http.user_agent | El valor se toma del campo userAgent del registro sin procesar y se asigna a network.http.user_agent . |
uri | network.http.referral_url | El valor se toma del campo uri del 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 tipo de evento lo determina el analizador en función de la presencia de información del principal y del objetivo. Si están presentes tanto el destino como el principal, el tipo de evento es NETWORK_HTTP . Si solo está presente la 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 como SIGNAL_SCIENCES_WAF . |
|
metadata.product_name | El valor está codificado como Signal Sciences WAF . |
|
metadata.vendor_name | El valor está codificado como 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.