Recoger registros de Signal Sciences WAF

Disponible en:

En este documento se explica cómo ingerir registros de WAF de Signal Sciences en Google Security Operations mediante Google Cloud Storage. El analizador transforma los registros de Signal Sciences de su formato JSON al modelo de datos unificado (UDM) de Chronicle. Gestiona dos estructuras de mensajes principales: los mensajes "RPC.PreRequest/PostRequest" se analizan mediante patrones Grok, mientras que otros mensajes se procesan como objetos JSON, extrayendo los campos relevantes y asignándolos al esquema UDM.

Antes de empezar

Asegúrate de que cumples los siguientes requisitos previos:

  • Instancia de Google SecOps
  • El flujo de VPC está configurado y activo en tu Google Cloud entorno
  • Acceso privilegiado a Signal Sciences WAF

Crea un Google Cloud segmento de almacenamiento

  1. Inicia sesión en la Google Cloud consola.
  2. Ve a la página Segmentos de Cloud Storage.

    Ir a Contenedores

  3. Haz clic en Crear.

  4. En la página Crear un segmento, introduce la información del segmento. Después de cada uno de los pasos siguientes, haga clic en Continuar para pasar al siguiente:

    1. En la sección Empezar, haz lo siguiente:

      • Introduce un nombre único que cumpla los requisitos de nombres de segmentos (por ejemplo, vpcflow-logs).
      • Para habilitar el espacio de nombres jerárquico, haz clic en la flecha para desplegar la sección Optimizar para cargas de trabajo orientadas a archivos y con gran cantidad de datos y, a continuación, selecciona Habilitar espacio de nombres jerárquico en este contenedor.
      • Para añadir una etiqueta de contenedor, haz clic en la flecha para desplegar la sección Etiquetas.
      • Haga clic en Añadir etiqueta y especifique una clave y un valor para la etiqueta.
    2. En la sección Elige dónde quieres almacenar los datos, haz lo siguiente:

      • Selecciona un Tipo de ubicación.
      • Usa el menú del tipo de ubicación para seleccionar una Ubicación donde se almacenarán de forma permanente los datos de los objetos de tu segmento.
      • Para configurar la replicación entre contenedores, despliega la sección Configurar la replicación entre contenedores.
    3. En la sección Elige una clase de almacenamiento para tus datos, selecciona una clase de almacenamiento predeterminada para el segmento o Autoclass para gestionar automáticamente la clase de almacenamiento de los datos del segmento.

    4. En la sección Elige cómo quieres 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 del segmento.

    5. En la sección Elige cómo proteger los datos de los objetos, haz lo siguiente:

      • Selecciona cualquiera de las opciones de Protección de datos que quieras configurar para tu contenedor.
      • Para elegir cómo se cifrarán los datos de los objetos, haga clic en la flecha del desplegable Cifrado de datos y seleccione un Método de cifrado de datos.
  5. Haz clic en Crear.

Configurar una clave de API de Signal Sciences WAF

  1. Inicia sesión en la interfaz web de Signal Sciences WAF.
  2. Ve a Mi perfil > Tokens de acceso a la API.
  3. Haz clic en Añadir token de acceso a la API.
  4. Proporciona un nombre único y descriptivo (por ejemplo, Google SecOps).
  5. Haz clic en Crear token de acceso a la API.
  6. Copia y guarda el token en un lugar seguro.
  7. Haz clic en Entendido para terminar de crear el token.

Implementar una secuencia de comandos en un host Linux para extraer registros de Signal Sciences y almacenarlos en Google Cloud

  1. Inicia sesión en el host de Linux mediante SSH.
  2. Instala la biblioteca de Python para almacenar el JSON del WAF de Signal Sciences en un segmento de Cloud Storage:

    pip install google-cloud-storage
    
  3. Define 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"
    
  4. Configura las siguientes variables de entorno, ya que 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>
    
  5. 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)
    

    Configurar feeds

Para configurar un feed, sigue estos pasos:

  1. Ve a Configuración de SIEM > Feeds.
  2. Haz clic en Añadir feed.
  3. En la página siguiente, haga clic en Configurar un solo feed.
  4. En el campo Nombre del feed, introduce un nombre para el feed (por ejemplo, Signal Sciences WAF Logs).
  5. Seleccione Google Cloud Storage como Tipo de origen.
  6. Seleccione Signal Sciences WAF como Tipo de registro.
  7. Haz clic en Obtener cuenta de servicio en Cuenta de servicio de Chronicle.
  8. Haz clic en Siguiente.
  9. Especifique los valores de los siguientes parámetros de entrada:

    • URI de segmento de almacenamiento: URL de segmento de almacenamiento en formato gs://my-bucket/<value>. Google Cloud
    • El URI es un: selecciona Directorio que incluye subdirectorios.
    • Opciones de eliminación de la fuente: selecciona la opción de eliminación que prefieras.

  10. Haz clic en Siguiente.

  11. Revise la configuración de la nueva fuente en la pantalla Finalizar y, a continuación, haga clic en Enviar.

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.
Tipo de contenido security_result.about.labels El valor se toma del campo Content-Type del registro sin procesar y se asigna a security_result.about.labels.
creado 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.
etiquetas 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 mediante 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 sobre el principal y el objetivo. Si están presentes tanto el objetivo como la entidad 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 se ha codificado como SIGNAL_SCIENCES_WAF.
metadata.product_name El valor se ha codificado como Signal Sciences WAF.
metadata.vendor_name El valor se ha 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 mediante un filtro grok.
target.user.userid El valor se extrae del campo message_data mediante un filtro grok.

¿Necesitas más ayuda? Recibe respuestas de los miembros de la comunidad y de los profesionales de Google SecOps.