Skip to main content

Comment créer des SBOM en Java avec Maven et Gradle

Écrit par
blog hero software supply chain security

31 octobre 2022

0 minutes de lecture

Lors du développement d’applications Java, nous dépendons fortement de bibliothèques et de frameworks externes. Chaque package Java importé dépend probablement lui aussi d’autres bibliothèques. Cela signifie qu’il est souvent difficile de savoir exactement quels packages Java sont inclus dans votre application. En tant que développeur, vous ne connaissez probablement pas toutes les bibliothèques que vous utilisez réellement, en raison de ces dépendances imbriquées (transitives).

Nous avons récemment expliqué pourquoi et comment gérer soigneusement nos dépendances. Dans l’article Bonnes pratiques pour gérer les dépendances Java, j’ai présenté les options et les outils disponibles pour mettre en place une stratégie de gestion des dépendances. Mais que se passe-t-il si vous livrez votre application Java à un client ? Comment peut-il savoir quelles dépendances sont incluses ? Et surtout, comment peut-il vérifier qu’elles ne présentent aucune faille de sécurité ? La réponse : une nomenclature logicielle.

Qu’est-ce qu’une SBOM ?

Une nomenclature logicielle, souvent désignée par l’acronyme SBOM, est une liste de tous les composants logiciels utilisés dans une application. Elle comprend les bibliothèques open source tierces, les packages fournis par des éditeurs et les artefacts développés par l’organisation elle-même. Vous pouvez la considérer comme la liste complète des ingrédients de vos applications.

Attention toutefois à ne pas confondre une SBOM avec la Bill Of Materials (BOM) de Maven. Dans Maven, une BOM est un type particulier de fichier POM qui permet de centraliser les dépendances d’une application. Dans la plupart des cas, ces dépendances fonctionnent bien ensemble et doivent être utilisées comme un ensemble, comme c’est le cas des BOM utilisées dans Spring.

Une SBOM est un document que vous créez en parallèle de votre application. Elle permet à tous les utilisateurs ou clients de savoir de manière uniforme ce que votre application utilise en coulisses.

Pourquoi créer une SBOM ?

Il existe plusieurs raisons de créer une SBOM. Tout d’abord, elle apporte de la transparence sur le contenu de votre application. Dans la plupart des applications Java, 80 à 90 % du binaire généré est constitué d’autres packages Java, comme des bibliothèques et des frameworks.

Aujourd’hui, les problèmes de sécurité de la chaîne d’approvisionnement sont nombreux. Les dépendances que vous utilisez font partie de votre chaîne d’approvisionnement. Si un problème est découvert dans l’une de ces bibliothèques, vous devez savoir si votre application est vulnérable. Prenons les récentes vulnérabilités Log4Shell et Spring4Shell, qui ont affecté certains packages couramment utilisés. Lorsqu’une SBOM est fournie avec chaque version, les utilisateurs finaux et les clients peuvent facilement vérifier s’ils sont concernés par des vulnérabilités.

La création de SBOM devrait bientôt devenir une pratique courante, voire parfois obligatoire, lors de la livraison de logiciels. Il nous semble donc important d’expliquer comment créer ces SBOM pour vos projets Java. C’est ce que nous allons voir dans la suite de cet article.

Normes SBOM : SPDX et CycloneDX

Il existe actuellement plusieurs normes SBOM. Les deux plus utilisées sont SPDX et CycloneDX. Elles permettent toutes deux de répertorier les composants contenus dans votre application.

Software Package Data Exchange (SPDX) est un projet collaboratif de la Linux Foundation qui fournit une norme ouverte pour communiquer des informations de nomenclature logicielle, notamment sur la provenance, les licences, la sécurité et d’autres sujets connexes. La spécification SPDX est reconnue comme norme internationale ouverte pour la sécurité, la conformité des licences et d’autres artefacts de la chaîne d’approvisionnement logicielle, sous la référence ISO/IEC 5962:2021.

CycloneDX est une norme SBOM de la fondation OWASP, conçue pour les contextes de sécurité des applications et l’analyse des composants de la chaîne d’approvisionnement. Elle fournit un inventaire de tous les composants logiciels internes et tiers. Cette spécification complète va au-delà des bibliothèques logicielles et inclut des normes telles que la nomenclature des logiciels en tant que service (SaaSBOM), le Vulnerability Exploitability Exchange (VEX) et bien d’autres. Le projet CycloneDX propose des normes en XML, JSON et Protocol Buffers, ainsi qu’une vaste collection d’outils officiels et pris en charge par la communauté pour créer des documents conformes à la norme ou interagir avec eux.

Quand créer une SBOM en Java

Java étant un langage compilé, vous devez créer une SBOM à chaque fois que vous générez une version de production de votre application. Il est donc tout à fait logique d’en créer une avec l’un des systèmes de build Java, puisque celui-ci télécharge tous les packages nécessaires à la compilation et à la création de votre application. Grâce à un plugin Maven ou Gradle, vous pouvez facilement créer une SBOM à chaque version de votre binaire, sur une seule machine ou dans le cadre de votre pipeline CI.

Créer une SBOM Java avec Maven

Plugin CycloneDX pour Maven

Un plugin CycloneDX est disponible sur Maven Central et GitHub. Il semble bien maintenu et couramment utilisé.

<plugins>
   <plugin>
       <groupId>org.cyclonedx</groupId>
       <artifactId>cyclonedx-maven-plugin</artifactId>
       <version>2.7.1</version>
       <executions>
           <execution>
               <phase>package</phase>
               <goals>
                   <goal>makeAggregateBom</goal>
               </goals>
           </execution>
       </executions>
       <configuration>
           <projectType>library</projectType>
           <schemaVersion>1.4</schemaVersion>
           <includeBomSerialNumber>true</includeBomSerialNumber>
           <includeCompileScope>true</includeCompileScope>
           <includeProvidedScope>true</includeProvidedScope>
           <includeRuntimeScope>true</includeRuntimeScope>
           <includeSystemScope>true</includeSystemScope>
           <includeTestScope>false</includeTestScope>
           <includeLicenseText>false</includeLicenseText>
           <outputReactorProjects>true</outputReactorProjects>
           <outputFormat>all</outputFormat>
           <outputName>CycloneDX-Sbom</outputName>
       </configuration>
   </plugin>
</plugins>

Vous pouvez configurer le plugin CycloneDX de différentes façons. Ici, j’ai associé l’objectif makeAggregateBom du plugin à la phase package de Maven. Une fois mon JAR créé, le plugin génère une SBOM en tenant compte de l’agrégation. Il exclut les dépendances de test et génère la SBOM aux formats XML et JSON dans mon dossier target.

Toutes les dépendances, directes comme transitives, sont répertoriées individuellement dans la SBOM, comme ci-dessous. Dans cet exemple, le package jackson-databind a été inclus de manière transitive dans mon application via sprint-boot-starter-web.

<component type="library" bom-ref="pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar">
 <publisher>FasterXML</publisher>
 <group>com.fasterxml.jackson.core</group>
 <name>jackson-databind</name>
 <version>2.13.4</version>
 <description>General data-binding functionality for Jackson: works on core streaming API</description>
 <hashes>
   <hash alg="MD5">03cb7aea126610e4c96ca6d14d75cc55</hash>
   <hash alg="SHA-1">98b0edfa8e4084078f10b7b356c300ded4a71491</hash>
   <hash alg="SHA-256">c9faff420d9e2c7e1e4711dbeebec2506a32c9942027211c5c293d8d87807eb6</hash>
   <hash alg="SHA-512">23f32026b181c6c71efc7789a8420c7d5cbcfb15f7696657e75f9cbe3635d13a88634b5db3c344deb914b719d60e3a9bfc1b63fa23152394e1e70b8e7bcd2116</hash>
   <hash alg="SHA-384">e25e844575891b2f3bcb2fdc67ae9fadf54d2836052c9ea2c045f1375eaa97e4780cd6752bef0ebc658fa17400c55268</hash>
   <hash alg="SHA3-384">e6955877c2c27327f6814f06d681118be2ae1a36bc5ff2e84ad27f213203bf77c347ba18d9abc61d5f1c99b6e81f6c2d</hash>
   <hash alg="SHA3-256">88b12b0643a4791fa5cd0c5e30bc2631903870cf916c8a1b4198c856fd91e5f4</hash>
   <hash alg="SHA3-512">7e86a69bcf7b4c8a6949acce0ec15f33b74d5ac604f23cd631ec16bfdfd70d42499028b9d062648b31d7a187ea4dc98ec296a329f4cfd4952744ed1281fa9d9a</hash>
 </hashes>
 <licenses>
   <license>
     <id>Apache-2.0</id>
   </license>
 </licenses>
 <purl>pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar</purl>
 <externalReferences><reference type="vcs"><url>http://github.com/FasterXML/jackson-databind</url></reference><reference type="website"><url>http://fasterxml.com/</url></reference><reference type="distribution"><url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url></reference></externalReferences>
</component>

Plugin SPDX pour Maven (prototype)

Il existe également un plugin Maven pour SPDX. Il est toutefois encore indiqué comme étant un prototype. Dans l’exemple ci-dessous, j’ai utilisé la dernière version disponible au moment de la rédaction, avec une configuration similaire à celle présentée dans le README GitHub. J’ai également associé la tâche de création SPDX à la phase package, comme dans l’exemple CycloneDX.

<plugin>
   <groupId>org.spdx</groupId>
   <artifactId>spdx-maven-plugin</artifactId>
   <version>0.6.1</version>
   <executions>
       <execution>
           <id>build-spdx</id>
           <phase>package</phase>
           <goals>
               <goal>createSPDX</goal>
           </goals>
       </execution>
   </executions>
</plugin>

Par défaut, cette version du plugin place le résultat dans /target/site/{groupId}_{artifactId}-{version}.spdx.json. Comme l’extension du fichier l’indique, le format de sortie par défaut est JSON.

En parcourant le résultat, j’ai été surpris de constater qu’il ne contenait que les dépendances de premier niveau, et non les dépendances transitives. Le plugin étant indiqué comme un prototype, c’est peut-être la raison. Il est également possible que je m’y prenne mal. Cependant, la documentation ne m’a pas permis d’y voir clair.

Outil CLI SPDX pour Maven

Autre possibilité : un outil en ligne de commande appelé spdx-sbom-generator. Cet outil CLI peut générer des SBOM SPDX pour de nombreux gestionnaires de packages, notamment Maven pour les applications Java. Gradle n’est actuellement pas pris en charge.

Exécuter cet outil depuis la ligne de commande, sans aucun paramètre et à la racine de mon application, génère une SBOM au format SPDX. D’autres formats de sortie, comme JSON, sont également disponibles en passant un paramètre.

./spdx-sbom-generator

Cette SBOM générée semble bien répertorier toutes les dépendances transitives individuellement, comme je le pensais.

##### Package representing the jackson-databind

PackageName: jackson-databind
SPDXID: SPDXRef-Package-jackson-databind-2.13.4
PackageVersion: 2.13.4
PackageSupplier: Organization: jackson-databind
PackageDownloadLocation: https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind/2.13.4
FilesAnalyzed: false
PackageChecksum: SHA1: 7d03e73aa50d143b3ecbdea2c0c9e158e5ed8021
PackageHomePage: NOASSERTION
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
PackageLicenseComments: NOASSERTION
PackageComment: NOASSERTION

Relationship: SPDXRef-Package-jackson-databind-2.13.4 DEPENDS_ON SPDXRef-Package-jackson-annotations-2.13.4
Relationship: SPDXRef-Package-jackson-databind-2.13.4 DEPENDS_ON SPDXRef-Package-jackson-core-2.13.4

Si vous souhaitez créer des SBOM au format SPDX, je vous recommande cet outil plutôt que le plugin prototype.

Créer une SBOM Java avec Gradle

Passons maintenant à Gradle. Bien qu’il soit moins utilisé que Maven, Gradle reste très répandu et est incontestablement un outil de build bien établi dans l’écosystème.

CycloneDX pour Gradle

Un plugin CyconeDX est disponible pour Gradle. Comme le plugin Maven présenté précédemment, le plugin Gradle est publié par l’organisation CycloneDX sur Github et compte certains des mêmes responsables de maintenance.

Pour utiliser le plugin, ajoutez-le simplement au bloc plugin de votre fichier Gradle :

plugins {
   id 'org.cyclonedx.bom' version '1.7.2'
}

Vous pouvez configurer le plugin avec un bloc cyclonedxBom, comme ci-dessous :

cyclonedxBom {
   includeConfigs = ["runtimeClasspath"]
   skipConfigs = ["compileClasspath", "testCompileClasspath"]
   projectType = "application"
   schemaVersion = "1.4"
   destination = file("build/reports")
   outputName = "CycloneDX-Sbom"
   outputFormat = "all"
   includeBomSerialNumber = true
   componentVersion = "2.0.0"
}

Dans cet exemple, j’ai également ajouté la ligne build.finalizedBy('cyclonedxBom') à la fin de mon fichier Gradle. Le plugin exécutera ainsi automatiquement la cible cyclonedxBom après le build de mon application, comme le plugin Maven. Bien entendu, c’est à vous de décider si vous souhaitez associer la cible du plugin au build, et de quelle manière.

Le résultat est conforme aux attentes et similaire à celui obtenu avec le plugin Maven. Avec la configuration ci-dessus, vous trouverez les versions JSON et XML de la SBOM dans le dossier build de votre projet. Ce plugin est donc une excellente option pour les utilisateurs de Gradle qui souhaitent créer des SBOM.

SPDX pour Gradle

Malheureusement, nous n’avons pas trouvé de véritable plugin permettant de créer des SBOM au format SPDX pour les projets Gradle. Les outils CLI tiers sont soit indisponibles, soit ne fonctionnent pas correctement avec les projets Java basés sur Gradle. Pour le moment, il n’existe donc pas de moyen simple de générer des SBOM SPDX avec Gradle.

Créer des SBOM pour vos projets Java

Générer une SBOM lors du build de votre projet Java devrait bientôt devenir une pratique de plus en plus courante. Confier cette tâche à votre système de build est tout à fait logique.

Des plugins sont disponibles pour Maven et Gradle afin de créer des SBOM lors du build de votre application. Comme nous l’avons montré ci-dessus, ces plugins permettent de créer facilement des SBOM en même temps que les artefacts de build Java.

Lancez-vous dans les compétitions Capture The Flag

Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.

Lire la suite

blog feature snyk container custom base recommendations
Blog

Découvrez Evo Agentic AppSec : une sécurité au rythme du développement de l’IA

Le développement piloté par l’IA dépasse les workflows de sécurité traditionnels. L’AppSec agentique de Snyk s’appuie sur des agents de sécurité pour détecter, corriger et vérifier les vulnérabilités en continu, tandis que les équipes définissent les exigences.

blog feature ai violet
Blog

VulnBump : les agents IA peuvent-ils corriger les dépendances vulnérables sans casser le build ?

VulnBump évalue des agents IA sur 307 mises à niveau de dépendances réelles. Une correction n’est comptabilisée que si la vulnérabilité disparaît et que la compilation et les tests restent au vert.

Blog

Les modèles de pointe ont trouvé les vulnérabilités. Seul l’attaquant a trouvé les chaînes d’exploitation.

L’analyse statique a détecté les failles, mais seuls des tests d’attaque en conditions réelles ont prouvé comment elles pouvaient être enchaînées pour provoquer des compromissions. Comparaison d’Evo COS, de Claude Security et de Claude Code Security.