Métricas de tempo até a aplicação de patches: uma abordagem de análise de sobrevivência usando Qualys e Elastic
Introdução
Compreender a rapidez com que as vulnerabilidades são corrigidas em diferentes ambientes e equipes é fundamental para manter uma postura de segurança robusta. Neste artigo, descrevemos como aplicamos a análise de sobrevivência aos dados de gerenciamento de vulnerabilidades (VM) do Qualys VMDR, usando o Elastic Stack. Isso nos permitiu não apenas confirmar suposições gerais sobre a velocidade da equipe (a rapidez com que as equipes concluem o trabalho) e a capacidade de remediação (o quanto de correção elas conseguem realizar), mas também obter informações mensuráveis. Como a maior parte dos nossos dados de segurança está no Elastic Stack, esse processo deve ser facilmente reproduzível para outras fontes de dados de segurança.
Por que fizemos isso
Nossa principal motivação foi passar de suposições gerais para insights baseados em dados sobre:
- Com que rapidez diferentes equipes e ambientes corrigem vulnerabilidades?
- Verificar se o desempenho da aplicação de patches atende aos objetivos internos de nível de serviço (SLOs).
- Onde ocorrem com frequência gargalos ou atrasos
- Que outros fatores podem afetar o desempenho da aplicação de patches?
Por que a análise de sobrevivência? Uma alternativa melhor ao tempo médio de remediação
O Tempo Médio para Correção (MTTR, na sigla em inglês) é comumente usado para monitorar a rapidez com que as vulnerabilidades são corrigidas, mas tanto a média quanto a mediana sofrem de limitações significativas (forneceremos um exemplo mais adiante neste artigo). A média é altamente sensível a outliers[^1] e pressupõe que os tempos de remediação sejam distribuídos uniformemente em torno do tempo médio de remediação, o que raramente acontece na prática. A mediana é menos sensível a extremos, mas descarta informações sobre o formato da distribuição e não diz nada sobre a longa cauda de vulnerabilidades que demoram a ser corrigidas. Nenhuma das duas opções leva em consideração os casos não resolvidos, ou seja, as vulnerabilidades que permanecem em aberto além do período de observação, as quais são frequentemente excluídas por completo. Na prática, as vulnerabilidades que permanecem abertas por mais tempo são precisamente aquelas que mais nos devem preocupar.
A análise de sobrevivência aborda essas limitações. Originária de contextos médicos e atuariais, ela modela dados de tempo até o evento, incorporando explicitamente observações censuradas, ou seja, em nosso contexto, vulnerabilidades que permanecem em aberto. (Para obter mais detalhes sobre sua aplicação à gestão de vulnerabilidades, recomendamos fortemente a leitura de "O Manifesto das Métricas"). Em vez de condensar o comportamento de remediação em um único número, a análise de sobrevivência estima a probabilidade de uma vulnerabilidade permanecer sem correção ao longo do tempo (por exemplo, 90% das vulnerabilidades são corrigidas em até 30 dias). Isso permite avaliações mais significativas, como a proporção de vulnerabilidades corrigidas dentro do SLO (por exemplo, em 30, 90 ou 180 dias).
A análise de sobrevivência nos fornece uma função de sobrevivência que estima a probabilidade de uma vulnerabilidade permanecer sem correção ao longo do tempo.
::: Este método oferece uma visão mais abrangente do desempenho da remediação, permitindo-nos avaliar não apenas por quanto tempo as vulnerabilidades persistem, mas também como o comportamento da remediação difere entre sistemas, equipes ou níveis de gravidade. É particularmente adequado para dados de segurança, que muitas vezes são incompletos, distorcidos e resistentes a suposições de normalidade. :::
Contexto
Embora tenhamos aplicado a análise de sobrevivência em diferentes ambientes, equipes e organizações, neste blog nos concentraremos nos resultados para o ambiente de produção do Elastic Cloud.
Cálculo da idade de vulnerabilidade
Existem diferentes métodos para calcular a idade de vulnerabilidade.
Para nossas métricas internas, como o SLO de aderência à vulnerabilidade, definimos a idade da vulnerabilidade como a diferença entre quando uma vulnerabilidade foi encontrada pela última vez e quando foi detectada pela primeira vez (geralmente alguns dias após a publicação). Essa abordagem visa penalizar vulnerabilidades que são reintroduzidas a partir de uma imagem base desatualizada. No passado, nossas imagens base não eram atualizadas com frequência suficiente para nossa satisfação. Se uma nova instância for criada, as vulnerabilidades podem ter uma idade significativa (por exemplo, 100 dias) desde o primeiro dia da descoberta.
Para esta análise, consideramos mais relevante calcular a idade com base no número de dias entre a última data em que o animal foi encontrado e a primeira data em que foi encontrado. Neste caso, a idade representa o número de dias em que o sistema esteve efetivamente exposto.
Estratégia de "remendar tudo"
Em nosso ambiente de nuvem, mantemos uma política de atualização contínua de todas as atualizações. Isso ocorre porque usamos quase que exclusivamente a mesma imagem base em todas as instâncias. Como o Elastic Cloud opera totalmente em contêineres, não há pacotes de aplicativos específicos (por exemplo, Elasticsearch) instalados diretamente em nossos sistemas. Como resultado, nossa frota permanece homogênea.
Fluxo de dados
Ingerir e mapear dados no Elastic Stack pode ser um processo complicado. Felizmente, temos muitas integrações de segurança que lidam com isso nativamente, sendo o Qualys VMDR uma delas.
Esta integração tem 3 interesses principais em relação aos métodos de ingestão personalizados (por exemplo roteiros, batidas, …):
- Ele enriquece nativamente os dados de vulnerabilidade da Base de Conhecimento Qualys, adicionando IDs CVE, informações de inteligência de ameaças, etc., sem a necessidade de configurar pipelines de enriquecimento.
- Os dados do Qualys já estão mapeados para o Elastic Common Schema, que é uma forma padronizada de representar dados, independentemente da fonte: por exemplo, as CVEs são sempre armazenadas no campo vulnerability.id. independente da fonte.
- Uma transformação com a vulnerabilidade mais recente já está configurada. Este índice pode ser consultado para obter o status mais recente das vulnerabilidades.
Configuração de integração do agente Qualys
Para a análise de sobrevivência, precisamos considerar tanto as vulnerabilidades ativas quanto as corrigidas. Para analisar um período específico, precisamos definir o número de dias no campo max_days_since_detection_updated. Em nosso ambiente, ingerimos dados do Qualys diariamente, portanto não há necessidade de ingerir um longo histórico de dados fixos, pois já fizemos isso.
A integração do agente elástico Qualys VMDR foi configurada da seguinte forma:
| Propriedade | Value | Comentário |
|---|---|---|
| (Seção Configurações) Nome de usuário | ||
| (Seção Configurações) Senha | Como não há chaves de API disponíveis no Qualys, só podemos autenticar com Autenticação Básica. Certifique-se de que o SSO esteja desativado nesta conta. | |
| URL | https://qualysapi.qg2.apps.qualys.com (para US2) | https://www.qualys.com/platform-identification/ |
| Intervalo | 4h | Ajuste-o com base no número de eventos ingeridos. |
| Parâmetros de entrada | show_asset_id=1& include_vuln_type=confirmed&show_results=1&max_days_since_detection_updated=3&status=New,Active,Re-Opened,Fixed&filter_superseded_qids=1&use_tags=1&tag_set_by=name&tag_include_selector=all&tag_exclude_selector=any&tag_set_include=status:running&tag_set_exclude=status:terminated,status:stopped,status:stale&show_tags=1&show_cloud_tags=1 | show_asset_id=1: recupera o ID do recurso show_results=1: detalhes sobre o pacote instalado atualmente e qual versão deve ser instalada max_days_since_detection_updated=3: filtra quaisquer vulnerabilidades que não foram atualizadas nos últimos 3 dias (por exemplo (corrigido há mais de 3 dias) status=Novo,Ativo,Reaberto,Corrigido: todos os status de vulnerabilidade são considerados filter_superseded_qids=1: ignorar vulnerabilidades substituídas Tags: filtrar por tags show_tags=1: recuperar tags do Qualys show_cloud_tags=1: recuperar tags da nuvem |
Após a ingestão completa dos dados, eles podem ser revisados no Kibana Discover (visualização de dados logs-* -> data_stream.dataset : "qualys_vmdr.asset_host_detection" ) ou no aplicativo Kibana Security (Resultados -> Vulnerabilidades).
Carregando dados no Python com o cliente Elasticsearch
Como o cálculo da análise de sobrevivência será feito em Python, precisamos extrair os dados do Elasticsearch para um dataframe do Python. Existem diversas maneiras de alcançar esse objetivo, e neste artigo vamos nos concentrar em duas delas.
Com ES|QL
A maneira mais fácil e conveniente é utilizar o ES|QL com o formato de seta. Isso irá preencher automaticamente o dataframe do Python (linhas e colunas). Recomendamos a leitura da postagem do blog " De ES|QL para dataframes nativos do Pandas em Python" para obter mais detalhes.
from elasticsearch import Elasticsearch
import pandas as pd
client = Elasticsearch(
"https://[host].elastic-cloud.com",
api_key="...",
)
response = client.esql.query(
query="""
FROM logs-qualys_vmdr.asset_host_detection-default
| WHERE elastic.owner.team == "platform-security" AND elastic.environment == "production"
| WHERE qualys_vmdr.asset_host_detection.vulnerability.is_ignored == FALSE
| EVAL vulnerability_age = DATE_DIFF("day", qualys_vmdr.asset_host_detection.vulnerability.first_found_datetime, qualys_vmdr.asset_host_detection.vulnerability.last_found_datetime)
| STATS
mean=AVG(vulnerability_age),
median=MEDIAN(vulnerability_age)
""",
format="arrow",
)
df = response.to_pandas(types_mapper=pd.ArrowDtype)
print(df)
Atualmente, temos uma limitação com o ESQL: não podemos paginar os resultados. Portanto, estamos limitados a 10 mil documentos de saída (100 mil se a configuração do servidor for modificada). O progresso pode ser acompanhado por meio desta solicitação de melhoria.
Com DSL
No cliente Python do Elasticsearch, existe um recurso nativo para extrair todos os dados de uma consulta com paginação transparente. A parte desafiadora é criar a consulta DSL. Recomendamos criar a consulta no Discover e, em seguida, clicar em Inspect e depois na guia Request para obter a consulta DSL.
query = {
"track_total_hits": True,
"query": {
"bool": {
"filter": [
{
"match": {
"elastic.owner.team": "awesome-sre-team"
}
},
{
"match": {
"elastic.environment": "production"
}
},
{
"match": {
"qualys_vmdr.asset_host_detection.vulnerability.is_ignored": False
}
}
]
}
},
"fields": [
"@timestamp",
"qualys_vmdr.asset_host_detection.vulnerability.unique_vuln_id",
"qualys_vmdr.asset_host_detection.vulnerability.first_found_datetime",
"qualys_vmdr.asset_host_detection.vulnerability.last_found_datetime",
"elastic.vulnerability.age",
"qualys_vmdr.asset_host_detection.vulnerability.status",
"vulnerability.severity",
"qualys_vmdr.asset_host_detection.vulnerability.is_ignored"
],
"_source": False
}
results = list(scan(
client=es,
query=query,
scroll='30m',
index=source_index,
size=10000,
raise_on_error=True,
preserve_order=False,
clear_scroll=True
))
Análise de Sobrevivência
Você pode consultar o código para entendê-lo ou reproduzi-lo em seu conjunto de dados.
O que aprendemos
Com base na pesquisa do Instituto Cyentia, analisamos algumas maneiras diferentes de medir quanto tempo leva para remediar vulnerabilidades, usando médias, medianas e curvas de sobrevivência. Cada método oferece uma perspectiva diferente através da qual podemos entender os dados de tempo de correção, e a comparação é importante porque, dependendo do método utilizado, chegaríamos a conclusões muito diferentes sobre a eficácia da correção das vulnerabilidades.
O primeiro método foca apenas nas vulnerabilidades que já foram corrigidas. Calcula o tempo médio e mediano que levou para consertá-los. Isso é intuitivo e simples, mas deixa de fora uma parte potencialmente grande e importante dos dados (as vulnerabilidades que ainda estão em aberto). Consequentemente, tende a subestimar o tempo real necessário para a correção, especialmente se algumas vulnerabilidades permanecerem abertas por muito mais tempo do que outras.
O segundo método tenta incluir vulnerabilidades tanto fechadas quanto abertas, utilizando o tempo em que elas estiveram abertas até o momento. Existem muitas opções para estimar o tempo necessário para corrigir as vulnerabilidades conhecidas, mas, por simplicidade, aqui assumimos que elas já haviam sido (ou seriam?) corrigidas no momento da publicação deste relatório, o que sabemos que não é verdade. Mas oferece uma maneira de levar em consideração a existência deles.
O terceiro método utiliza análise de sobrevivência. Especificamente, utilizamos o estimador de Kaplan-Meier para modelar a probabilidade de uma vulnerabilidade ainda estar aberta em um determinado momento. Este método lida adequadamente com as vulnerabilidades abertas: em vez de fingir que foram corrigidas, ele as trata como dados "censurados". A curva de sobrevivência que ela produz diminui com o tempo, mostrando a proporção de vulnerabilidades que permanecem abertas à medida que os dias ou semanas passam.
Quanto tempo duram as vulnerabilidades?
No snapshot atual de 6 meses[^2], o tempo para patch apenas fechado tem uma mediana de ~33 dias e uma média de ~35 dias. À primeira vista, isso parece razoável, mas a curva de Kaplan-Meier mostra o que esses números escondem: em 33 dias, ~54% ainda estão abertos; em 35 dias, ~46% ainda estão abertos. Assim, mesmo por volta do período "típico" de um mês, cerca de metade dos problemas permanecem sem solução.
Também calculamos as estatísticas observadas até o momento (tratando as vulnerabilidades abertas como se tivessem sido corrigidas ao final do período de medição). Nesse período, eles acabam sendo quase iguais (mediana de aproximadamente 33 dias, média de aproximadamente 35 dias) porque a duração dos itens abertos de hoje se concentra em torno de um mês. Essa coincidência pode fazer com que as médias pareçam tranquilizadoras, mas é incidental e instável: se mudarmos a captura de tela para pouco antes do aumento mensal de desempenho, essas mesmas estatísticas caem drasticamente (observamos uma mediana de aproximadamente 19 dias e uma média de aproximadamente 15 dias) sem qualquer alteração no processo subjacente.
A curva de sobrevivência evita essa armadilha, porque responde à pergunta de "% ainda em aberto após 30/60/90 dias" e oferece visibilidade à longa cauda que permanece aberta bem depois de um mês.
Remendar tudo da mesma maneira em todo lugar?
A análise de sobrevivência estratificada leva a ideia de curvas de sobrevivência um passo adiante. Em vez de analisar todas as vulnerabilidades juntas em um grande conjunto, o modelo as separa em grupos (ou “estratos”) com base em alguma característica significativa. Em nossa análise, estratificamos as vulnerabilidades por gravidade, criticidade do ativo, ambiente, provedor de nuvem e equipe/divisão/organização. Cada grupo tem sua própria curva de sobrevivência, e aqui, no gráfico de exemplo, comparamos a rapidez com que diferentes níveis de vulnerabilidade são corrigidos ao longo do tempo.
A vantagem dessa abordagem é que ela expõe diferenças que, de outra forma, ficariam ocultas no agregado. Se analisarmos apenas a curva de sobrevivência geral, só poderemos tirar conclusões sobre o desempenho da remediação de forma generalizada. Mas a estratificação revela se diferentes equipes, ambientes ou problemas de gravidade são resolvidos mais rapidamente do que os demais e, no nosso caso, que a estratégia de corrigir tudo é de fato consistente. Esse nível de detalhamento é importante para fazer melhorias direcionadas, ajudando-nos a entender não apenas quanto tempo a correção leva em geral, mas também se e onde existem gargalos reais.
Quão rápido as equipes agem?
Embora a curva de sobrevivência enfatize por quanto tempo as vulnerabilidades permanecem abertas, podemos inverter a perspectiva usando a função de distribuição cumulativa (CDF). O CDF concentra-se na rapidez com que as vulnerabilidades são corrigidas, mostrando a proporção de vulnerabilidades que foram solucionadas em um determinado momento.
Nossa escolha de representar graficamente a CDF fornece uma visão clara da velocidade de correção; no entanto, é importante observar que esta versão inclui apenas as vulnerabilidades que foram corrigidas dentro do período de tempo observado. Ao contrário da curva de sobrevivência que calculamos em uma coorte móvel de 6 meses para capturar ciclos de vida completos, a CDF é calculada mês a mês em itens fechados naquele mês[^3].
Sendo assim, indica a rapidez com que as equipes corrigem as vulnerabilidades depois de identificá-las, e não reflete por quanto tempo as vulnerabilidades não resolvidas permanecem em aberto. Por exemplo, vemos que 83,2% das vulnerabilidades corrigidas no mês atual foram resolvidas em até 30 dias após a primeira detecção. Isso destaca a velocidade de aplicação de patches recentes e bem-sucedidos, mas não leva em consideração vulnerabilidades antigas que permanecem abertas e que provavelmente terão tempos de correção mais longos. Portanto, usamos a CDF para entender o comportamento de resposta a curto prazo, enquanto a dinâmica do ciclo de vida completo é dada por uma combinação da CDF com a análise de sobrevivência: a CDF descreve a rapidez com que as equipes agem após a aplicação de patches, enquanto a curva de sobrevivência mostra quanto tempo as vulnerabilidades realmente duram.
Diferença entre análise de sobrevivência e média/mediana
Espere, dissemos que a análise de sobrevivência é melhor para analisar o tempo até a correção, a fim de evitar o impacto de valores discrepantes. Mas, neste exemplo, a análise de média/mediana e a análise de sobrevivência fornecem resultados semelhantes. Qual é o valor agregado? O motivo é simples: não temos casos atípicos em nossos ambientes de produção, já que nosso processo de aplicação de patches é totalmente automatizado e eficaz.
Para demonstrar o impacto em dados heterogêneos, usaremos um exemplo desatualizado de um ambiente de não produção que não possui aplicação automática de patches.
Consulta ESQL:
FROM qualys_vmdr.vulnerability_6months
| WHERE elastic.environment == "my-outdated-non-production-environment"
| WHERE qualys_vmdr.asset_host_detection.vulnerability.is_ignored == FALSE
| EVAL vulnerability_age = DATE_DIFF("day", qualys_vmdr.asset_host_detection.vulnerability.first_found_datetime, qualys_vmdr.asset_host_detection.vulnerability.last_found_datetime)
| STATS
count=COUNT(*),
count_closed_only=COUNT(*) WHERE qualys_vmdr.asset_host_detection.vulnerability.status == "Fixed",
mean_observed_so_far=MEDIAN(vulnerability_age),
mean_closed_only=MEDIAN(vulnerability_age) WHERE qualys_vmdr.asset_host_detection.vulnerability.status == "Fixed",
median_observed_so_far=MEDIAN(vulnerability_age),
median_closed_only=MEDIAN(vulnerability_age) WHERE qualys_vmdr.asset_host_detection.vulnerability.status == "Fixed"
| Observado até o momento | Somente fechado | |
|---|---|---|
| Contagem | 833 | 322 |
| Significar | 178,7 (dias) | 163,8 (dias) |
| Mediana | 61 (dias) | 5 (dias) |
| Sobrevida mediana | 527 (dias) | N/D |
Neste exemplo, o uso da média e da mediana produz resultados muito diferentes. Escolher uma única métrica representativa pode ser desafiador e potencialmente enganoso. O gráfico de análise de sobrevivência representa com precisão nossa eficácia em lidar com as vulnerabilidades nesse ambiente.
Considerações finais
Os benefícios da utilização da análise de sobrevivência não advêm apenas de uma medição mais precisa, mas também das informações sobre a dinâmica do comportamento de formação de manchas, mostrando onde ocorrem gargalos, os fatores que afetam a velocidade de formação de manchas e se esta está alinhada com o nosso objetivo de sobrevivência. Do ponto de vista da integração técnica, a utilização da análise de sobrevivência como parte dos nossos fluxos de trabalho operacionais e relatórios pode ser alcançada com alterações mínimas na nossa configuração atual do Elastic Stack: a análise de sobrevivência pode ser executada na mesma frequência do nosso ciclo de aplicação de patches, com os resultados sendo enviados de volta para o Kibana para visualização. A principal vantagem é combinar nossas métricas operacionais existentes com a análise de sobrevivência para acompanhar tanto as tendências de longo prazo quanto o desempenho de curto prazo.
Olhando para o futuro, estamos experimentando novas métricas adicionais, como Taxa de Chegada, Taxa de Queima e Taxa de Escape , que nos permitem avançar para uma compreensão mais dinâmica de como as vulnerabilidades são realmente tratadas.
A Taxa de Chegada é a medida da rapidez com que novas vulnerabilidades entram no ambiente. Saber que cinquenta novas CVEs surgem a cada mês, por exemplo, nos indica o que esperar da carga de trabalho antes mesmo de começarmos a analisar as correções. Assim, a taxa de chegada é uma métrica que não informa necessariamente sobre o acúmulo de tarefas, mas sim sobre a pressão exercida sobre o sistema.
A taxa de redução (tendência) mostra a outra metade da equação: a rapidez com que as vulnerabilidades estão sendo corrigidas em relação à velocidade com que surgem.
A taxa de escape acrescenta mais uma dimensão ao focar nas vulnerabilidades que escapam dos pontos onde deveriam ter sido contidas. Em nosso contexto, uma "fuga" refere-se a CVEs que não recebem atualizações de segurança ou que excedem os limites de SLO. Uma alta taxa de escape não apenas demonstra que vulnerabilidades existem, mas também que o processo projetado para controlá-las está falhando, seja porque os ciclos de aplicação de patches são muito lentos, os processos de automação são deficientes ou os controles compensatórios não estão funcionando como deveriam.
Em conjunto, as métricas criam um panorama mais completo: a taxa de chegada indica a quantidade de novos riscos que estão sendo introduzidos; as tendências de redução mostram se estamos acompanhando essa pressão ou se estamos sendo sobrecarregados por ela; as taxas de escape revelam onde as vulnerabilidades persistem apesar dos controles planejados.
[1]:Um outlier em estatística é um ponto de dados que está muito longe da tendência central (ou longe do resto dos valores em um conjunto de dados). Por exemplo, se a maioria das vulnerabilidades forem corrigidas em 30 dias, mas uma levar 600 dias, esse caso de 600 dias é um valor atípico. Valores atípicos podem puxar as médias para cima ou para baixo de maneiras que não refletem a experiência "típica". No contexto de aplicação de patches, essas são as vulnerabilidades que demoram especialmente para serem corrigidas e que permanecem abertas por muito mais tempo do que o normal. Podem representar situações raras, mas importantes, como sistemas que não podem ser facilmente atualizados ou correções que exigem testes extensivos.
[2]: Nota: O conjunto de dados atual de 6 meses inclui todas as vulnerabilidades que permanecem abertas no final do período de observação (independentemente de há quanto tempo foram abertas/vistas pela primeira vez) e todas as vulnerabilidades que foram fechadas durante a janela de 6 meses. Apesar dessa abordagem de coorte mista, as curvas de sobrevivência de janelas de observação anteriores mostram tendências consistentes, particularmente na parte inicial da curva. O formato e a inclinação ao longo dos primeiros 30 a 60 dias mostraram-se notavelmente estáveis em diferentes momentos da análise, sugerindo que métricas como o tempo médio para a correção e o comportamento de remediação em estágio inicial não são artefatos do curto período de observação. Embora as estimativas de longo prazo (por exemplo) Embora o percentil 90 permaneça incompleto em análises mais curtas, as conclusões extraídas dessas coortes ainda refletem uma dinâmica de agrupamento persistente e confiável.
[3]: Mantivemos o CDF em uma cadência mensal para relatórios operacionais (produtividade e adesão ao SLO para o trabalho concluído durante o mês atual), enquanto o Kaplan-Meier usa uma janela de 6 meses para lidar adequadamente com a censura e expor o risco de cauda em toda a coorte mais ampla.
