É publicada uma vulnerabilidade crítica, o aviso espalha-se e, numa hora, alguém pergunta no chat da empresa: estamos afetados? O Log4Shell tornou a pergunta famosa. O CVE-2021-44228 afetou o Log4j Core desde a versão 2.0-beta9 até à 2.15.0, uma biblioteca que estava várias camadas abaixo na árvore de dependências de inúmeros produtos Java, e a maioria das equipas teve de descobrir da pior maneira onde ela estava.
A pergunta parece simples. Na verdade, são três perguntas:
- O componente vulnerável está em alguma coisa que compilamos ou distribuímos?
- Se estiver, pode ser explorado no nosso produto?
- Desde quando, e em que versões?
A maioria dos processos responde às duas primeiras. A terceira é a que clientes, auditores e reguladores colocam a seguir, e é a mais difícil de responder a posteriori.
Passo 1: descobrir se o componente está lá
As empresas chegam normalmente a uma resposta de uma de quatro formas, mais ou menos por ordem de maturidade.
Perguntar e pesquisar. Alguém publica no Slack, os engenheiros procuram o nome do pacote nos seus repositórios e lockfiles, e uma folha de cálculo reúne as respostas. Continua a ser o método mais comum. É lento, depende de quem responde e falha tudo o que não esteja declarado num ficheiro: dependências de dependências, bibliotecas incorporadas no repositório, imagens base, ferramentas instaladas durante o build.
Consultar os painéis dos scanners. Os scanners de dependências assinalam o CVE por repositório em poucas horas. É mais rápido, mas um scanner reporta sobre o código que tem à frente hoje, normalmente o branch predefinido. Não lhe diz que versões os seus clientes estão a executar, nem o que um build de há três meses realmente obteve.
Consultar um inventário de SBOM. As equipas que mantêm uma lista de materiais de software para cada versão podem fazer uma pergunta a todas elas: que produtos e versões contêm as versões afetadas deste pacote? É o primeiro método que responde pelo software que distribuiu, e não apenas pelo software que está no repositório.
Cruzar continuamente. Quando as SBOM são monitorizadas face aos dados de vulnerabilidades, a lista de produtos afetados existe antes de alguém perguntar. A conversa no chat começa com a resposta em vez da pergunta.
A qualidade de cada método depende do que o inventário realmente contém. Os pontos cegos habituais são:
- Dependências transitivas. O pacote vulnerável raramente é um que tenha adicionado. Entra três ou quatro níveis abaixo.
- Tudo o que o manifesto não declara. Pacotes instalados por scripts de build, ferramentas
npx, passos de Dockerfile, caches restauradas e código C e C++ incorporado no repositório. - Versões antigas. Um branch que já não compila não pode voltar a ser analisado, mas o produto compilado a partir dele pode continuar em uso.
Passo 2: decidir se é relevante
Um componente pode estar presente sem constituir um risco real, pelo que o passo seguinte é a triagem:
- Versão e configuração. A versão está exatamente dentro do intervalo afetado? A funcionalidade vulnerável está compilada e ativada?
- Alcançabilidade. O seu código chega a chamar a função vulnerável?
- Exposição. O componente é alcançável a partir da rede ou de entradas não fiáveis, ou é usado apenas durante o build?
- Mitigações. Existe sandboxing, uma restrição de rede ou uma configuração que bloqueie o exploit?
- Sinais de exploração. O CVSS indica a gravidade, o EPSS estima a probabilidade de um CVE ser explorado nos 30 dias seguintes e o catálogo Known Exploited Vulnerabilities da CISA enumera os que já são explorados na prática. Em conjunto, decidem o que é analisado primeiro.
Passo 3: registar a decisão
O resultado é registado por produto e versão, cada vez mais sob a forma de uma declaração VEX (Vulnerability Exploitability eXchange). Os requisitos mínimos para VEX da CISA definem quatro estados: not affected, affected, fixed e under investigation. Uma declaração not affected tem de indicar porquê, por exemplo porque o código vulnerável não está presente ou não pode ser alcançado por um atacante.
Esse registo alimenta tudo o que se segue: a correção e as versões que a incluem, o aviso de segurança para os clientes e qualquer relatório que um regulador espere. Ao abrigo do Cyber Resilience Act da UE, por exemplo, um fabricante tem de enviar um alerta precoce sobre uma vulnerabilidade ativamente explorada no seu produto no prazo de 24 horas após tomar conhecimento dela.
Passo 4: calcular a janela de exposição
"Estamos afetados?" tem uma segunda parte que é muitas vezes ignorada: durante quanto tempo estivemos afetados?
A vulnerabilidade existia muito antes de o CVE ser publicado. O Log4Shell estava no Log4j desde a versão 2.0-beta9, lançada anos antes de alguém o divulgar. A sua exposição começou no dia em que um build obteve pela primeira vez uma versão vulnerável e terminou no dia em que o último build que a continha foi substituído. Precisa dessa janela para:
- dizer aos clientes quais das versões que executam estão afetadas, e não apenas a mais recente
- delimitar a investigação de um incidente ao período certo, caso a vulnerabilidade possa ter sido explorada
- mostrar a um auditor ou regulador quando o problema entrou no produto e quando a correção foi distribuída
Analisar o código de hoje não lhe dá isso. O lockfile atual diz o que o repositório quer agora, e não o que cada build anterior instalou. A única fonte fiável é um registo de cada build, feito enquanto decorria e conservado depois.
Como o CRACI responde
O CRACI executa os seus jobs de GitHub Actions em runners próprios e regista cada pacote que cada build realmente obtém, direto e transitivo, incluindo pacotes instalados por scripts e restaurados de caches. A SBOM de cada build é conservada, pelo que o histórico já lá está quando um CVE é publicado.
Quando surge um novo CVE, a resposta já existe: todos os builds anteriores e as respetivas SBOM, quais deles continham a dependência vulnerável, direta ou transitiva, e o período em que esteve afetado. Sem folhas de cálculo, sem novas análises, sem reconstruções a partir de lockfiles. O primeiro build que a continha e o build que a removeu dão-lhe a janela de exposição, até onde chegar a sua retenção (180 dias por predefinição, retenção personalizada no plano Enterprise).
Depois de o saber, uma política de bloqueio pode impedir builds que contenham este CVE, para que uma atualização posterior de dependências ou uma cache restaurada não possa reintroduzir discretamente a versão vulnerável num lançamento.
A partir daí, o resto do processo tem uma base em que assentar:
- O CRACI monitoriza as SBOM continuamente, pelo que os novos CVE são cruzados com os seus builds sem que ninguém tenha de perguntar.
- As equipas de segurança fazem a triagem das conclusões e encaminham-nas para as equipas responsáveis pela correção, e o CRACI suporta VEX para registar o resultado.
- O inventário do CRACI mostra que versões de software estão implementadas em que produtos.
- Para o CRA, o CRACI submete o alerta precoce, a notificação e o relatório final em seu nome.
Marque uma demo para ver o histórico de builds de um dos seus repositórios.
