Aller au contenu
Sécurité medium

SBOM : comprendre le Software Bill of Materials

24 min de lecture

« Est-ce qu’on utilise ce composant ? » — Combien de fois ai-je entendu cette question en urgence, après l’annonce d’une CVE critique ? À chaque incident supply chain, c’est la même course : fouiller les package.json, les requirements.txt, les images Docker… sans jamais être certain d’avoir tout couvert.

Le SBOM (Software Bill of Materials) répond à ce problème. C’est un inventaire exhaustif et machine-readable de tout ce qui compose un logiciel : bibliothèques, paquets OS, dépendances transitives, versions, licences. En clair : si on ne sait pas ce qu’on exécute, on ne peut ni corriger vite, ni prouver ce qu’on livre.

Dans ce guide, je montre concrètement :

  • C’est quoi un SBOM ?
  • Comment générer un SBOM avec Syft (Anchore)
  • Comment l’exploiter pour détecter des vulnérabilités avec Grype, Trivy, Dependency Track
  • Comment le distribuer (fichier, artefact CI, attestation OCI signée)
  • Comment l’intégrer en CI/CD pour automatiser tout ça
Cycle de vie du SBOM : Générer, Distribuer, Scanner, Réagir
Les 4 étapes du cycle de vie d’un SBOM

Un SBOM, c’est un document qui décrit :

  • Les composants (nom, version, fournisseur/éditeur quand possible)
  • Des identifiants stables (ex. purl, parfois CPE)
  • Les relations (dépendances directes/transitives)
  • Des métadonnées utiles (licences, hashes, emplacements, type de composant…)

L’objectif n’est pas « faire un fichier pour la conformité ». L’objectif est d’avoir un SBOM actionnable : chercher, corréler, prouver, automatiser.

  • Ce n’est pas un scan de vulnérabilités.
  • Ce n’est pas une preuve d’intégrité (ça, c’est la signature/attestation).
  • Ce n’est pas une garantie d’exploitabilité (ça, c’est plutôt le rôle d’un VEX).

Quand une CVE critique tombe (Log4Shell, XZ Utils, Polyfill.io…), la première question est toujours la même : « Est-ce qu’on est impactés ? ». Sans inventaire centralisé, on doit :

  • fouiller manuellement chaque package.json, requirements.txt, go.mod
  • scanner toutes mes images Docker une par une
  • interroger chaque équipe pour savoir ce qu’elle utilise
  • espérer n’avoir rien oublié

Résultat : des heures (voire des jours) perdues à chercher, pendant que la vulnérabilité reste exploitable.

Une attaque supply chain cible la chaîne d’approvisionnement logicielle : dépendances, outils de build, registres de paquets, pipelines CI/CD. L’attaquant comprommet un composant en amont pour toucher tous les projets qui en dépendent.

Pour comprendre les vecteurs d’attaque et les exemples récents (XZ Utils, Polyfill.io, tj-actions…), consulte mon guide complet sur la sécurité de la supply chain. Pour évaluer la posture sécurité d’un projet avant de l’adopter, utilise OpenSSF Scorecard.

Le point commun de ces incidents : sans inventaire fiable, on passe son temps à répondre à « est-ce qu’on est touchés ? » au lieu de corriger.

Avec un SBOM par artefact, on peut en quelques secondes :

Fenêtre de terminal
# Rechercher un composant vulnérable dans tous mes SBOM
grep -l "xz-utils" *.sbom.json

Le SBOM transforme donc une question floue (« on utilise quoi ? ») en une requête précise sur des données structurées.

Deux formats dominent l’écosystème SBOM. Chacun a son histoire, ses forces et son écosystème d’outils. Comprendre leurs différences permet de choisir le bon format selon le contexte.

CycloneDX est un standard développé par l’OWASP (Open Web Application Security Project), conçu dès le départ pour la sécurité applicative et la supply chain logicielle.

Versions et évolution :

  • CycloneDX 1.4 (2022) : ajout du support VEX (Vulnerability Exploitability eXchange) pour qualifier l’exploitabilité des vulnérabilités
  • CycloneDX 1.5 (2023) : support des attestations de formulation (build environment, sources, configurations)
  • CycloneDX 1.6 (2024) : amélioration du support cryptographique (CBOM) et des services (SaaSBOM)

Points forts :

  • Orienté sécurité : intégration native de VEX, hashes, signatures
  • Écosystème DevSecOps : support natif dans Trivy, Grype, Dependency Track, Snyk, GitHub
  • Léger et pragmatique : schéma JSON/XML simple, facile à parser
  • Évolution rapide : nouvelles fonctionnalités tous les 6-12 mois

Formats de sortie : JSON, XML, Protocol Buffers

Fenêtre de terminal
# Générer un SBOM CycloneDX 1.5 avec Syft
syft mon-image:latest -o cyclonedx-json@1.5 > sbom.cdx.json

SPDX (Software Package Data Exchange) est un standard de la Linux Foundation, devenu norme ISO/IEC 5962:2021. Il est historiquement très fort sur la conformité des licences et la traçabilité juridique.

Versions et évolution :

  • SPDX 2.2 (2020) : version largement adoptée, base de la norme ISO
  • SPDX 2.3 (2022) : ajout d’annotations, relations enrichies, meilleur support des conteneurs
  • SPDX 3.0 (2024) : refonte majeure avec profils modulaires (Core, Software, Security, Licensing, Build, AI/ML), support natif de VEX et des attestations

Points forts :

  • Standard ISO : reconnu internationalement, requis par certains gouvernements et industries réglementées
  • Licences exhaustives : liste SPDX des identifiants de licences (MIT, Apache-2.0, GPL-3.0…) utilisée universellement
  • Provenance détaillée : traçabilité complète de l’origine des composants
  • SPDX 3.0 : rattrape CycloneDX sur la sécurité avec les profils Security et Build

Formats de sortie : JSON, RDF/XML, Tag-Value (texte plat), YAML

Fenêtre de terminal
# Générer un SBOM SPDX 2.3 avec Syft
syft mon-image:latest -o spdx-json@2.3 > sbom.spdx.json
Comparaison CycloneDX vs SPDX
CycloneDX (sécurité) vs SPDX (conformité ISO) : deux standards complémentaires
CritèreCycloneDXSPDX
OrganismeOWASPLinux Foundation / ISO
Version actuelle1.6 (2024)3.0 (2024)
Focus principalSécurité, supply chainLicences, conformité
Support VEXNatif depuis 1.4Natif depuis 3.0
Norme ISONonOui (ISO/IEC 5962)
Adoption DevSecOpsTrès largeEn croissance
ComplexitéSimplePlus verbeux

En pratique, le choix dépend du contexte :

  • Sécurité et DevSecOps : CycloneDX est souvent plus « plug-and-play » avec les outils de scan (Trivy, Grype, Snyk, Dependency Track)
  • Conformité réglementaire : SPDX est requis par certains secteurs (défense, automobile, médical) et reconnu ISO
  • Licences open source : SPDX reste la référence pour l’audit de licences
  • Gouvernement US : les deux formats sont acceptés par la CISA et le NIST

Ma recommandation : génèrez les deux formats quand c’est possible. Syft et Trivy le font facilement, ce qui permet de répondre à tous les consommateurs (équipes sécurité, juridique, clients, autorités).

Fenêtre de terminal
# Générer les deux formats en une seule commande
syft mon-image:latest -o cyclonedx-json > sbom.cdx.json
syft mon-image:latest -o spdx-json > sbom.spdx.json

Plusieurs outils permettent de générer des SBOM. Voici les principaux que j’utilise en production :

OutilÉditeurPoints fortsFormats
SyftAnchoreImages conteneur, archives, filesystem. Très rapideCycloneDX, SPDX
TrivyAqua SecurityScanner de vulnérabilités + génération SBOM intégréeCycloneDX, SPDX
cdxgenOWASP/CycloneDXOfficiel CycloneDX, excellent support multi-langagesCycloneDX
spdx-sbom-generatorSPDX ProjectOfficiel SPDX, focus conformité licencesSPDX
Fenêtre de terminal
# Syft : image conteneur vers CycloneDX et SPDX
syft nginx:latest -o cyclonedx-json > sbom.cdx.json
syft nginx:latest -o spdx-json > sbom.spdx.json
# Trivy : génération SBOM intégrée
trivy image --format cyclonedx nginx:latest > sbom.cdx.json
# cdxgen : projet source multi-langages
cdxgen -o sbom.json ./mon-projet

Une fois le SBOM généré, ces outils permettent de l’exploiter :

OutilFonctionGuide
GrypeScan de vulnérabilités sur SBOM existantGuide Grype
TrivyScan multi-cibles (SBOM, images, IaC, secrets)Guide Trivy
Dependency-TrackPlateforme de gestion continue des SBOMGuide Dependency-Track
Fenêtre de terminal
# Grype : scanner un SBOM existant
grype sbom:./sbom.cdx.json
# Gate CI : échouer si vulnérabilité high+ avec correctif disponible
grype sbom:./sbom.cdx.json --only-fixed --fail-on high

Générer un SBOM ne suffit pas. Un SBOM qui reste sur le poste du développeur ou dans un artefact CI oublié ne sert à rien le jour où une CVE critique tombe.

Pour qu’un SBOM soit utile, il doit être :

  • Accessible : les équipes sécurité, les clients, les auditeurs doivent pouvoir le récupérer sans demander à personne
  • Associé à l’artefact : savoir quel SBOM correspond à quelle version déployée (sinon, c’est le chaos)
  • Vérifiable : garantir que le SBOM n’a pas été modifié après sa génération

Sans distribution structurée, on se retrouve à chercher « c’est où le SBOM de la version 2.3.1 en prod ? » pendant qu’une vulnérabilité est activement exploitée.

StratégieAvantagesInconvénients
Fichier à côté (CI, S3, release)Simple à mettre en placeDissocié de l’image, risque de désynchronisation
SBOM attaché OCICo-localisé avec l’image, même registryNécessite des outils compatibles OCI
Attestation signéeIntégrité garantie, traçabilité cryptographiqueSetup plus complexe (clés, Sigstore)
Les 3 stratégies de distribution SBOM
De la plus simple (fichier CI) à la plus robuste (attestation signée)

Ma recommandation : démarrez avec un fichier artefact CI pour avoir quelque chose rapidement, puis évoluez vers OCI attach + attestation signée dès que votre pipeline est stable.

L’attachement OCI place le SBOM dans la même registry que l’image, avec une référence liée. Quand on pull l’image, on peut récupérer son SBOM sans chercher ailleurs. Pour maîtriser Cosign, consulte mon guide sur la signature d’images conteneur.

Fenêtre de terminal
# Générer un SBOM (ex: SPDX)
syft packages mon-registry/mon-image:1.0.0 -o spdx > sbom.spdx
# Attacher le SBOM à l'image dans la registry
cosign attach sbom --sbom sbom.spdx mon-registry/mon-image:1.0.0
# Vérifier que le SBOM est bien attaché
cosign download sbom mon-registry/mon-image:1.0.0

L’attestation va plus loin : elle signe cryptographiquement le SBOM et l’associe à l’image. Impossible de le modifier sans casser la signature.

Fenêtre de terminal
# Attestation CycloneDX JSON (keyless via **Sigstore**/**OIDC**)
syft attest --output cyclonedx-json mon-registry/mon-image:1.0.0
# Vérifier l'attestation
cosign verify-attestation mon-registry/mon-image:1.0.0

Pourquoi cette approche plutôt qu’un simple fichier ?

Section intitulée « Pourquoi cette approche plutôt qu’un simple fichier ? »

Parce qu’on crée un graphe d’artefacts vérifiable autour de l’image : SBOM, signatures, provenance SLSA… tout est au même endroit, lié cryptographiquement. Le jour où un client demande « prouvez-moi ce que contient cette image », on a une réponse immédiate et vérifiable.

Réagir vite à une CVE : rechercher dans les SBOM

Section intitulée « Réagir vite à une CVE : rechercher dans les SBOM »

Vendredi 17h, une CVE critique tombe sur un composant très répandu. Mon manager me demande : « On est impactés ? Combien de systèmes ? C’est quoi la priorité ? ». Sans SBOM, je passe mon week-end à fouiller des package-lock.json et des images Docker. Avec des SBOM centralisés, j’ai ma réponse en quelques minutes.

La première question est : quels projets/images utilisent ce composant ?

Fenêtre de terminal
# Rechercher un composant dans tous mes SBOM CycloneDX
for sbom in *.cdx.json; do
if jq -e '.components[] | select(.name=="log4j-core")' "$sbom" > /dev/null 2>&1; then
echo "⚠️ $sbom contient log4j-core"
fi
done

Pour une recherche plus précise avec la version :

Fenêtre de terminal
# Trouver les versions exactes de log4j-core dans chaque SBOM
for sbom in *.cdx.json; do
jq -r --arg file "$sbom" '
.components[]
| select(.name=="log4j-core")
| "\($file): \(.name) \(.version)"
' "$sbom" 2>/dev/null
done

Étape 2 : vérifier si la version est vulnérable

Section intitulée « Étape 2 : vérifier si la version est vulnérable »

Une fois les artefacts identifiés, vérifiez si leurs versions sont dans la plage vulnérable. Pour Log4Shell (CVE-2021-44228), les versions 2.0-beta9 à 2.14.1 étaient impactées.

Fenêtre de terminal
# Extraire composant + version + purl pour corrélation
jq -r '
.components[]
| select(.name=="log4j-core")
| "\(.name) \(.version) \(.purl // "no-purl")"
' mon-app.cdx.json
# Résultat exemple :
# log4j-core 2.14.1 pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1

Le purl (Package URL) est particulièrement utile : il permet une corrélation directe avec les bases de vulnérabilités (OSV, NVD, GitHub Advisory).

Tous les artefacts impactés ne sont pas égaux. On priorise selon les critères décrits dans mon guide CVE, CVSS et EPSS :

CritèrePriorité hautePriorité basse
ExpositionProd exposée InternetEnv de dev interne
Criticité métierService critique 24/7Batch mensuel
ExploitabilitéCVE avec exploit publicCVE théorique
Effort de correctionBump de version simpleRefactoring majeur
Fenêtre de terminal
# Exemple : lister les images de prod contenant le composant vulnérable
for sbom in prod-*.cdx.json; do
if jq -e '.components[] | select(.name=="log4j-core" and .version=="2.14.1")' "$sbom" > /dev/null 2>&1; then
echo "🔴 CRITIQUE: $sbom (prod)"
fi
done

Pour une gestion à l’échelle, on centralise les SBOM dans Dependency-Track. La plateforme :

  • Ingère les SBOM automatiquement (API, CI/CD)
  • Corrèle avec les bases de vulnérabilités en continu
  • Alerte quand une nouvelle CVE impacte un composant existant
  • Historise l’évolution des vulnérabilités par projet
Fenêtre de terminal
# Upload d'un SBOM vers Dependency-Track via API
curl -X POST "https://dtrack.example.com/api/v1/bom" \
-H "X-Api-Key: $DTRACK_API_KEY" \
-H "Content-Type: application/json" \
-d @sbom.cdx.json

Prenons l’exemple de Log4Shell (CVE-2021-44228, score CVSS 10.0). Avec des SBOM centralisés, le workflow de réponse devient :

  1. Identifier : rechercher log4j-core dans tous les SBOM pour lister les artefacts concernés
  2. Filtrer : parmi ces artefacts, isoler ceux avec une version vulnérable (< 2.15.0)
  3. Prioriser : distinguer les environnements de production exposés des environnements de développement internes
  4. Corriger : déployer les patches en commençant par les services critiques

Sans SBOM, chaque étape nécessite des recherches manuelles dans les dépôts, les images et les configurations. Avec des SBOM à jour, on passe de plusieurs jours de recherche à quelques heures de traitement.

Un scan de vulnérabilités sur un SBOM complet peut remonter des centaines de CVE. En pratique, la majorité ne sont pas exploitables dans le contexte :

  • Dépendance présente mais jamais appelée : le code vulnérable existe dans l’image mais aucun chemin d’exécution ne l’atteint
  • Composant désactivé : une feature flag ou une configuration désactive la fonction concernée
  • Contexte d’exploitation absent : la CVE nécessite un accès réseau que mon conteneur n’a pas
  • Déjà mitigé : un WAF, un contrôle réseau ou une sandbox neutralise l’attaque

Sans moyen de qualifier ces vulnérabilités, mes équipes passent leur temps à trier du bruit au lieu de corriger les vrais problèmes. C’est l’alert fatigue : à force de faux positifs, on finit par ignorer les vraies alertes.

Le VEX (Vulnerability Exploitability eXchange) est un format standardisé pour documenter l’état d’exploitabilité d’une vulnérabilité dans un contexte donné. C’est le compagnon indispensable du SBOM.

Un document VEX associe une CVE à un statut :

StatutSignification
not_affectedLe produit n’est pas impacté (composant non utilisé, config désactivée…)
affectedLe produit est impacté et nécessite une action
fixedLa vulnérabilité a été corrigée dans cette version
under_investigationL’analyse est en cours

Imaginons que Grype remonte CVE-2024-1234 sur libxml2 dans une image. Après analyse, on constate que :

  • l’application n’appelle jamais les fonctions XML concernées
  • le binaire vulnérable est présent mais jamais exécuté

On peut créer un VEX pour documenter cette décision :

{
"document": {
"category": "vex",
"title": "VEX pour mon-app:1.2.0"
},
"statements": [
{
"vulnerability": { "name": "CVE-2024-1234" },
"products": ["pkg:oci/mon-app@1.2.0"],
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path",
"impact_statement": "libxml2 est présent dans l'image de base mais notre application n'utilise aucune fonction de parsing XML."
}
]
}

Deux formats principaux existent :

  • OpenVEX : format léger porté par Chainguard et l’écosystème Sigstore
  • CycloneDX VEX : intégré nativement dans CycloneDX depuis la version 1.4
  • CSAF VEX : format OASIS utilisé par les grands éditeurs (Red Hat, Cisco…)
Fenêtre de terminal
# Générer un scan avec Grype
grype sbom:./sbom.cdx.json -o json > vulns.json
# Appliquer un VEX pour filtrer les faux positifs
grype sbom:./sbom.cdx.json --vex ./mon-app.vex.json
# Le scan ne remonte plus les CVE marquées not_affected

Un SBOM utile, ce n’est pas « un fichier JSON de plus ». C’est un levier d’automatisation qui transforme une question floue (« on utilise quoi ? ») en données structurées et interrogeables.

Les bénéfices sont concrets :

  • Visibilité : on sait exactement ce que contient chaque artefact
  • Réactivité : en quelques minutes, on identifie les systèmes impactés par une CVE
  • Traçabilité : on peut prouver ce qu’on livre à ses clients et auditeurs
  • Conformité : on répond aux exigences CRA, NIS2 et Executive Order 14028

Ma checklist minimale :

  1. Générer un SBOM sur chaque artefact final (image, binaire)
  2. Scanner automatiquement avec Grype ou Trivy en CI/CD
  3. Distribuer le SBOM (artefact CI → OCI attach → attestation signée)
  4. Centraliser dans Dependency-Track pour la gestion continue
  5. Qualifier les faux positifs avec des documents VEX
  6. Surveiller les nouvelles CVE sur mes composants existants

La question n’est plus « faut-il adopter les SBOM ? » mais « comment les rendre actionnables ? ». Ce guide t’a donné les bases — à toi de les adapter à ton contexte.

Voici quelques ressources pour aller plus loin :

Le SBOM dit « ce composant est présent ». Le VEX (Vulnerability Exploitability eXchange) dit « cette vulnérabilité est-elle exploitable dans mon contexte ? ».

Consultez le guide VEX complet pour :

  • Comprendre les 4 statuts VEX (not_affected, affected, fixed, under_investigation)
  • Créer un document VEX avec vexctl
  • Intégrer VEX dans votre workflow SBOM → Scan → VEX → Rapport filtré

Ressources externes :

Un SBOM non signé peut être falsifié. Utilisez Cosign pour :

  • Attester le SBOM : le lier cryptographiquement à l’image avec une signature
  • Vérifier l’attestation avant déploiement
  • Automatiser la vérification dans Kubernetes avec Kyverno