Análisis de SBOM para Vulnerabilidades en la Cadena de Suministro
Cuándo Usarlo
- Un nuevo requisito regulatorio (EO 14028, EU CRA) exige el análisis de SBOM para entregas de software
- El equipo de seguridad necesita evaluar el riesgo de terceros escaneando SBOMs proporcionados por proveedores
- La tubería CI/CD requiere verificaciones automatizadas de vulnerabilidades contra SBOMs generados
- La respuesta a incidentes necesita determinar si un CVE recién divulgado afecta al software implementado
- El equipo de adquisiciones requiere una evaluación de riesgo de la cadena de suministro para una compra de software
No usar para escaneo de vulnerabilidades en tiempo real de sistemas en vivo; usar herramientas de escaneo de contenedores (Trivy, Grype CLI) o escáneres de vulnerabilidades basados en host (Nessus, Qualys) en su lugar.
Prerrequisitos
- Archivo SBOM en formato CycloneDX JSON (v1.4+) o SPDX JSON (v2.3+)
- Python 3.9+ con las bibliotecas requests, networkx y packaging instaladas
- Clave API de NVD (gratuita, de https://nvd.nist.gov/developers/request-an-api-key) para límites de tasa más altos
- Acceso de red a la API de NVD (https://services.nvd.nist.gov/rest/json/cves/2.0)
- Opcionalmente: syft para generación de SBOM, grype para validación cruzada
Flujo de Trabajo
Paso 1: Generar SBOM (si no se proporciona)
Use syft para crear un SBOM a partir de una imagen de contenedor o directorio de proyecto:
# Generar CycloneDX JSON a partir de una imagen de contenedor
syft alpine:latest -o cyclonedx-json > sbom-cyclonedx.json
# Generar SPDX JSON a partir de un directorio de proyecto
syft dir:/path/to/project -o spdx-json > sbom-spdx.json
# Generar desde un contenedor en ejecución
syft docker:my-app-container -o cyclonedx-json > sbom.json
Syft admite más de 30 ecosistemas de paquetes, incluidos npm, PyPI, Maven, módulos Go, apt, apk y RPM. El SBOM generado incluye nombres de paquetes, versiones, licencias, identificadores CPE y referencias PURL (URL de paquete).
Paso 2: Analizar SBOM y Extraer Componentes
Analice el SBOM para extraer todos los componentes de software con sus identificadores:
Estructura JSON CycloneDX:
{
"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]"]}
]
}
Estructura JSON SPDX:
{
"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"}
]
}
Paso 3: Correlacionar Componentes con la Base de Datos NVD CVE
Consulte la API 2.0 de NVD para encontrar vulnerabilidades conocidas 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", [])
La API de NVD admite búsqueda por nombre CPE (más preciso), palabra clave, ID de CVE y rangos de fechas. Límites de tasa: 5 solicitudes/30 segundos sin clave API, 50 solicitudes/30 segundos con clave.
Paso 4: Construir Grafo de Dependencias e Identificar Riesgos Transitivos
Construya un grafo dirigido de dependencias para rastrear la propagación de vulnerabilidades:
import networkx as nx
def build_dependency_graph(sbom):
G = nx.DiGraph()
# Añadir nodos para cada componente
for comp in sbom["components"]:
G.add_node(comp["purl"], name=comp["name"], version=comp["version"])
# Añadir aristas desde las relaciones de dependencia
for dep in sbom.get("dependencies", []):
for child in dep.get("dependsOn", []):
G.add_edge(dep["ref"], child)
return G
El análisis de dependencias transitivas identifica componentes que no están incluidos directamente pero se incorporan a través de cadenas de dependencias. Una vulnerabilidad en una dependencia transitiva profundamente anidada (por ejemplo, 4 niveles de profundidad) sigue representando riesgo, pero puede ser más difícil de remediar.
Métricas clave del grafo para la evaluación de riesgos:
- Grado de entrada: Cuántos componentes dependen de este (grado de entrada alto = radio de explosión alto)
- Camino más corto a la raíz: Distancia desde el punto de entrada de la aplicación (más cerca = más explotable)
- Centralidad de intermediación: Componentes que se encuentran en muchos caminos de dependencia (riesgo de cuello de botella)
Paso 5: Calcular Puntuaciones de Riesgo
Agregue datos de vulnerabilidad en puntuaciones de riesgo de componente y general:
Cálculo de Puntuación de Riesgo:
━━━━━━━━━━━━━━━━━━━━━━
Riesgo del Componente = max(puntuaciones CVSS de todos los CVE que afectan al componente)
Riesgo Ponderado = Riesgo del Componente * Factor de Dependencia
donde Factor de Dependencia = 1.0 + (0.1 * grado de entrada)
(más dependientes = mayor impacto organizacional)
Riesgo General del SBOM = promedio ponderado de todos los riesgos de componentes
ponderado por centralidad de dependencia
Niveles de Riesgo:
CRÍTICO: CVSS >= 9.0 o explotado conocido (CISA KEV)
ALTO: CVSS >= 7.0
MEDIO: CVSS >= 4.0
BAJO: CVSS < 4.0
Paso 6: Validación Cruzada con Grype
Use grype para escanear de forma independiente el SBOM y comparar los hallazgos:
# Escanear SBOM CycloneDX con grype
grype sbom:sbom-cyclonedx.json -o json > grype-results.json
# Escanear SBOM SPDX
grype sbom:sbom-spdx.json -o table
# Filtrar por severidad
grype sbom:sbom-cyclonedx.json --only-fixed --fail-on critical
Grype obtiene datos de vulnerabilidad de NVD, GitHub Security Advisories, Alpine SecDB, Red Hat, Debian, Ubuntu, Amazon Linux y bases de datos de seguridad de Oracle, proporcionando una cobertura más amplia que solo NVD.
Paso 7: Generar Informe de Cumplimiento
Produzca un informe estructurado adecuado para el cumplimiento regulatorio:
INFORME DE ANÁLISIS DE VULNERABILIDADES DEL SBOM
==================================================
Archivo SBOM: app-sbom-cyclonedx.json
Formato: CycloneDX v1.5
Fecha de Análisis: 2026-03-19
Total de Componentes: 247
Total de Dependencias: 1,842 (directas: 34, transitivas: 213)
RESUMEN DE VULNERABILIDADES
Crítico: 3 componentes / 5 CVEs
Alto: 11 componentes / 18 CVEs
Medio: 27 componentes / 41 CVEs
Bajo: 8 componentes / 12 CVEs
HALLAZGOS CRÍTICOS
1. [email protected]
CVE-2021-23337 (CVSS 7.2) - Inyección de comandos mediante plantillas
CVE-2020-28500 (CVSS 5.3) - ReDoS en trimEnd
Dependientes: 14 componentes (alto radio de explosión)
Solución: Actualizar a 4.17.21+
2. [email protected]
CVE-2021-44228 (CVSS 10.0) - Log4Shell RCE [CISA KEV]
CVE-2021-45046 (CVSS 9.0) - Bypass de corrección incompleta
Dependientes: 8 componentes
Solución: Actualizar a 2.17.1+
RIESGOS DEL GRAFO DE DEPENDENCIAS
Más dependido: [email protected] (47 dependientes)
Cadena más profunda: app -> framework -> adapter -> codec -> zlib (5 niveles)
Componentes cuello de botella: 3 componentes en >50% de las rutas de dependencia
CUMPLIMIENTO DE LICENCIAS
Licencias copyleft encontradas: 2 (GPL-3.0 en libxml2, AGPL-3.0 en mongodb-driver)
Se requiere revisión para distribución comercial
Conceptos Clave
| Término | Definición |
|---|---|
| SBOM | Lista de Materiales de Software; un inventario formal de todos los componentes, bibliotecas y dependencias en un producto de software |
| CycloneDX | Estándar SBOM mantenido por OWASP que admite formatos JSON, XML y protobuf con grafo de dependencias y datos de vulnerabilidad |
| SPDX | Estándar SBOM de la Linux Foundation centrado en el cumplimiento de licencias con soporte para detalles a nivel de paquete, archivo y fragmento |
| PURL | URL de Paquete; un esquema estandarizado para identificar paquetes de software en diferentes ecosistemas (p.ej., pkg:npm/[email protected]) |
| CPE | Enumeración de Plataformas Comunes; esquema de nomenclatura de NIST para productos TI utilizado para correlacionar con datos CVE de NVD |
| NVD | Base de Datos Nacional de Vulnerabilidades; repositorio del gobierno de EE. UU. de datos de vulnerabilidad indexados por identificadores CVE |
| Dependencia Transitiva | Una dependencia no declarada directamente pero incorporada a través de la cadena de dependencias de dependencias directas |
| CISA KEV | Catálogo de Vulnerabilidades Explotadas Conocidas de CISA; CVEs confirmados como explotados activamente en la naturaleza |
Herramientas y Sistemas
- syft (Anchore): Generador de SBOM de código abierto que admite más de 30 ecosistemas de paquetes y salida CycloneDX/SPDX
- grype (Anchore): Escáner de vulnerabilidades que acepta SBOM como entrada y correlaciona contra múltiples bases de datos de avisos
- cyclonedx-python-lib: Biblioteca Python para crear, analizar y validar SBOM CycloneDX mediante programación
- lib4sbom: Biblioteca Python para analizar SBOM en formatos SPDX y CycloneDX
- nvdlib: Envoltorio Python para la API 2.0 de NVD que admite consultas de CVE y CPE con gestión de límites de tasa
- OWASP Dependency-Track: Plataforma para análisis continuo de SBOM, seguimiento de vulnerabilidades y aplicación de políticas
Escenarios Comunes
Escenario: Evaluación de Software de Proveedores Después de la Divulgación de Log4Shell
Contexto: Después de la divulgación de Log4Shell (CVE-2021-44228), el equipo de seguridad necesita determinar qué aplicaciones suministradas por proveedores contienen versiones vulnerables de log4j. Varios proveedores han proporcionado SBOM según los requisitos contractuales.
Enfoque:
- Recopilar todos los SBOM de los proveedores (formato JSON CycloneDX o SPDX)
- Analizar cada SBOM y buscar componentes log4j-core con versiones < 2.17.1
- Consultar la API de NVD para los CVEs específicos (CVE-2021-44228, CVE-2021-45046, CVE-2021-45105)
- Construir grafos de dependencias para identificar qué componentes de la aplicación dependen de log4j
- Calcular el radio de explosión: cuántos servicios y puntos finales están expuestos
- Generar un informe de remediación priorizado ordenado por exposición y criticidad del negocio
- Validar cruzadamente los hallazgos con un escaneo de grype de los mismos SBOM
Errores comunes:
- Los SBOM de proveedores pueden estar incompletos, faltando archivos JAR sombreados/empaquetados que incrustan log4j
- Las diferencias de versión entre SPDX y CycloneDX pueden afectar la compatibilidad del analizador
- Los límites de tasa de la API de NVD pueden ralentizar el análisis al escanear cientos de componentes sin una clave API
- Los nombres CPE en los SBOM pueden no coincidir exactamente con las entradas de NVD, requiriendo coincidencia difusa
- Las dependencias transitivas pueden incluir log4j incluso cuando no es una dependencia directa