Coletar registros do WAF da Signal Sciences
Este documento explica como transferir os registros do WAF da Signal Sciences para as Operações de segurança do Google usando o Google Cloud Storage. O analisador transforma os registros da Signal Sciences do formato JSON no modelo de dados unificado (UDM, na sigla em inglês) do Chronicle. Ele processa duas estruturas de mensagens principais: as mensagens "RPC.PreRequest/PostRequest" são analisadas usando padrões Grok, enquanto outras mensagens são processadas como objetos JSON, extraindo campos relevantes e mapeando-os para o esquema da UDM.
Antes de começar
Verifique se você tem os pré-requisitos a seguir:
- Instância do Google SecOps
- O VPC Flow está configurado e ativo no seu Google Cloud ambiente
- Acesso privilegiado ao WAF da Signal Sciences
Crie um bucket do Google Cloud Storage
- Faça login no console do Google Cloud .
Acesse a página Buckets do Cloud Storage.
Clique em Criar.
Na página Criar um bucket, insira as informações do seu bucket. Após cada uma das etapas a seguir, clique em Continuar para prosseguir para a próxima:
Na seção Começar, faça o seguinte:
- Insira um nome exclusivo que atenda aos requisitos de nome de bucket (por exemplo, vpcflow-logs).
- Para ativar o namespace hierárquico, clique na seta de expansão para abrir a seção Otimizar para cargas de trabalho orientadas a arquivos e com uso intensivo de dados e selecione Ativar namespace hierárquico neste bucket.
- Para adicionar um rótulo de bucket, clique na seta de expansão para abrir a seção Rótulos.
- Clique em Adicionar rótulo e especifique uma chave e um valor para o rótulo.
Na seção Escolha onde armazenar seus dados, faça o seguinte:
- Selecione um tipo de local.
- Use o menu do tipo de local para selecionar um Local em que os dados de objetos no bucket serão armazenados permanentemente.
- Para configurar a replicação entre buckets, abra a seção Configurar a replicação entre buckets.
Na seção Escolha uma classe de armazenamento para seus dados, selecione uma classe de armazenamento padrão para o bucket ou selecione Classe automática para gerenciamento automático da classe de armazenamento dos dados do bucket.
Na seção Escolha como controlar o acesso a objetos, selecione não para aplicar a prevenção de acesso público e selecione um modelo de controle de acesso para os objetos do bucket.
Na seção Escolha como proteger os dados do objeto, faça o seguinte:
- Selecione qualquer uma das opções em Proteção de dados que você quer definir para o bucket.
- Para escolher como os dados do objeto serão criptografados, clique na seta de expansão identificada como Criptografia de dados e selecione um método de criptografia de dados.
Clique em Criar.
Configurar uma chave de API do WAF da Signal Sciences
- Faça login na UI da Web do Signal Sciences WAF.
- Acesse Meu perfil > Tokens de acesso da API.
- Clique em Adicionar token de acesso à API.
- Forneça um nome exclusivo e descritivo (por exemplo,
Google SecOps
). - Clique em Criar token de acesso à API.
- Copie e salve o token em um local seguro.
- Clique em Entendi para concluir a criação do token.
Implantar um script em um host Linux para extrair registros do Signal Sciences e armazená-los em Google Cloud
- Faça login no host Linux usando SSH.
Instale a biblioteca Python para armazenar o JSON do WAF da Signal Sciences em um bucket do Cloud Storage:
pip install google-cloud-storage
Defina essa variável de ambiente para chamar o arquivo JSON que tem as credenciais de Google Cloud:
export GOOGLE_APPLICATION_CREDENTIALS="path/to/your/service-account-key.json"
Configure as seguintes variáveis de ambiente, porque essas informações não podem ser codificadas em disco:
export SIGSCI_EMAIL=<Signal_Sciences_account_email> export SIGSCI_TOKEN=<Signal_Sciences_API_token> export SIGSCI_CORP=<Corporation_name_in_Signal_Sciences>
Execute o script a seguir:
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)
Configurar feeds
Há dois pontos de entrada diferentes para configurar feeds na plataforma Google SecOps:
- Configurações do SIEM > Feeds
- Hub de conteúdo > Pacotes de conteúdo
Configurar feeds em "Configurações do SIEM" > "Feeds"
Para configurar um feed, siga estas etapas:
- Acesse Configurações do SIEM > Feeds.
- Clique em Adicionar novo feed.
- Na próxima página, clique em Configurar um único feed.
- No campo Nome do feed, insira um nome para o feed (por exemplo,
Signal Sciences WAF Logs
). - Selecione Google Cloud Storage como o Tipo de origem.
- Selecione Signal Sciences WAF como o Tipo de registro.
- Clique em Pegar conta de serviço como a Conta de serviço do Chronicle.
- Clique em Próxima.
Especifique valores para os seguintes parâmetros de entrada:
- URI do bucket do Cloud Storage: Google Cloud URL do bucket do Cloud Storage no formato
gs://my-bucket/<value>
. - URI Is A: selecione Directory which includes subdirectories.
Opções de exclusão de origem: selecione a opção de exclusão de acordo com sua preferência.
- URI do bucket do Cloud Storage: Google Cloud URL do bucket do Cloud Storage no formato
Clique em Próxima.
Revise a configuração do novo feed na tela Finalizar e clique em Enviar.
Configurar feeds na Central de conteúdo
Especifique valores para os seguintes campos:
- URI do bucket do Cloud Storage: Google Cloud URL do bucket do Cloud Storage no formato
gs://my-bucket/<value>
. - URI Is A: selecione Directory which includes subdirectories.
Opções de exclusão de origem: selecione a opção de exclusão de acordo com sua preferência.
Opções avançadas
- Nome do feed: um valor preenchido automaticamente que identifica o feed.
- Tipo de origem: método usado para coletar registros no Google SecOps.
- Namespace do recurso: namespace associado ao feed.
- Rótulos de transferência: rótulos aplicados a todos os eventos desse feed.
Tabela de mapeamento da UDM
Campo de registro | Mapeamento do UDM | Lógica |
---|---|---|
CLIENT-IP | target.ip | Extraídos do campo de cabeçalho CLIENT-IP . |
CLIENT-IP | target.port | Extraídos do campo de cabeçalho CLIENT-IP . |
Conexão | security_result.about.labels | O valor é extraído do campo Connection do registro bruto e mapeado para security_result.about.labels . |
Content-Length | security_result.about.labels | O valor é extraído do campo Content-Length do registro bruto e mapeado para security_result.about.labels . |
Content-Type | security_result.about.labels | O valor é extraído do campo Content-Type do registro bruto e mapeado para security_result.about.labels . |
created | metadata.event_timestamp | O valor é extraído do campo created do registro bruto e mapeado para metadata.event_timestamp . |
details.headersIn | security_result.about.resource.attribute.labels | O valor é extraído do campo details.headersIn do registro bruto e mapeado para security_result.about.resource.attribute.labels . |
details.headersOut | security_result.about.resource.attribute.labels | O valor é extraído do campo details.headersOut do registro bruto e mapeado para security_result.about.resource.attribute.labels . |
details.id | principal.process.pid | O valor é extraído do campo details.id do registro bruto e mapeado para principal.process.pid . |
details.method | network.http.method | O valor é extraído do campo details.method do registro bruto e mapeado para network.http.method . |
details.protocol | network.application_protocol | O valor é extraído do campo details.protocol do registro bruto e mapeado para network.application_protocol . |
details.remoteCountryCode | principal.location.country_or_region | O valor é extraído do campo details.remoteCountryCode do registro bruto e mapeado para principal.location.country_or_region . |
details.remoteHostname | target.hostname | O valor é extraído do campo details.remoteHostname do registro bruto e mapeado para target.hostname . |
details.remoteIP | target.ip | O valor é extraído do campo details.remoteIP do registro bruto e mapeado para target.ip . |
details.responseCode | network.http.response_code | O valor é extraído do campo details.responseCode do registro bruto e mapeado para network.http.response_code . |
details.responseSize | network.received_bytes | O valor é extraído do campo details.responseSize do registro bruto e mapeado para network.received_bytes . |
details.serverHostname | principal.hostname | O valor é extraído do campo details.serverHostname do registro bruto e mapeado para principal.hostname . |
details.serverName | principal.asset.network_domain | O valor é extraído do campo details.serverName do registro bruto e mapeado para principal.asset.network_domain . |
details.tags | security_result.detection_fields | O valor é extraído do campo details.tags do registro bruto e mapeado para security_result.detection_fields . |
details.tlsCipher | network.tls.cipher | O valor é extraído do campo details.tlsCipher do registro bruto e mapeado para network.tls.cipher . |
details.tlsProtocol | network.tls.version | O valor é extraído do campo details.tlsProtocol do registro bruto e mapeado para network.tls.version . |
details.userAgent | network.http.user_agent | O valor é extraído do campo details.userAgent do registro bruto e mapeado para network.http.user_agent . |
details.uri | network.http.referral_url | O valor é extraído do campo details.uri do registro bruto e mapeado para network.http.referral_url . |
eventType | metadata.product_event_type | O valor é extraído do campo eventType do registro bruto e mapeado para metadata.product_event_type . |
headersIn | security_result.about.labels | O valor é extraído do campo headersIn do registro bruto e mapeado para security_result.about.labels . |
headersOut | security_result.about.labels | O valor é extraído do campo headersOut do registro bruto e mapeado para security_result.about.labels . |
ID | principal.process.pid | O valor é extraído do campo id do registro bruto e mapeado para principal.process.pid . |
mensagem | metadata.description | O valor é extraído do campo message do registro bruto e mapeado para metadata.description . |
método | network.http.method | O valor é extraído do campo method do registro bruto e mapeado para network.http.method . |
ModuleVersion | metadata.ingestion_labels | O valor é extraído do campo ModuleVersion do registro bruto e mapeado para metadata.ingestion_labels . |
msgData.actions | security_result.action | O valor é extraído do campo msgData.actions do registro bruto e mapeado para security_result.action . |
msgData.changes | target.resource.attribute.labels | O valor é extraído do campo msgData.changes do registro bruto e mapeado para target.resource.attribute.labels . |
msgData.conditions | security_result.description | O valor é extraído do campo msgData.conditions do registro bruto e mapeado para security_result.description . |
msgData.detailLink | network.http.referral_url | O valor é extraído do campo msgData.detailLink do registro bruto e mapeado para network.http.referral_url . |
msgData.name | target.resource.name | O valor é extraído do campo msgData.name do registro bruto e mapeado para target.resource.name . |
msgData.reason | security_result.summary | O valor é extraído do campo msgData.reason do registro bruto e mapeado para security_result.summary . |
msgData.sites | network.http.user_agent | O valor é extraído do campo msgData.sites do registro bruto e mapeado para network.http.user_agent . |
protocolo | network.application_protocol | O valor é extraído do campo protocol do registro bruto e mapeado para network.application_protocol . |
remoteCountryCode | principal.location.country_or_region | O valor é extraído do campo remoteCountryCode do registro bruto e mapeado para principal.location.country_or_region . |
remoteHostname | target.hostname | O valor é extraído do campo remoteHostname do registro bruto e mapeado para target.hostname . |
remoteIP | target.ip | O valor é extraído do campo remoteIP do registro bruto e mapeado para target.ip . |
responseCode | network.http.response_code | O valor é extraído do campo responseCode do registro bruto e mapeado para network.http.response_code . |
responseSize | network.received_bytes | O valor é extraído do campo responseSize do registro bruto e mapeado para network.received_bytes . |
serverHostname | principal.hostname | O valor é extraído do campo serverHostname do registro bruto e mapeado para principal.hostname . |
serverName | principal.asset.network_domain | O valor é extraído do campo serverName do registro bruto e mapeado para principal.asset.network_domain . |
tags | security_result.detection_fields | O valor é extraído do campo tags do registro bruto e mapeado para security_result.detection_fields . |
timestamp | metadata.event_timestamp | O valor é extraído do campo timestamp do registro bruto e mapeado para metadata.event_timestamp . |
tlsCipher | network.tls.cipher | O valor é extraído do campo tlsCipher do registro bruto e mapeado para network.tls.cipher . |
tlsProtocol | network.tls.version | O valor é extraído do campo tlsProtocol do registro bruto e mapeado para network.tls.version . |
URI | target.url | O valor é extraído do campo URI do registro bruto e mapeado para target.url . |
userAgent | network.http.user_agent | O valor é extraído do campo userAgent do registro bruto e mapeado para network.http.user_agent . |
uri | network.http.referral_url | O valor é extraído do campo uri do registro bruto e mapeado para network.http.referral_url . |
X-ARR-SSL | network.tls.client.certificate.issuer | O valor é extraído do campo de cabeçalho X-ARR-SSL usando filtros grok e kv. |
metadata.event_type | O tipo de evento é determinado pelo analisador com base na presença de informações de destino e principais. Se o alvo e o principal estiverem presentes, o tipo de evento será NETWORK_HTTP . Se apenas o principal estiver presente, o tipo de evento será STATUS_UPDATE . Caso contrário, o tipo de evento é GENERIC_EVENT . |
|
metadata.log_type | O valor é fixado em SIGNAL_SCIENCES_WAF . |
|
metadata.product_name | O valor é fixado em Signal Sciences WAF . |
|
metadata.vendor_name | O valor é fixado em Signal Sciences . |
|
principal.asset.hostname | O valor é retirado do campo principal.hostname . |
|
target.asset.hostname | O valor é retirado do campo target.hostname . |
|
target.asset.ip | O valor é retirado do campo target.ip . |
|
target.user.user_display_name | O valor é extraído do campo message_data usando um filtro grok. |
|
target.user.userid | O valor é extraído do campo message_data usando um filtro grok. |
Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.