Analisando SBOM para Vulnerabilidades na Cadeia de Suprimentos
Quando Usar
- Um novo requisito regulatório (EO 14028, EU CRA) exige análise de SBOM para entregas de software
- A equipe de segurança precisa avaliar o risco de terceiros, escaneando SBOMs fornecidos pelos fornecedores
- O pipeline de CI/CD requer verificações automatizadas de vulnerabilidades contra SBOMs gerados
- A resposta a incidentes precisa determinar se um CVE divulgado recentemente afeta o software implantado
- A equipe de compras necessita de avaliação de risco da cadeia de suprimentos para uma aquisição de software
Não usar para varredura de vulnerabilidades em tempo real de sistemas ativos; use ferramentas de varredura de contêineres (Trivy, Grype CLI) ou scanners de vulnerabilidade baseados em host (Nessus, Qualys).
Pré-requisitos
- Arquivo SBOM no formato CycloneDX JSON (v1.4+) ou SPDX JSON (v2.3+)
- Python 3.9+ com as bibliotecas requests, networkx e packaging instaladas
- Chave de API NVD (gratuita, em https://nvd.nist.gov/developers/request-an-api-key) para limites de taxa mais altos
- Acesso à rede para a API NVD (https://services.nvd.nist.gov/rest/json/cves/2.0)
- Opcionalmente: syft para geração de SBOM, grype para validação cruzada
Fluxo de Trabalho
Passo 1: Gerar SBOM (se não fornecido)
Use o syft para criar um SBOM a partir de uma imagem de contêiner ou diretório de projeto:
# Gerar CycloneDX JSON a partir de uma imagem de contêiner
syft alpine:latest -o cyclonedx-json > sbom-cyclonedx.json
# Gerar SPDX JSON a partir de um diretório de projeto
syft dir:/path/to/project -o spdx-json > sbom-spdx.json
# Gerar a partir de um contêiner em execução
syft docker:my-app-container -o cyclonedx-json > sbom.json
O Syft suporta mais de 30 ecossistemas de pacotes, incluindo npm, PyPI, Maven, Go modules, apt, apk e RPM. O SBOM gerado inclui nomes de pacotes, versões, licenças, identificadores CPE e referências PURL (Package URL).
Passo 2: Analisar SBOM e Extrair Componentes
Analise o SBOM para extrair todos os componentes de software com seus identificadores:
Estrutura CycloneDX JSON:
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"components": [
{
"type": "library",
"name": "lodash",
"version": "4.17.20",
"purl": "pkg:npm/[email protected]",
"cpe": "cpe:2.3:a:lodash:lodash:4.17.20:*:*:*:*:*:*:*",
"licenses": [{"license": {"id": "MIT"}}]
}
],
"dependencies": [
{"ref": "pkg:npm/[email protected]", "dependsOn": ["pkg:npm/[email protected]"]}
]
}
Estrutura SPDX JSON:
{
"spdxVersion": "SPDX-2.3",
"packages": [
{
"name": "lodash",
"versionInfo": "4.17.20",
"externalRefs": [
{"referenceType": "purl", "referenceLocator": "pkg:npm/[email protected]"},
{"referenceType": "cpe23Type", "referenceLocator": "cpe:2.3:a:lodash:lodash:4.17.20:*:*:*:*:*:*:*"}
],
"licenseConcluded": "MIT"
}
],
"relationships": [
{"spdxElementId": "SPDXRef-express", "relatedSpdxElement": "SPDXRef-lodash",
"relationshipType": "DEPENDS_ON"}
]
}
Passo 3: Correlacionar Componentes com o Banco de Dados de CVEs do NVD
Consulte a API NVD 2.0 para encontrar vulnerabilidades conhecidas para cada componente:
import requests
NVD_API = "https://services.nvd.nist.gov/rest/json/cves/2.0"
def search_cves_by_cpe(cpe_name, api_key=None):
params = {"cpeName": cpe_name, "resultsPerPage": 50}
headers = {"apiKey": api_key} if api_key else {}
resp = requests.get(NVD_API, params=params, headers=headers, timeout=30)
resp.raise_for_status()
return resp.json().get("vulnerabilities", [])
def search_cves_by_keyword(keyword, version=None, api_key=None):
params = {"keywordSearch": keyword, "resultsPerPage": 50}
headers = {"apiKey": api_key} if api_key else {}
resp = requests.get(NVD_API, params=params, headers=headers, timeout=30)
resp.raise_for_status()
return resp.json().get("vulnerabilities", [])
A API NVD suporta pesquisa por nome CPE (mais preciso), palavra-chave, ID do CVE e intervalos de datas. Limites de taxa: 5 solicitações/30 segundos sem chave de API, 50 solicitações/30 segundos com chave.
Passo 4: Construir Gráfico de Dependências e Identificar Riscos Transitivos
Construa um grafo direcionado de dependências para rastrear a propagação de vulnerabilidades:
import networkx as nx
def build_dependency_graph(sbom):
G = nx.DiGraph()
# Adiciona nós para cada componente
for comp in sbom["components"]:
G.add_node(comp["purl"], name=comp["name"], version=comp["version"])
# Adiciona arestas a partir de relacionamentos de dependência
for dep in sbom.get("dependencies", []):
for child in dep.get("dependsOn", []):
G.add_edge(dep["ref"], child)
return G
A análise de dependência transitiva identifica componentes que não são incluídos diretamente, mas são puxados por meio de cadeias de dependência. Uma vulnerabilidade em uma dependência transitiva profundamente aninhada (por exemplo, 4 níveis de profundidade) ainda representa risco, mas pode ser mais difícil de remediar.
Métricas-chave do grafo para avaliação de risco:
- Grau de entrada: Quantos componentes dependem deste (alto grau de entrada = alto raio de explosão)
- Caminho mais curto para a raiz: Distância do ponto de entrada do aplicativo (mais próximo = mais explorável)
- Centralidade de intermediação: Componentes que estão em muitos caminhos de dependência (risco de gargalo)
Passo 5: Calcular Pontuações de Risco
Agregue dados de vulnerabilidade em pontuações de risco para componentes e gerais:
Cálculo da Pontuação de Risco:
━━━━━━━━━━━━━━━━━━━━━━
Risco do Componente = max(pontuações CVSS de todos os CVEs que afetam o componente)
Risco Ponderado = Risco do Componente * Fator de Dependência
onde Fator de Dependência = 1,0 + (0,1 * grau_de_entrada)
(mais dependentes = maior impacto organizacional)
Risco Geral do SBOM = média ponderada de todos os riscos dos componentes
ponderado pela centralidade da dependência
Níveis de Risco:
CRÍTICO: CVSS >= 9,0 ou explorado conhecido (CISA KEV)
ALTO: CVSS >= 7,0
MÉDIO: CVSS >= 4,0
BAIXO: CVSS < 4,0
Passo 6: Validar Cruzadamente com Grype
Use o grype para escanear independentemente o SBOM e comparar os resultados:
# Escanear SBOM CycloneDX com grype
grype sbom:sbom-cyclonedx.json -o json > grype-results.json
# Escanear SBOM SPDX
grype sbom:sbom-spdx.json -o table
# Filtrar por gravidade
grype sbom:sbom-cyclonedx.json --only-fixed --fail-on critical
O Grype obtém dados de vulnerabilidade do NVD, GitHub Security Advisories, Alpine SecDB, Red Hat, Debian, Ubuntu, Amazon Linux e bancos de dados de segurança Oracle, fornecendo cobertura mais ampla do que apenas o NVD.
Passo 7: Gerar Relatório de Conformidade
Produza um relatório estruturado adequado para conformidade regulatória:
RELATÓRIO DE ANÁLISE DE VULNERABILIDADES DO SBOM
====================================
Arquivo SBOM: app-sbom-cyclonedx.json
Formato: CycloneDX v1.5
Data da Análise: 2026-03-19
Total de Componentes: 247
Total de Dependências: 1.842 (diretas: 34, transitivas: 213)
SUMÁRIO DE VULNERABILIDADES
Crítico: 3 componentes / 5 CVEs
Alto: 11 componentes / 18 CVEs
Médio: 27 componentes / 41 CVEs
Baixo: 8 componentes / 12 CVEs
DESCOBERTAS CRÍTICAS
1. [email protected]
CVE-2021-23337 (CVSS 7.2) - Injeção de Comando via template
CVE-2020-28500 (CVSS 5.3) - ReDoS em trimEnd
Dependentes: 14 componentes (alto raio de explosão)
Correção: Atualizar para 4.17.21+
2. [email protected]
CVE-2021-44228 (CVSS 10.0) - Log4Shell RCE [CISA KEV]
CVE-2021-45046 (CVSS 9.0) - Bypass de correção incompleta
Dependentes: 8 componentes
Correção: Atualizar para 2.17.1+
RISCOS DO GRÁFICO DE DEPENDÊNCIAS
Mais dependente: [email protected] (47 dependentes)
Cadeia mais profunda: app -> framework -> adapter -> codec -> zlib (5 níveis)
Componentes gargalo: 3 componentes em >50% dos caminhos de dependência
CONFORMIDADE DE LICENÇA
Licenças copyleft encontradas: 2 (GPL-3.0 em libxml2, AGPL-3.0 em mongodb-driver)
Revisão necessária para distribuição comercial
Conceitos Chave
| Termo | Definição |
|---|---|
| SBOM | Lista de Materiais de Software; um inventário formal de todos os componentes, bibliotecas e dependências em um produto de software |
| CycloneDX | Padrão SBOM mantido pela OWASP com suporte aos formatos JSON, XML e protobuf, incluindo gráfico de dependências e dados de vulnerabilidade |
| SPDX | Padrão SBOM da Linux Foundation focado em conformidade de licença com suporte a detalhes em nível de pacote, arquivo e trecho |
| PURL | Package URL; um esquema padronizado para identificar pacotes de software em diferentes ecossistemas (ex.: pkg:npm/[email protected]) |
| CPE | Common Platform Enumeration; esquema de nomenclatura do NIST para produtos de TI usado para correlacionar com dados de CVE do NVD |
| NVD | National Vulnerability Database; repositório governamental dos EUA de dados de vulnerabilidade indexados por identificadores CVE |
| Dependência Transitiva | Uma dependência não declarada diretamente, mas puxada através da cadeia de dependências das dependências diretas |
| CISA KEV | Catálogo de Vulnerabilidades Conhecidas Exploradas da CISA; CVEs confirmados como sendo ativamente explorados na natureza |
Ferramentas e Sistemas
- syft (Anchore): Gerador de SBOM de código aberto com suporte a mais de 30 ecossistemas de pacotes e saída CycloneDX/SPDX
- grype (Anchore): Scanner de vulnerabilidade que aceita SBOMs como entrada e correlaciona com vários bancos de dados de avisos
- cyclonedx-python-lib: Biblioteca Python para criar, analisar e validar SBOMs CycloneDX programaticamente
- lib4sbom: Biblioteca Python para analisar SBOMs nos formatos SPDX e CycloneDX
- nvdlib: Wrapper Python para a API NVD 2.0 com suporte a consultas de CVE e CPE e gerenciamento de limite de taxa
- OWASP Dependency-Track: Plataforma para análise contínua de SBOM, rastreamento de vulnerabilidades e aplicação de políticas
Cenários Comuns
Cenário: Avaliando Software de Fornecedor Após a Divulgação do Log4Shell
Contexto: Após a divulgação do Log4Shell (CVE-2021-44228), a equipe de segurança precisa determinar quais aplicativos fornecidos por fornecedores contêm versões vulneráveis do log4j. Vários fornecedores forneceram SBOMs conforme requisitos contratuais.
Abordagem:
- Coletar todos os SBOMs dos fornecedores (formato CycloneDX ou SPDX JSON)
- Analisar cada SBOM e pesquisar por componentes log4j-core com versões < 2.17.1
- Consultar a API NVD para os CVEs específicos (CVE-2021-44228, CVE-2021-45046, CVE-2021-45105)
- Construir gráficos de dependência para identificar quais componentes do aplicativo dependem do log4j
- Calcular o raio de explosão: quantos serviços e endpoints estão expostos
- Gerar relatório de remediação priorizado, classificado por exposição e criticidade de negócios
- Validar cruzadamente as descobertas com uma varredura grype dos mesmos SBOMs
Armadilhas:
- SBOMs de fornecedores podem estar incompletos, faltando arquivos JAR sombreados/agrupados que incorporam log4j
- Diferenças de versão entre SPDX e CycloneDX podem afetar a compatibilidade do analisador
- Os limites de taxa da API NVD podem atrasar a análise ao escanear centenas de componentes sem uma chave de API
- Os nomes CPE nos SBOMs podem não corresponder exatamente às entradas do NVD, exigindo correspondência difusa
- Dependências transitivas podem incluir log4j mesmo quando não é uma dependência direta