Descripción general del análisis de registros

Compatible con:

En este documento, se proporciona una descripción general de cómo Google Security Operations analiza los registros sin procesar en el formato del modelo de datos unificado (UDM).

Google SecOps puede recibir datos de registros provenientes de las siguientes fuentes de transferencia:

  • Receptor de reenvío de Google SecOps
  • Feed de la API de Chronicle
  • API de Chronicle Ingestion
  • Socio tecnológico externo

En general, los clientes envían los datos como registros sin procesar originales. Google SecOps identifica de forma única el dispositivo que generó los registros con LogType. LogType identifica ambos elementos:

  • El proveedor y el dispositivo que generaron el registro, como Cisco Firewall, Linux DHCP Server o Bro DNS
  • qué analizador convierte el registro sin procesar en UDM estructurado. Existe una relación de uno a uno entre un analizador y un LogType. Cada analizador convierte los datos que recibe un solo LogType.

Google SecOps proporciona un conjunto de analizadores predeterminados que leen los registros sin procesar originales y generan registros UDM estructurados a partir de los datos del registro sin procesar original. Google SecOps mantiene estos analizadores. Los clientes también pueden definir instrucciones de asignación de datos personalizadas creando un analizador específico para el cliente.

Flujo de trabajo de normalización y transferencia

El analizador contiene instrucciones de asignación de datos. Define cómo se asignan los datos del registro sin procesar original a uno o más campos en la estructura de datos del UDM.

Si no hay errores de análisis, Google SecOps crea un registro estructurado en el UDM con los datos del registro sin procesar. El proceso de convertir un registro sin procesar en un registro de UDM se denomina normalización.

Un analizador predeterminado puede asignar un subconjunto de valores principales del registro sin procesar. Por lo general, estos campos principales son los más importantes para proporcionar estadísticas de seguridad en Google SecOps. Los valores sin asignar permanecen en el registro sin procesar, pero no se almacenan en el registro del UDM.

Un cliente también puede usar la API de Ingestion para enviar datos en formato UDM estructurado.

Personaliza la forma en que se analizan los datos ingeridos

Google SecOps proporciona las siguientes capacidades que permiten a los clientes personalizar el análisis de datos en los datos de registros originales entrantes.

  • Analizadores específicos del cliente: Los clientes crean una configuración de analizador personalizada para un tipo de registro específico que satisfaga sus requisitos particulares. Un analizador específico del cliente reemplaza al analizador predeterminado para el LogType específico. Para obtener más detalles, consulta Administra analizadores personalizados y prediseñados.
  • Extensiones del analizador: Los clientes pueden agregar instrucciones de asignación personalizadas además de la configuración del analizador predeterminado. Cada cliente puede crear su propio conjunto único de instrucciones de asignación personalizadas. Estas instrucciones de asignación definen cómo extraer y transformar campos adicionales de los registros sin procesar originales en campos de UDM. Una extensión del analizador no reemplaza el analizador predeterminado ni el específico del cliente.

Ejemplo con un registro de proxy web de Squid

En esta sección, se proporciona un ejemplo de registro de proxy web de Squid y se describe cómo se asignan los valores a un registro de UDM. Para obtener una descripción de todos los campos del esquema del UDM, consulta la lista de campos del modelo de datos unificado.

El registro de proxy web de Squid de ejemplo contiene valores separados por espacios. Cada registro representa un evento y almacena los siguientes datos: marca de tiempo, duración, cliente, código o estado del resultado, bytes transmitidos, método de solicitud, URL, usuario, código de jerarquía y tipo de contenido. En este ejemplo, se extraen y se asignan los siguientes campos a un registro de UDM: hora, cliente, estado del resultado, bytes, método de solicitud y URL.

1588059648.129 23 192.168.23.4 TCP_HIT/200 904 GET www.google.com/images/sunlogo.png - HIER_DIRECT/203.0.113.52 image/jpeg

Ejemplo de proxy web Squid

A medida que comparas estas estructuras, observa que solo se incluye un subconjunto de los datos de registro originales en el registro del UDM. Algunos campos son obligatorios y otros son opcionales. Además, solo un subconjunto de las secciones del registro del UDM contiene datos. Si el analizador no asigna los datos del registro original al registro del UDM, no verás esa sección del registro del UDM en Google SecOps.

Registra valores asignados al UDM

La sección metadata almacena la marca de tiempo del evento. Ten en cuenta que el valor se convirtió del formato EPOCH al formato RFC 3339. Esta conversión es opcional. La marca de tiempo se puede almacenar en formato EPOCH, con un preprocesamiento para separar las partes de segundos y milisegundos en campos independientes.

El campo metadata.event_type almacena el valor NETWORK_HTTP, que es un valor enumerado que identifica el tipo de evento. El valor de metadata.event_type determina qué campos del UDM adicionales son obligatorios y cuáles son opcionales. Los valores de product_name y vendor_name contienen descripciones fáciles de entender del dispositivo que registró el registro original.

El metadata.event_type en un registro de evento de UDM no es el mismo que el log_type definido cuando se transfieren datos con la API de Ingestion. Estos dos atributos almacenan información diferente.

La sección network contiene valores del evento de registro original. En este ejemplo, observa que el valor de estado del registro original se analizó desde el campo "código/estado del resultado" antes de escribirse en el registro de UDM. Solo se incluyó el result_code en el registro del UDM.

Registra valores asignados al UDM

La sección principal almacena la información del cliente del registro original. La sección target almacena la URL completamente calificada y la dirección IP.

La sección security_result almacena uno de los valores de enumeración para representar la acción que se registró en el registro original.

Este es el registro de UDM con formato JSON. Ten en cuenta que solo se incluyen las secciones que contienen datos. No se incluyen las secciones src, observer, intermediary, about y extensions.

{
        "metadata": {
            "event_timestamp": "2020-04-28T07:40:48.129Z",
            "event_type": "NETWORK_HTTP",
            "product_name": "Squid Proxy",
            "vendor_name": "Squid"
        },
        "principal": {
            "ip": "192.168.23.4"
        },
        "target": {
            "url": "www.google.com/images/sunlogo.png",
            "ip": "203.0.113.52"
        },
        "network": {
            "http": {
                "method": "GET",
                "response_code": 200,
                "received_bytes": 904
            }
        },
        "security_result": {
            "action": "UNKNOWN_ACTION"
        }
}

Pasos dentro de las instrucciones del analizador

Las instrucciones de asignación de datos dentro de un analizador siguen un patrón común, como se indica a continuación:

  1. Analiza y extrae datos del registro original.
  2. Manipular los datos extraídos Esto incluye el uso de lógica condicional para analizar valores de forma selectiva, convertir tipos de datos, reemplazar subcadenas en un valor, convertir a mayúsculas o minúsculas, etcétera.
  3. Asigna valores a los campos de UDM.
  4. Genera el registro de UDM asignado a la clave @output.

Analiza y extrae datos del registro original

Establece la sentencia de filtro

La instrucción filter es la primera del conjunto de instrucciones de análisis. Todas las instrucciones de análisis adicionales se encuentran dentro de la instrucción filter.

filter {

}

Inicializa las variables que almacenarán los valores extraídos

Dentro de la declaración filter, inicializa las variables intermedias que el analizador usará para almacenar los valores extraídos del registro.

Estas variables se usan cada vez que se analiza un registro individual. El valor de cada variable intermedia se establecerá en uno o más campos del UDM más adelante en las instrucciones de análisis.

  mutate {
    replace => {
      "event.idm.read_only_udm.metadata.product_name" => "Webproxy"
      "event.idm.read_only_udm.metadata.vendor_name" => "Squid"
      "not_valid_log" => "false"
      "when" => ""
      "srcip" => ""
      "action" => ""
      "username" => ""
      "url" => ""
      "tgtip" => ""
      "method" => ""
    }
  }

Extrae valores individuales del registro

Google SecOps proporciona un conjunto de filtros basados en Logstash para extraer campos de los archivos de registro originales. Según el formato del registro, puedes usar uno o varios filtros de extracción para extraer todos los datos del registro. Si la cadena es:

  • JSON nativo: La sintaxis del analizador es similar a la del filtro JSON, que admite registros con formato JSON. No se admite JSON anidado.
  • El formato XML y la sintaxis del analizador son similares al filtro XML, que admite registros con formato XML.
  • pares clave-valor, la sintaxis del analizador es similar a la del filtro Kv, que admite mensajes con formato de clave-valor.
  • El formato CSV y la sintaxis del analizador son similares al filtro Csv, que admite mensajes con formato CSV.
  • En todos los demás formatos, la sintaxis del analizador es similar al filtro GROK con patrones integrados de GROK . Se usan instrucciones de extracción de estilo Regex.

Google SecOps proporciona un subconjunto de las capacidades disponibles en cada filtro. Google SecOps también proporciona una sintaxis de asignación de datos personalizada que no está disponible en los filtros. Consulta la referencia de la sintaxis del analizador para obtener una descripción de las funciones compatibles y las funciones personalizadas.

Continuando con el ejemplo del registro del proxy web de Squid, la siguiente instrucción de extracción de datos incluye una combinación de la sintaxis de Grok de Logstash y expresiones regulares.

La siguiente instrucción de extracción almacena valores en las siguientes variables intermedias:

  • when
  • srcip
  • action
  • returnCode
  • size
  • method
  • username
  • url
  • tgtip

Esta instrucción de ejemplo también usa la palabra clave overwrite para almacenar los valores extraídos en cada variable. Si el proceso de extracción devuelve un error, la instrucción on_error establece not_valid_log en True.

grok {
   match => {
     "message" => [
       "%{NUMBER:when}\\s+\\d+\\s%{SYSLOGHOST:srcip} %{WORD:action}\\/%{NUMBER:returnCode} %{NUMBER:size} %{WORD:method} (?P<url>\\S+) (?P<username>.*?) %{WORD}\\/(?P<tgtip>\\S+).*"
     ]
   }
   overwrite => ["when","srcip","action","returnCode","size","method","url","username","tgtip"]
   on_error => "not_valid_log"
}

Manipular y transformar los valores extraídos

Google SecOps aprovecha las capacidades del complemento de filtro mutate de Logstash para permitir la manipulación de los valores extraídos del registro original. Google SecOps proporciona un subconjunto de las capacidades disponibles en el complemento. Consulta la sintaxis del analizador para obtener una descripción de las funciones compatibles y las funciones personalizadas, como las siguientes:

  • convertir valores a un tipo de datos diferente
  • reemplazar valores en la cadena
  • combinar dos arrays o agregar una cadena a un array Los valores de cadenas se convierten en un array antes de la combinación.
  • convertir a minúsculas o mayúsculas

En esta sección, se proporcionan ejemplos de transformación de datos basados en el registro del proxy web de Squid que se presentó anteriormente.

Transforma la marca de tiempo del evento

Todos los eventos almacenados como un registro de UDM deben tener una marca de tiempo del evento. En este ejemplo, se verifica si se extrajo un valor para los datos del registro. Luego, usa la función de fecha de Grok para hacer coincidir el valor con el formato de hora UNIX.

if [when] != "" {
  date {
    match => [
      "when", "UNIX"
    ]
   }
 }

Transforma el valor de username

La siguiente instrucción de ejemplo convierte el valor de la variable username a minúsculas.

mutate {
   lowercase => [ "username"]
   }

Transforma el valor de action

En el siguiente ejemplo, se evalúa el valor de la variable intermedia action y se cambia el valor a ALLOW, BLOCK o UNKNOWN_ACTION, que son valores válidos para el campo security_result.action del UDM. El campo security_result.action del UDM es un tipo enumerado que solo almacena valores específicos.

if ([action] == "TCP_DENIED" or [action] == "TCP_MISS" or [action] == "Denied" or [action] == "denied" or [action] == "Dropped") {
      mutate {
        replace => {
          "action" => "BLOCK"
        }
      }
   } else if ([action] == "TCP_TUNNEL" or [action] == "Accessed" or [action] == "Built" or [action] == "Retrieved" or [action] == "Stored") {
     mutate {
        replace => {
          "action" => "ALLOW"
        }
     }
   } else {
      mutate {
        replace => {
          "action" => "UNKNOWN_ACTION" }
      }
   }

Transforma la dirección IP de destino

En el siguiente ejemplo, se verifica si hay un valor en la variable intermedia tgtip. Si se encuentra, el valor se compara con un patrón de dirección IP usando un patrón de Grok predefinido. Si se produce un error al hacer coincidir el valor con un patrón de dirección IP, la función on_error establece la propiedad not_valid_tgtip en True. Si la coincidencia se realiza correctamente, no se establece la propiedad not_valid_tgtip.

if [tgtip] not in [ "","-" ] {
   grok {
     match => {
       "tgtip" => [ "%{IP:tgtip}" ]
     }
     overwrite => ["tgtip"]
     on_error => "not_valid_tgtip"
   }

Cambia el tipo de datos y el tamaño de returnCode

En el siguiente ejemplo, se convierte el valor de la variable size en uinteger y el valor de la variable returnCode en integer. Esto es necesario porque la variable size se guardará en el campo network.received_bytes de UDM, que almacena un tipo de datos int64. La variable returnCode se guardará en el campo network.http.response_code del UDM, que almacena un tipo de datos int32.

mutate {
  convert => {
    "returnCode" => "integer"
    "size" => "uinteger"
  }
}

Asigna valores a los campos de UDM en un evento

Después de extraer y preprocesar los valores, asígnalos a los campos en un registro de evento del UDM. Puedes asignar tanto valores extraídos como valores estáticos a un campo del UDM.

Si completas event.disambiguation_key, asegúrate de que este campo sea único para cada evento que se genere en el registro determinado. Si dos eventos diferentes tienen el mismo disambiguation_key, esto generará un comportamiento inesperado en el sistema.

Los ejemplos de analizador de esta sección se basan en el ejemplo anterior del registro del proxy web Squid.

Cómo guardar la marca de tiempo del evento

Cada registro de evento del UDM debe tener un valor establecido para el campo metadata.event_timestamp del UDM. En el siguiente ejemplo, se guarda la marca de tiempo del evento extraída del registro en la variable integrada @timestamp. Google Security Operations guarda esta información en el campo metadata.event_timestamp del UDM de forma predeterminada.

mutate {
  rename => {
    "when" => "timestamp"
  }
}

Cómo establecer el tipo de evento

Cada registro de evento de UDM debe tener un valor establecido para el campo metadata.event_type de UDM. Este campo es un tipo enumerado. El valor de este campo determina qué campos adicionales del UDM se deben completar para que se guarde el registro del UDM. El proceso de análisis y normalización fallará si alguno de los campos obligatorios no contiene datos válidos.

replace => {
    "event.idm.read_only_udm.metadata.event_type" => "NETWORK_HTTP"
   }
}

Guarda los valores username y method con la instrucción replace.

Los valores de los campos intermedios username y method son cadenas. En el siguiente ejemplo, se verifica si existe un valor válido y, si es así, se almacena el valor username en el campo principal.user.userid de UDM y el valor method en el campo network.http.method de UDM.

if [username] not in [ "-" ,"" ] {
  mutate {
    replace => {
      "event.idm.read_only_udm.principal.user.userid" => "%{username}"
    }
  }
}

if [method] != "" {
  mutate {
    replace => {
      "event.idm.read_only_udm.network.http.method" => "%{method}"
    }
  }
}

Guarda el action en el campo security_result.action del UDM.

En la sección anterior, se evaluó y transformó el valor de la variable intermedia action en uno de los valores estándar para el campo security_result.action del UDM.

Los campos security_result y action del UDM almacenan un array de elementos, lo que significa que debes seguir un enfoque ligeramente diferente cuando guardes este valor.

Primero, guarda el valor transformado en un campo intermedio security_result.action. El campo security_result es principal del campo action.

mutate {
   merge => {
     "security_result.action" => "action"
   }
}

A continuación, guarda el campo intermedio security_result.action en el campo security_result del UDM. El campo security_result del UDM almacena un array de elementos, por lo que el valor se agrega a este campo.

 # save the security_result field
mutate {
  merge => {
    "event.idm.read_only_udm.security_result" => "security_result"
  }
}

Almacena la dirección IP de destino y la dirección IP de origen con la instrucción merge.

Almacena los siguientes valores en el registro de eventos del UDM:

  • Valor de la variable intermedia srcip en el campo principal.ip del UDM.
  • Valor de la variable intermedia tgtip en el campo target.ip del UDM.

Los campos principal.ip y target.ip del UDM almacenan un array de elementos, por lo que los valores se agregan a cada campo.

En los siguientes ejemplos, se muestran diferentes enfoques para guardar estos valores. Durante el paso de transformación, la variable intermedia tgtip se correlacionó con una dirección IP a través de un patrón de Grok predefinido. La siguiente instrucción de ejemplo verifica si la propiedad not_valid_tgtip es verdadera, lo que indica que el valor de tgtip no pudo coincidir con un patrón de dirección IP. Si es falso, guarda el valor de tgtip en el campo target.ip del UDM.

if ![not_valid_tgtip] {
  mutate {
    merge => {
      "event.idm.read_only_udm.target.ip" => "tgtip"
    }
  }
 }

La variable intermedia srcip no se transformó. La siguiente instrucción verifica si se extrajo un valor del registro original y, si fue así, guarda el valor en el campo principal.ip del UDM.

if [srcip] != "" {
  mutate {
    merge => {
      "event.idm.read_only_udm.principal.ip" => "srcip"
    }
  }
}

Guarda url, returnCode y size con la sentencia rename.

La siguiente instrucción de ejemplo almacena los valores con la instrucción rename:

  • La variable url se guardó en el campo target.url del UDM.
  • Es la variable intermedia returnCode que se guardó en el campo network.http.response_code del UDM.
  • Es la variable intermedia size que se guardó en el campo network.received_bytes del UDM.
mutate {
  rename => {
     "url" => "event.idm.read_only_udm.target.url"
     "returnCode" => "event.idm.read_only_udm.network.http.response_code"
     "size" => "event.idm.read_only_udm.network.received_bytes"
  }
}

Vincula el registro de UDM al resultado

La instrucción final en la instrucción de asignación de datos genera los datos procesados en un registro de eventos del UDM.

mutate {
    merge => {
      "@output" => "event"
    }
  }

El código completo del analizador

Este es el ejemplo de código completo del analizador. El orden de las instrucciones no sigue el mismo orden que las secciones anteriores de este documento, pero genera el mismo resultado.

filter {

# initialize variables
  mutate {
    replace => {
      "event.idm.read_only_udm.metadata.product_name" => "Webproxy"
      "event.idm.read_only_udm.metadata.vendor_name" => "Squid"
      "not_valid_log" => "false"
      "when" => ""
      "srcip" => ""
      "action" => ""
      "username" => ""
      "url" => ""
      "tgtip" => ""
      "method" => ""
    }
  }

  # Extract fields from the raw log.
    grok {
      match => {
        "message" => [
          "%{NUMBER:when}\\s+\\d+\\s%{SYSLOGHOST:srcip} %{WORD:action}\\/%{NUMBER:returnCode} %{NUMBER:size} %{WORD:method} (?P<url>\\S+) (?P<username>.*?) %{WORD}\\/(?P<tgtip>\\S+).*"
        ]
      }
      overwrite => ["when","srcip","action","returnCode","size","method","url","username","tgtip"]
      on_error => "not_valid_log"
    }

  # Parse event timestamp
  if [when] != "" {
    date {
      match => [
        "when", "UNIX"
      ]
     }
   }

   # Save the value in "when" to the event timestamp
   mutate {
     rename => {
       "when" => "timestamp"
     }
   }

   # Transform and save username
   if [username] not in [ "-" ,"" ] {
     mutate {
       lowercase => [ "username"]
        }
      }
     mutate {
       replace => {
         "event.idm.read_only_udm.principal.user.userid" => "%{username}"
       }
     }


if ([action] == "TCP_DENIED" or [action] == "TCP_MISS" or [action] == "Denied" or [action] == "denied" or [action] == "Dropped") {
      mutate {
        replace => {
          "action" => "BLOCK"
        }
      }
   } else if ([action] == "TCP_TUNNEL" or [action] == "Accessed" or [action] == "Built" or [action] == "Retrieved" or [action] == "Stored") {
     mutate {
        replace => {
          "action" => "ALLOW"
        }
     }
   } else {
      mutate {
        replace => {
          "action" => "UNKNOWN_ACTION" }
      }
   }

  # save transformed value to an intermediary field
   mutate {
      merge => {
        "security_result.action" => "action"
      }
   }

    # save the security_result field
    mutate {
      merge => {
        "event.idm.read_only_udm.security_result" => "security_result"
      }
    }

   # check for presence of target ip. Extract and store target IP address.
   if [tgtip] not in [ "","-" ] {
     grok {
       match => {
         "tgtip" => [ "%{IP:tgtip}" ]
       }
       overwrite => ["tgtip"]
       on_error => "not_valid_tgtip"
     }

     # store  target IP address
     if ![not_valid_tgtip] {
       mutate {
         merge => {
           "event.idm.read_only_udm.target.ip" => "tgtip"
         }
       }
     }
   }

   # convert  the returnCode and size  to integer data type
   mutate {
     convert => {
       "returnCode" => "integer"
       "size" => "uinteger"
     }
   }

   # save  url, returnCode, and size
   mutate {
     rename => {
        "url" => "event.idm.read_only_udm.target.url"
        "returnCode" => "event.idm.read_only_udm.network.http.response_code"
        "size" => "event.idm.read_only_udm.network.received_bytes"
     }

     # set the event type to NETWORK_HTTP
     replace => {
        "event.idm.read_only_udm.metadata.event_type" => "NETWORK_HTTP"
     }
   }

   # validate and set source IP address
   if [srcip] != "" {
     mutate {
       merge => {
         "event.idm.read_only_udm.principal.ip" => "srcip"
       }
     }
   }

  # save  event to @output
   mutate {
     merge => {
       "@output" => "event"
     }
   }

} #end of filter

¿Necesitas más ayuda? Obtén respuestas de miembros de la comunidad y profesionales de Google SecOps.