Descripción general del análisis de registros
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 unificados (UDM).
Google Security Operations puede recibir datos de registro que se originan de la siguiente transferencia fuentes:
- Reenviador de Google Security Operations
- Feed de la API de Google Security Operations
- API de transferencia de Google Security Operations
- Socio de tecnología externo
En general, los clientes envían datos como registros sin procesar originales. Google Security Operations identifica de forma única el dispositivo que generó los registros con el LogType. El tipo de registro identifica ambos:
- el proveedor y el dispositivo que generó el registro, como Cisco Firewall, Linux DHCP Server o Bro DNS.
- que convierte el registro sin procesar en un modelo de datos unificados (UDM) estructurado. Existe una relación de uno a uno entre un analizador y un LogType. Cada analizador convierte los datos recibidos por un solo LogType.
Google Security Operations proporciona un conjunto de analizadores predeterminados que leen registros sin procesar originales y generan registros del UDM estructurados con datos del registro sin procesar original. Google Security Operations mantiene estos analizadores. Los clientes también pueden definir instrucciones personalizadas de asignación de datos creando un analizador específico del cliente. Comunícate con tu representante de Operaciones de seguridad de Google para obtener información sobre cómo crear un analizador específico del cliente.
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 de la AUA.
Si no hay errores de análisis, Google Security Operations crea un registro estructurado por UDM con a partir del registro sin procesar. El proceso de convertir un registro sin procesar en un registro de la UDM se llama normalización.
Un analizador predeterminado puede asignar un subconjunto de valores principales del registro sin procesar. Normalmente, estos campos básicos son los más importantes para proporcionar información de seguridad en Google Security Operations. Los valores no asignados permanecen en el registro sin procesar, pero no se almacenan en el registro de la UDM.
Un cliente también puede usar la API de transferencia. para enviar datos en formato de Modelo de datos unificado (UDM) estructurado.
Personaliza cómo se analizan los datos transferidos
Google Security Operations proporciona las siguientes funciones que permiten a los clientes personalizar el análisis de datos en los datos de registro originales entrantes.
- Analizadores específicos del cliente: los clientes crean un analizador personalizado. predeterminada para un tipo de registro específico que cumpla con y los requisitos de cumplimiento. Un analizador específico del cliente reemplaza el analizador predeterminado para el LogType específico. Comunícate con tu representante de Operaciones de seguridad de Google para obtener información sobre cómo crear un analizador específico del cliente.
- Extensiones de analizadores: Los clientes pueden agregar instrucciones de asignación personalizadas en además de la configuración predeterminada del analizador. Cada cliente puede crear su propio conjunto único de instrucciones de asignación personalizadas. Estas asignaciones definen cómo extraer y transformar campos adicionales de de los registros originales sin procesar a los campos UDM. Una extensión de analizador no reemplaza al analizador predeterminado ni al específico del cliente.
Ejemplo en el que se usa un registro del proxy web de Squid
En esta sección, se proporciona un ejemplo de registro del proxy web de Squid y se describe cómo la se asignan a un registro de UDM. Para la descripción de todos los campos en el esquema de UDM, consulta la Lista de campos del modelo de datos unificado
El ejemplo de registro del proxy web de Squid 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 asignan los siguientes campos a un registro de la 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
Cuando compares estas estructuras, observa que solo se incluye un subconjunto de los datos de registro originales en el registro de la UDM. Algunos campos son obligatorios y otros son opcionales. Además, solo un subconjunto de las secciones del registro UDM contienen datos. Si el analizador no asigna datos del registro original a la UDM no verás esa sección del registro de UDM en Google Security Operations.
La sección metadata
almacena la marca de tiempo del evento. Observa que el valor se convirtió
de EPOCH a formato RFC 3339. Esta conversión es opcional. La marca de tiempo puede ser
se almacenan como formato EPOCH, con procesamiento previo para separar los segundos y
de milisegundos en campos separados.
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 adicionales del UDM son obligatorios y cuáles son opcionales. Los operadores product_name
y
Los valores vendor_name
contienen descripciones del dispositivo fáciles de usar que
registró el registro original.
El metadata.event_type
en un registro de evento de la AUA no es el mismo que el log_type definido cuando se transfieren datos con la API de transferencia. Estos dos atributos almacenan
información diferente.
La sección network
contiene valores del evento de registro original. Observa que
ejemplo de que el valor de estado del registro original se analizó del
código/estado antes de escribirse en el registro de UDM. Solo el result_code
se incluyó en el registro de UDM.
En la sección principal
, se almacena la información del cliente del registro original. El
La sección target
almacena la URL completamente calificada y la dirección IP.
En la sección security_result
, se 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 la AUA con formato JSON. Ten en cuenta que solo las secciones
que contienen datos. No se incluyen las secciones src
, observer
, intermediary
, about
ni 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 sigue:
- Analiza y extrae datos del registro original.
- Manipular los datos extraídos Esto incluye el uso de lógica condicional para analizar valores de forma selectiva, convertir tipos de datos, reemplazar substrings en un valor, convertirlos a mayúsculas o minúsculas, etcétera.
- Asignar valores a los campos de la AUA
- Muestra el registro de la UDM asignado a la clave @output.
Analiza y extrae datos del registro original
Cómo establecer la sentencia de filtro
La sentencia filter
es la primera declaración del conjunto de instrucciones de análisis.
Todas las instrucciones de análisis adicionales se incluyen en la sentencia filter
.
filter {
}
Inicializa las variables que almacenarán los valores extraídos
Dentro de la sentencia filter
, inicializa las variables intermedias que usará el analizador 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 de la 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 Security Operations 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 Filtro JSON que admite registros con formato JSON. No se admite el JSON anidado.
- XML, la sintaxis del analizador es similar a la Filtro XML que admite registros con formato XML.
- pares clave-valor, la sintaxis del analizador es similar al filtro Kv, que admite mensajes con formato de par clave-valor.
- El formato CSV, la sintaxis del analizador es similar al filtro CSV, que admite mensajes con formato CSV.
- En todos los demás formatos, la sintaxis del analizador es similar al filtro GROOKAPIAN con patrones integrados de GROOKAPIAN. Se usan instrucciones de extracción de estilo Regex.
Google Security Operations proporciona un subconjunto de las funciones disponibles en cada filtro. Google Security Operations también ofrece una sintaxis de asignación de datos personalizada que no está disponible. en los filtros. Consulta la referencia de sintaxis del analizador para obtener una descripción de las funciones compatibles y personalizadas.
Siguiendo con el ejemplo de registro del proxy web de Squid, la siguiente instrucción de extracción de datos incluye una combinación de sintaxis de Logstash Grok y expresiones regulares.
La siguiente instrucción de extracción almacena valores en el siguiente intermedio variables:
when
srcip
action
returnCode
size
method
username
url
tgtip
Esta sentencia de ejemplo también usa la palabra clave overwrite
para almacenar los valores extraídos
en cada variable. Si el proceso de extracción muestra un error, la sentencia on_error
configura not_valid_log
como 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"
}
Manipula y transforma los valores extraídos
Google Security Operations aprovecha las capacidades del complemento de filtro mutate de Logstash para permitir la manipulación de los valores extraídos del registro original. Google Security Operations proporciona un subconjunto de las funciones disponibles del complemento. Consulta la sintaxis del analizador para ver una descripción de las características compatibles y personalizadas, como las siguientes:
- convertir valores en un tipo de datos diferente
- reemplaza los valores de 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 que se basan en el registro del proxy web de Squid que se presentó antes.
Cómo transformar la marca de tiempo del evento
Todos los eventos almacenados como 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
Función de fecha Grok
para que el valor coincida con el formato de hora UNIX
.
if [when] != "" {
date {
match => [
"when", "UNIX"
]
}
}
Transforma el valor username
La siguiente sentencia 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 cambia el valor a ALLOW, BLOCK o UNKNOWN_ACTION, que se
valores válidos para el campo UDM security_result.action
. El campo UDM security_result.action
es un tipo enumerado que almacena solo 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 busca un valor en la variable intermedia tgtip
.
Si se encuentra, el valor coincide con un patrón de dirección IP mediante un patrón de Grok predefinido. Si se produce un error que coincide el valor con un patrón de dirección IP, el
La función on_error
establece la propiedad not_valid_tgtip
en True
. Si la coincidencia
se realiza de forma correcta, entonces 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 de returnCode y size
En el siguiente ejemplo, se asigna el valor de la variable size
a uinteger
y el valor de la variable returnCode
a integer
. Esto es obligatorio porque la variable size
se guardará en el campo UDM network.received_bytes
, que almacena un tipo de datos int64
. El
La variable returnCode
se guardará en el campo de UDM network.http.response_code
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 procesar previamente los valores, asígnales a campos en un registro de eventos de la UDM. Puedes asignar valores extraídos y valores estáticos a un campo de la AUA.
Si propagas event.disambiguation_key
, asegúrate de que este campo sea único para
cada evento que se genera para un registro determinado. Si dos eventos diferentes tienen
mismo disambiguation_key
, se generará un comportamiento inesperado en el
en un sistema de archivos.
Los ejemplos de analizadores de esta sección se basan en el ejemplo de registro del proxy web de Squid. arriba.
Cómo guardar la marca de tiempo del evento
Cada registro de evento de la AUA debe tener un valor establecido para el campo metadata.event_timestamp
de la AUA. En el siguiente ejemplo, se guarda la marca de tiempo del evento extraída del registro en la variable integrada @timestamp
. Google Security Operations la guarda
Es el campo de UDM metadata.event_timestamp
de forma predeterminada.
mutate {
rename => {
"when" => "timestamp"
}
}
Configura el tipo de evento
Cada registro de evento de la AUA debe tener un valor establecido para el campo de la AUA metadata.event_type
. Este campo es un tipo enumerado. El valor de este campo determina
qué campos de UDM adicionales se deben propagar para que se guarde el registro de 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 sentencia replace
Los valores en 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 de UDM principal.user.userid
y el valor method
en el campo de UDM network.http.method
.
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 de UDM security_result.action
.
En la sección anterior, el valor de la variable intermedia action
era
Se evaluó y transformó en uno de los valores estándar del campo UDM security_result.action
.
Tanto los campos de la UDM security_result
como los de action
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 security_result.action
intermediario. El campo security_result
es superior al campo action
.
mutate {
merge => {
"security_result.action" => "action"
}
}
A continuación, guarda el campo intermediario security_result.action
intermedio en
Campo de UDM security_result
. El campo UDM security_result
almacena un array de
items, 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 de origen con la sentencia merge
Almacena los siguientes valores en el registro de eventos de la AUA:
- Valor de la variable intermedia de
srcip
para el campo de UDMprincipal.ip
. - Valor de la variable intermedia de
tgtip
para el campo de UDMtarget.ip
.
Tanto los campos de la AUA principal.ip
como los de target.ip
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 hizo coincidir con una dirección IP mediante un patrón de Grok predefinido. La siguiente declaración de ejemplo
verifica si la propiedad not_valid_tgtip
es verdadera, lo que indica que tgtip
no se pudo hacer coincidir el valor con un patrón de dirección IP. Si es falsa, guarda
Valor tgtip
al campo de UDM target.ip
if ![not_valid_tgtip] {
mutate {
merge => {
"event.idm.read_only_udm.target.ip" => "tgtip"
}
}
}
La variable intermedia srcip
no se transformó. La siguiente sentencia verifica si se extrajo un valor del registro original y, de ser así, lo guarda en el campo UDM principal.ip
.
if [srcip] != "" {
mutate {
merge => {
"event.idm.read_only_udm.principal.ip" => "srcip"
}
}
}
Guarda url
, returnCode
y size
con la sentencia rename
En la siguiente sentencia de ejemplo, se almacenan los siguientes valores con la sentencia rename
.
- La variable
url
se guarda en el campo UDMtarget.url
. - La variable intermedia
returnCode
se guardó en el campo de UDMnetwork.http.response_code
. - La variable intermedia
size
guardada en el campo UDMnetwork.received_bytes
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 a la salida
La instrucción final en la instrucción de asignación de datos genera los datos procesados en un registro de evento de 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 en el mismo orden que las secciones anteriores de este documento, pero obtendrás 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