Coletar registros do WAF da Fastly

Compatível com:

Visão geral

Esse analisador extrai campos dos registros JSON do WAF da Fastly, os transforma e renomeia, e os mapeia para o UDM. Ele processa vários tipos de dados, converte níveis de gravidade e categoriza eventos com base nas informações de IP e nome de host disponíveis. Ele também lida com possíveis falhas de análise e exclui entradas de registro com formato incorreto.

Antes de começar

  • Verifique se você tem uma instância do Google SecOps.
  • Uma conta da Fastly com acesso para configurar as configurações do WAF.

Configurar um feed no Google SecOps para processar os registros do WAF do Fastly

  1. Acesse Configurações do SIEM > Feeds.
  2. Clique em Adicionar novo.
  3. No campo Nome do feed, insira um nome para o feed (por exemplo, Logs do Fastly WAF).
  4. Selecione Webhook como o Tipo de origem.
  5. Selecione Fastly WAF como o Tipo de registro.
  6. Clique em Próxima.
  7. Opcional: especifique valores para os seguintes parâmetros de entrada:
    • Delimitador de divisão: o delimitador usado para separar linhas de registro, como \n.
    • Namespace de recursos: o namespace de recursos.
    • Rótulos de ingestão: o rótulo aplicado aos eventos desse feed.
  8. Clique em Próxima.
  9. Revise a configuração do feed na tela Finalizar e clique em Enviar.
  10. Clique em Gerar chave secreta para gerar uma chave secreta para autenticar esse feed.
  11. Copie e armazene a chave secreta. Não é possível acessar essa chave secreta novamente. Se necessário, você pode gerar uma nova chave secreta, mas essa ação torna a chave secreta anterior obsoleta.
  12. Na guia Detalhes, copie o URL do endpoint do feed no campo Informações do endpoint. É necessário especificar esse URL de endpoint no aplicativo cliente.
  13. Clique em Concluído.

Criar uma chave de API para o feed de webhook

  1. Acesse o console do Google Cloud > Credenciais.

    Ir para Credenciais

  2. Clique em Criar credenciais e, em seguida, selecione Chave de API.

  3. Restrinja o acesso da chave de API à API Google Security Operations.

Especificar o URL do endpoint

  1. No aplicativo cliente, especifique o URL do endpoint HTTPS fornecido no feed de webhook.
  2. Ative a autenticação especificando a chave de API e a chave secreta como parte do cabeçalho personalizado no seguinte formato:

    X-goog-api-key = API_KEY
    X-Webhook-Access-Key = SECRET
    

    Recomendação: especifique a chave de API como um cabeçalho em vez de especificar no URL.

  3. Se o cliente do webhook não tiver suporte a cabeçalhos personalizados, especifique a chave de API e a chave secreta usando parâmetros de consulta no seguinte formato:

    ENDPOINT_URL?key=API_KEY&secret=SECRET
    

    Substitua:

    • ENDPOINT_URL: o URL do endpoint do feed.
    • API_KEY: a chave de API para autenticação no Google Security Operations.
    • SECRET: a chave secreta gerada para autenticar o feed.

Configurar o webhook no Fastly

  1. Faça login no Fastly.
  2. Opcional: selecione um site no menu Sites (se você tiver mais de um).
  3. Selecione Gerenciar > Integrações do site.
  4. Clique em Adicionar integração de site.
  5. Selecione Webhook genérico.
  6. URL do webhook: insira ENDPOINT_URL do Google SecOps, seguido por API_KEY e SECRET.
  7. Posição do alerta: selecione Toda a atividade ou Atividade específica.
  8. Opcional: se você selecionou Atividade específica, acesse o Menu de atividades e selecione os tipos de atividade que você quer que o webhook envie.
  9. Clique em Criar integração de site.

Tabela de mapeamento do UDM

Campo de registro Mapeamento do UDM Lógica
anomaly_score security_result.detection_fields[].key: "anomaly"
security_result.detection_fields[].value: anomaly_score
Se waf.score.anomaly for 0 ou vazio e anomaly_score não estiver vazio ou 0, o valor anomaly_score será usado para preencher a matriz security_result.detection_fields com uma chave de "anomalia" e o valor do campo anomaly_score.
cache_status additional.fields[].key: "cache_status"
additional.fields[].value.string_value: cache_status
O valor cache_status é usado para preencher a matriz additional.fields com uma chave de "cache_status" e o valor do campo cache_status.
client_ip principal.ip: client_ip O campo client_ip é mapeado para principal.ip.
connection.fastly_is_edge additional.fields[].key: "fastly_is_edge"
additional.fields[].value.bool_value: connection.fastly_is_edge
O valor connection.fastly_is_edge é usado para preencher a matriz additional.fields com uma chave de "fastly_is_edge" e o valor do campo connection.fastly_is_edge.
connection.fastly_is_shield additional.fields[].key: "fastly_is_shield"
additional.fields[].value.bool_value: connection.fastly_is_shield
O valor connection.fastly_is_shield é usado para preencher a matriz additional.fields com uma chave de "fastly_is_shield" e o valor do campo connection.fastly_is_shield.
connection.request_tls_version network.tls.version: connection.request_tls_version O campo connection.request_tls_version é mapeado para network.tls.version.
fastly.server target.hostname: fastly.server O campo fastly.server é mapeado para target.hostname.
fastly.service_id additional.fields[].key: "service_id"
additional.fields[].value.string_value: fastly.service_id
O valor fastly.service_id é usado para preencher a matriz additional.fields com uma chave "service_id" e o valor do campo fastly.service_id.
geo.city principal.location.city: geo.city O campo geo.city é mapeado para principal.location.city.
geo.country principal.location.country_or_region: geo.country O campo geo.country é mapeado para principal.location.country_or_region.
geo.location principal.location.region_latitude: extraído de geo.location
principal.location.region_longitude: extraído de geo.location
A latitude e a longitude são extraídas do campo geo.location usando uma expressão regular e mapeadas para principal.location.region_latitude e principal.location.region_longitude, respectivamente.
geo.region principal.location.state: geo.region O campo geo.region é mapeado para principal.location.state.
host principal.hostname: host O campo host é mapeado para principal.hostname.
request_headers.accept_charset additional.fields[].key: "accept_charset"
additional.fields[].value.string_value: request_headers.accept_charset
O valor request_headers.accept_charset é usado para preencher a matriz additional.fields com uma chave de "accept_charset" e o valor do campo request_headers.accept_charset.
request_headers.accept_language additional.fields[].key: "accept_language"
additional.fields[].value.string_value: request_headers.accept_language
O valor request_headers.accept_language é usado para preencher a matriz additional.fields com uma chave "accept_language" e o valor do campo request_headers.accept_language.
request_headers.referer network.http.referral_url: request_headers.referer O campo request_headers.referer é mapeado para network.http.referral_url.
request_headers.user_agent network.http.user_agent: request_headers.user_agent O campo request_headers.user_agent é mapeado para network.http.user_agent.
request_id metadata.product_log_id: request_id O campo request_id é mapeado para metadata.product_log_id.
request_method network.http.method: request_method O campo request_method é mapeado para network.http.method.
response_headers.cache_control additional.fields[].key: "cache_control"
additional.fields[].value.string_value: response_headers.cache_control
O valor response_headers.cache_control é usado para preencher a matriz additional.fields com uma chave de "cache_control" e o valor do campo response_headers.cache_control.
response_headers.content_type additional.fields[].key: "content_type"
additional.fields[].value.string_value: response_headers.content_type
O valor response_headers.content_type é usado para preencher a matriz additional.fields com uma chave "content_type" e o valor do campo response_headers.content_type.
response_state additional.fields[].key: "response_state"
additional.fields[].value.string_value: response_state
O valor response_state é usado para preencher a matriz additional.fields com uma chave "response_state" e o valor do campo response_state.
response_status network.http.response_code: response_status O campo response_status é mapeado para network.http.response_code se o campo status estiver vazio.
rule_id security_result.rule_id: rule_id Se waf.rule_id estiver vazio, o valor rule_id será usado para preencher security_result.rule_id.
severity waf.severity: severity O valor do campo severity é copiado para waf.severity.
size_bytes.request_header network.sent_bytes: size_bytes.request_header O campo size_bytes.request_header é mapeado para network.sent_bytes.
size_bytes.response_header network.received_bytes: size_bytes.response_header O campo size_bytes.response_header é mapeado para network.received_bytes.
status network.http.response_code: status O campo status é mapeado para network.http.response_code.
timestamp metadata.event_timestamp: timestamp O campo timestamp é analisado e mapeado para metadata.event_timestamp.
url target.url: url O campo url é mapeado para target.url.
waf.blocked security_result.action: derivado Se waf.blocked for falso, security_result.action será definido como "PERMITIR". Se waf.blocked for verdadeiro, security_result.action será definido como "BLOCK".
waf.executed security_result.detection_fields[].key: "executed"
security_result.detection_fields[].value: waf.executed
O valor waf.executed é usado para preencher a matriz security_result.detection_fields com uma chave "executed" e o valor do campo waf.executed.
waf.failures security_result.detection_fields[].key: "failures"
security_result.detection_fields[].value: waf.failures
O valor waf.failures é usado para preencher a matriz security_result.detection_fields com uma chave de "failures" e o valor do campo waf.failures.
waf.logged security_result.detection_fields[].key: "logged"
security_result.detection_fields[].value: waf.logged
O valor waf.logged é usado para preencher a matriz security_result.detection_fields com uma chave "logged" e o valor do campo waf.logged.
waf.message metadata.description: waf.message Se waf.message não estiver vazio, ele será mapeado para metadata.description.
waf.rule_id security_result.rule_id: waf.rule_id Se waf.rule_id não estiver vazio, ele será mapeado para security_result.rule_id.
waf.score.anomaly security_result.detection_fields[].key: "anomaly"
security_result.detection_fields[].value: waf.score.anomaly
Se waf.score.anomaly não for 0 nem vazio, o valor será usado para preencher a matriz security_result.detection_fields com uma chave de "anomalia" e o valor do campo waf.score.anomaly.
waf.score.http_violation security_result.detection_fields[].key: "http_violation"
security_result.detection_fields[].value: waf.score.http_violation
Se waf.score.http_violation não for 0 nem vazio, o valor será usado para preencher a matriz security_result.detection_fields.
waf.score.lfi security_result.detection_fields[].key: "lfi"
security_result.detection_fields[].value: waf.score.lfi
Lógica semelhante à waf.score.http_violation.
waf.score.php_injection security_result.detection_fields[].key: "php_injection"
security_result.detection_fields[].value: waf.score.php_injection
Lógica semelhante à waf.score.http_violation.
waf.score.rce security_result.detection_fields[].key: "rce"
security_result.detection_fields[].value: waf.score.rce
Lógica semelhante à waf.score.http_violation.
waf.score.rfi security_result.detection_fields[].key: "rfi"
security_result.detection_fields[].value: waf.score.rfi
Lógica semelhante à waf.score.http_violation.
waf.score.session_fixation security_result.detection_fields[].key: "session_fixation"
security_result.detection_fields[].value: waf.score.session_fixation
Lógica semelhante à waf.score.http_violation.
waf.score.sql_injection security_result.detection_fields[].key: "sql_injection"
security_result.detection_fields[].value: waf.score.sql_injection
Lógica semelhante à waf.score.http_violation.
waf.score.xss security_result.detection_fields[].key: "xss"
security_result.detection_fields[].value: waf.score.xss
Lógica semelhante à waf.score.http_violation.
waf.severity security_result.severity: derivado
security_result.severity_details: waf.severity
Se waf.severity não estiver vazio, ele vai determinar o valor de security_result.severity com base nos intervalos (<=3: ALTO, >3 e <=6: MÉDIO, >6 e <=8: BAIXO, caso contrário: UNKNOWN_SEVERITY). O valor original de waf.severity também é mapeado para security_result.severity_details.
waf_message metadata.description: waf_message Se waf.message estiver vazio e waf_message não estiver, ele será associado a metadata.description. Se client_ip ou host e fastly.server não estiverem vazios, metadata.event_type será definido como "NETWORK_HTTP". Caso contrário, se client_ip ou host não estiverem vazios, metadata.event_type será definido como "STATUS_UPDATE". Caso contrário, ele será definido como "GENERIC_EVENT". Valor codificado. Valor codificado. Valor codificado.

Alterações

2022-06-06

  • Parser recém-criado.