Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Sécurité supply chain logicielle : SBOM, SLSA, Sigstore

Par mis à jour le

Améliorer cette page

En décembre 2021, la faille Log4Shell a posé une question à laquelle la plupart des équipes ne savaient pas répondre : « utilisons-nous Log4j, et où ? ». La supply chain logicielle, tout ce qui intervient entre une ligne de code et l'application en production, est devenue la cible privilégiée des attaquants : en 2025, Sonatype a recensé plus de 454 600 nouveaux paquets malveillants. Cette leçon ouvre le module sur la chaîne d'approvisionnement : elle donne la carte des risques et des trois réponses, SBOM, SLSA et Sigstore, que les leçons suivantes détaillent une à une.

Les commandes d'installation de dépendances sont mesurées : npm ci refuse un lock falsifié, pip refuse un paquet dont l'empreinte ne correspond pas, et une application Express d'une seule dépendance en tire 69 autres.

  • Situer les maillons de la chaîne et les attaques qui les ont visés
  • Distinguer les trois questions : transparence, intégrité, provenance
  • Produire un SBOM et lire ce qu'il contient
  • Situer un build sur les niveaux de SLSA 1.2
  • Expliquer la signature sans clé de Sigstore et le Trusted Publishing
  • Durcir l'installation des dépendances avec un lock, des empreintes et --ignore-scripts

La supply chain logicielle est l'ensemble des fournisseurs, outils et processus qui interviennent entre votre première ligne de code et l'application déployée. Le mot vient de la logistique, et l'analogie tient : un produit n'est pas plus sûr que la pièce la moins contrôlée qui le compose. Chaque maillon est un point d'entrée possible.

MaillonExemplesCe qu'un attaquant y fait
Code sourcevotre dépôt, les contributions externesinjecte du code par un compte ou une revue faible
Dépendancesnpm, PyPI, Maven, modules Gopublie une version piégée ou un nom proche (typosquatting)
Buildrunners CI, compilateurs, actionsmodifie l'artefact pendant sa fabrication
Artefactsimages, binaires, paquetssubstitue un artefact par un autre au même nom
Distributionregistres, CDNsert une version altérée à tous les clients

D'après le rapport OSSRA 2026 de Black Duck, 98 % des applications commerciales auditées contiennent de l'open source, qui représente en moyenne 70 % de leur code. Le chiffre se vérifie en une commande : une application qui ne déclare qu'Express en dépendance installe 69 paquets, mesuré avec npm 11.19.0.

Fenêtre de terminal
$ cat package.json
{ "name": "demo-sbom", "version": "1.0.0", "dependencies": { "express": "4.21.2" } }
$ npm install --silent
$ node -e 'const l=require("./package-lock.json"); console.log(Object.keys(l.packages).length - 1)'
69

Chacun de ces 69 paquets a un ou plusieurs mainteneurs dont vous n'avez jamais vérifié la sécurité du compte. Le rapport 2026 de Sonatype donne l'autre face du problème : 454 600 paquets malveillants publiés en 2025, 1,233 million au total, et plus de 99 % de ce malware sur npm.

Chaque attaque marquante a visé un maillon différent, et chacune a laissé une parade derrière elle. Les retenir par paire, attaque et parade, est le moyen le plus sûr de comprendre à quoi sert chaque outil du module.

AttaqueMaillon viséCe qui s'est passéParade apparue ensuite
SolarWinds (2020)builddu code malveillant inséré pendant la compilation d'Orion ; environ 18 000 clients reçoivent la mise à jour piégéeprovenance du build (SLSA)
ua-parser-js (2021)dépendancele compte npm du mainteneur est piraté, trois versions publiées avec un mineur et un voleur de mots de passelock, épinglage, Trusted Publishing
xz utils (2024)code sourceune porte dérobée introduite après deux ans d'ingénierie sociale envers le mainteneur (CVE-2024-3094)revue à deux, provenance des sources
Polyfill.io (2024)distributionle domaine du CDN racheté sert du code malveillant à plus de 100 000 sitesintégrité des ressources, auto-hébergement
Shai-Hulud (2025)dépendanceun ver npm vole des jetons de publication et se republie : plus de 500 paquets en septembre, environ 800 en novembreTrusted Publishing, --ignore-scripts

L'OWASP en a tiré les conséquences : dans son Top 10:2025, la catégorie A03 Software Supply Chain Failures arrive troisième, et la moitié des répondants de son enquête communautaire l'ont classée première préoccupation. En 2026, Trivy lui-même, un scanner de sécurité, a été compromis : la leçon sur Trivy en détaille l'incident.

Les trois questions : transparence, intégrité, provenance

Section intitulée « Les trois questions : transparence, intégrité, provenance »

Toute la sécurité de la supply chain se ramène à trois questions. Si l'une reste sans réponse vérifiable, la chaîne a un trou, quel que soit le soin mis dans les deux autres.

QuestionCe qu'elle demandeRéponse outillée
TransparenceQu'est-ce qui compose mon logiciel ?un SBOM
IntégritéL'artefact a-t-il été modifié depuis sa fabrication ?une signature
ProvenanceDe quel commit et de quel build vient-il ?une attestation SLSA

Les trois se tiennent. Un SBOM non signé peut être falsifié par celui qui modifie l'image. Une signature prouve qu'un artefact n'a pas changé, pas ce qu'il contient. Une attestation de provenance dit d'où vient l'image, pas si elle embarque une dépendance vulnérable. Les leçons suivantes du module traitent chacune une de ces réponses.

Le schéma ci-dessous place chaque réponse sur la chaîne : le SBOM inventorie les dépendances, l'attestation de provenance naît au build, et la signature accompagne l'artefact jusqu'à l'admission, où elle est vérifiée avant le déploiement.

La chaîne va du code source aux dépendances, au build, à l'artefact puis à l'admission. Le SBOM inventorie les dépendances, l'attestation SLSA naît au build, la signature Cosign accompagne l'artefact et est vérifiée à l'admission.Code sourceDépendancesBuildArtefactimage, paquetAdmissionvérificationSBOMtransparenceAttestation SLSAprovenanceSignature Cosignintégrité
Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %

Un SBOM (Software Bill of Materials) est l'inventaire de tous les composants d'un logiciel : dépendances directes et transitives, versions exactes, licences et identifiants standard (purl). C'est lui qui permet de répondre en quelques minutes à « sommes-nous touchés par cette CVE ? », là où Log4Shell a coûté des semaines d'audit manuel.

Deux formats dominent. CycloneDX, porté par l'OWASP et normalisé par l'Ecma sous la référence ECMA-424, est orienté sécurité et porte les déclarations VEX d'exploitabilité. SPDX, porté par la Linux Foundation et normalisé ISO/IEC 5962, vient de la conformité des licences. Les outils courants produisent les deux.

Syft (Anchore) inventorie un dossier ou une image. La commande à retenir est syft scan : l'ancienne forme syft packages, encore citée partout, affiche désormais Command "packages" is deprecated, use syft scan instead avec Syft 1.52.0. Sur l'application Express, le SBOM CycloneDX recense 71 composants : les 69 paquets npm, plus l'application et son lock.

Fenêtre de terminal
$ syft scan dir:. -o cyclonedx-json > sbom.cdx.json
$ jq '.specVersion, (.components | length)' sbom.cdx.json
"1.7"
71
$ jq '.components[] | select(.name == "express") | {name, version, purl, licenses}' sbom.cdx.json
{
"name": "express",
"version": "4.21.2",
"purl": "pkg:npm/express@4.21.2",
"licenses": [ { "license": { "id": "MIT" } } ]
}

Le champ purl (package URL) est la clé qui relie le SBOM aux bases de vulnérabilités. Produire, publier et exploiter cet inventaire est le sujet de la leçon suivante, sur le SBOM.

SLSA (Supply-chain Levels for Software Artifacts, prononcé « salsa ») est un cadre de l'OpenSSF qui gradue la confiance qu'on peut accorder à un artefact. Sa version 1.2, la version en vigueur, compte deux volets : le volet Build, qui juge la fabrication, et le volet Source, réintroduit dans cette version après avoir été retiré de la 1.0, qui juge la gestion du code.

Niveau BuildExigenceCe que ça prouve
L0aucunerien
L1une provenance existele build est documenté
L2provenance signée par une plateforme de build hébergéeelle n'a pas été falsifiée après coup
L3build isolé, secret de signature hors de portée des étapes du buildmême un build compromis ne peut pas mentir sur sa provenance

Le volet Source va de L1 (code sous gestion de versions) à L4 (revue par deux personnes de confiance sur les branches protégées). Côté outillage, GitHub l'écrit dans sa documentation : ses attestations d'artefacts fournissent seules le niveau Build L2, et un workflow réutilisable, qui sépare le build du workflow appelant, permet d'atteindre L3. La leçon sur la provenance SLSA montre comment la vérifier avant de déployer.

Signer un artefact a longtemps voulu dire gérer une clé privée : la stocker, la renouveler, la révoquer si elle fuit. Presque personne ne le faisait. Sigstore, projet de l'OpenSSF, supprime la clé durable : la signature repose sur l'identité OIDC du signataire, par exemple le workflow GitHub Actions qui publie.

Trois briques coopèrent. Fulcio délivre un certificat de dix minutes lié à cette identité. Cosign signe l'artefact avec. Rekor enregistre la signature dans un journal de transparence public et inaltérable : le certificat expire, mais la signature reste vérifiable, et toute signature frauduleuse y laisse une trace.

Fenêtre de terminal
# Signer une image par son digest, dans un job CI qui a l'identité OIDC
cosign sign ghcr.io/acme/facturation@sha256:<digest>
# Vérifier : qui a signé, et depuis quel émetteur d'identité
cosign verify \
--certificate-identity-regexp '^https://github.com/acme/facturation/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/acme/facturation@sha256:<digest>

La vérification compte plus que la signature : une image signée que personne ne vérifie ne protège rien. Dans un cluster, ce contrôle revient à un contrôleur d'admission comme Kyverno, qui refuse un pod dont l'image n'est pas signée par l'identité attendue. La leçon sur Cosign pratique la signature et ses échecs de vérification.

Shai-Hulud a exploité le dernier maillon faible : des jetons de publication npm à longue durée de vie, volés sur des postes ou dans des variables de CI. Le Trusted Publishing, disponible sur npm et PyPI, remplace ce jeton par une authentification OIDC du pipeline auprès du registre, qui délivre un jeton éphémère. Le paquet publié porte alors une provenance signée. npm a révoqué ses anciens jetons classiques en décembre 2025, ce qui pousse tous les mainteneurs vers ce mode.

Les dépendances sont le maillon le plus attaqué, parce que leur code s'exécute avec vos droits, souvent dès l'installation. Quatre gestes réduisent ce risque, et trois se vérifient en quelques secondes. La leçon sur la sécurisation des dépendances les décline par écosystème.

Une plage de versions comme ^4.17.0 accepte toute version future compatible, y compris une version piégée publiée demain. On épingle donc une version exacte, et surtout on versionne le lock file, qui fige l'arbre complet, dépendances transitives comprises, avec l'empreinte de chaque paquet.

// ❌ À éviter : accepte n'importe quelle version future
{ "dependencies": { "lodash": "^4.17.0", "express": "*" } }
// Version exacte, et package-lock.json versionné
{ "dependencies": { "lodash": "4.17.21", "express": "4.21.2" } }

En CI, on installe avec npm ci, jamais npm install. Mesuré avec npm 11.19.0 : quand package.json et le lock divergent, npm ci refuse d'installer au lieu de réécrire le lock en silence.

Fenêtre de terminal
$ npm ci
npm error code EUSAGE
npm error `npm ci` can only install packages when your package.json and package-lock.json
or npm-shrinkwrap.json are in sync. Please update your lock file with `npm install` before continuing.

Le lock porte l'empreinte SHA-512 de chaque paquet (champ integrity). Si le registre, un miroir ou un proxy sert un fichier différent, l'installation échoue. Mesuré en remplaçant l'empreinte d'Express dans le lock : npm ci sort en code 1 sur une erreur EINTEGRITY.

Fenêtre de terminal
$ npm ci
npm error code EINTEGRITY
npm error sha512-AAAA…== integrity checksum failed when using sha512:
wanted sha512-AAAA…== but got sha512-28HqgMZAmih1Czt9…== (58016 bytes)

Python fait de même avec pip install --require-hashes, sur un fichier produit par pip-compile --generate-hashes. Une subtilité, mesurée avec pip 26.1.2 : chaque paquet liste plusieurs empreintes, une par fichier publié, et pip en accepte n'importe laquelle. Fausser une seule empreinte ne bloque donc rien ; fausser toutes celles de requests fait échouer l'installation avec THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE.

Un paquet npm peut déclarer des scripts preinstall ou postinstall exécutés à l'installation. C'est par un preinstall que Shai-Hulud 2.0 lançait sa charge, avant même que le code soit importé. L'option --ignore-scripts les désactive : npm ci --ignore-scripts installe l'arbre sans exécuter une ligne de code tiers. Quelques paquets en ont besoin pour compiler un module natif ; on les traite alors un par un.

Les trois gestes précédents protègent contre une substitution, pas contre une faille connue dans une version légitime. Un scanner de composition (SCA) compare les dépendances aux bases de CVE : npm audit, Trivy ou Grype. Le module sur le code et les dépendances les a mesurés, avec leurs codes de sortie, dans la leçon sur la SCA.

Ce workflow réunit les trois réponses au moment de la publication d'une version : il construit l'image, atteste sa provenance avec l'action officielle de GitHub (niveau Build L2) et produit son SBOM, archivé avec le run. Chaque action est épinglée sur le SHA de son commit, et le workflow passe actionlint, zizmor 1.30.0 et poutine sans constat.

.github/workflows/release.yml
name: release
on:
push:
tags:
- "v*"
permissions: {}
jobs:
build:
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
id-token: write
attestations: write
env:
IMAGE: ghcr.io/acme/facturation
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Construire et pousser l'image
id: push
env:
TAG: ${{ github.ref_name }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "$GH_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin
docker build -t "$IMAGE:$TAG" .
docker push "$IMAGE:$TAG"
digest=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE:$TAG" | cut -d@ -f2)
echo "digest=$digest" >> "$GITHUB_OUTPUT"
- name: Attester la provenance
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-name: ${{ env.IMAGE }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
- name: Générer le SBOM
uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2
with:
image: ${{ env.IMAGE }}@${{ steps.push.outputs.digest }}
format: cyclonedx-json
output-file: sbom.cdx.json
registry-username: ${{ github.actor }}
registry-password: ${{ secrets.GITHUB_TOKEN }}

Le tag Git n'apparaît jamais directement dans le script : il passe par la variable TAG, ce qui évite une injection de commande par un nom de tag forgé. L'action sbom-action archive elle-même le SBOM comme artefact du run, son option upload-artifact valant true par défaut.

Tout mettre en place d'un coup échoue presque toujours. L'ordre qui fonctionne suit les trois questions, de la moins coûteuse à la plus exigeante, et chaque étape apporte une protection utile avant la suivante.

  1. Inventorier : un SBOM à chaque build des projets critiques, et un scanner de dépendances en CI.

  2. Verrouiller : lock files versionnés, npm ci --ignore-scripts, empreintes vérifiées, Trusted Publishing pour vos propres paquets.

  3. Prouver : images signées avec Cosign et attestations de provenance, niveau Build L2.

  4. Imposer : vérification des signatures à l'admission dans le cluster, puis niveau L3 avec un workflow de build réutilisable.

  • La supply chain va du code source à la distribution ; chaque maillon a déjà été attaqué.
  • 98 % des applications contiennent de l'open source, 70 % de leur code en moyenne (OSSRA 2026).
  • Trois questions : transparence (SBOM), intégrité (signature), provenance (attestation SLSA).
  • Un SBOM se produit avec syft scan, pas l'ancienne forme syft packages.
  • SLSA 1.2 a deux volets : Build (L0 à L3) et Source (L1 à L4) ; les attestations GitHub donnent seules Build L2.
  • Sigstore signe sans clé durable : certificat Fulcio de dix minutes, trace publique dans Rekor.
  • En CI : npm ci --ignore-scripts, lock versionné, empreintes vérifiées ; pip n'échoue que si aucune empreinte listée ne correspond.

Vérifiez que l'essentiel de cette leçon est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Les questions ci-dessous reprennent les doutes les plus courants sur la supply chain logicielle : SBOM, SLSA, Sigstore et protection des dépendances, avec les mêmes versions mesurées que la leçon.

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn