Meilleures pratiques pour une chaîne d’approvisionnement logicielle sécurisée
L’open source est partout. Il se trouve dans de nombreux codebase protégé et de nombreux projets de la communauté. Pour les organisations et les individus, la question aujourd’hui n’est pas de savoir si vous utilisez ou non du code open source, mais de quel code open source vous vous servez, et en quelle quantité.
Si vous n’êtes pas au courant de ce qui se trouve dans votre chaîne d’approvisionnement logicielle, une vulnérabilité en amont située dans l’une de vos dépendances peut être fatale, vous rendant ainsi, vous et vos clients, vulnérables à une potentielle compromission. Dans ce document, nous allons approfondir ce que signifie le terme « chaîne d’approvisionnement logicielle », pourquoi cela est important et de quelle manière vous pouvez aider à sécuriser la chaîne d’approvisionnement de votre projet avec les meilleures pratiques.
Les dépendances
Le terme chaîne d’approvisionnement logicielle est utilisé pour faire référence à tout ce qui va dans votre logiciel et de là où il provient. Il s’agit des dépendances et des propriétés de vos dépendances dont votre chaîne d’approvisionnement logicielle dépend. Une dépendance est ce que votre logiciel doit exécuter. Il peut s’agir de code, de fichiers binaires ou d’autres composants, et de leur provenance, par exemple un référentiel ou un gestionnaire de package.
Elle inclut qui a écrit le code, quand il a été contribué, comment il a été examiné pour les problèmes de sécurité, les vulnérabilités connues, les versions prises en charge, les informations de licence et tout ce qui y touche à tout moment du processus.
Votre chaîne d’approvisionnement englobe également d’autres parties de votre pile au-delà d’une application unique. Il s’agit par exemple de scripts de génération et d’empaquetage ou du logiciel qui exécute l’infrastructure sur laquelle votre application s’appuie.
Vulnerabilities
Aujourd’hui, les dépendances logicielles sont omniprésentes. Il est très courant que vos projets utilisent des centaines de dépendances open source pour les fonctionnalités que vous n’avez pas besoin d’écrire vous-même. Cela peut signifier que vous n’avez pas écrit la majorité du code de votre application vous-même.
Les vulnérabilités possibles dans vos dépendances tierces ou open source sont probablement des dépendances que vous ne pouvez pas contrôler aussi étroitement que le code que vous écrivez vous-même. Cela peut créer des risques de sécurité potentiels dans votre chaîne d’approvisionnement.
Si l’une de ces dépendances souffre d’une vulnérabilité, il y a de grandes chances pour que vous en souffriez aussi. Cela peut être effrayant car l’une de vos dépendances peut changer que vous n’en ayez conscience. Même si une vulnérabilité existe dans une dépendance aujourd’hui, mais n’est pas encore exploitable, elle peut être l’être à l’avenir.
La possibilité de tirer profit du travail de milliers de développeurs open source et d’auteurs de bibliothèque signifie que des milliers d’étrangers peuvent contribuer directement à votre code de production. Via la chaîne d’approvisionnement logicielle, votre produit est affecté par des vulnérabilités non corrigées, des erreurs involontaires ou même des attaques malveillantes contre les dépendances.
Compromission de la chaîne d’approvisionnement
La définition traditionnelle d’une chaîne d’approvisionnement provient de l’industrie manufacturière. Il s’agit de la chaîne formée par tous les processus nécessaires pour fabriquer et fournir quelque chose. Cette chaîne part de la planification, passe l’approvisionnement de matériaux, la fabrication et se termine par la vente. Une chaîne d’approvisionnement logicielle est similaire, sauf à la place des matériaux, ion utilise du code. On ne fabrique pas, mais on développe. Au lieu de creuser le minerai du sol, le code est sourcé auprès de fournisseurs commerciaux ou open source, et, en général, le code open source provient de référentiels. L’ajout de code à partir d’un référentiel signifie que votre produit est dépendant de ce code.
Par exemple, une attaque par la chaîne d’approvisionnement logicielle se produit lorsque du code malveillant est ajouté délibérément à une dépendance, par le biais de la chaîne d’approvisionnement de cette dépendance pour distribuer le code à ses victimes. Les attaques par la chaîne d’approvisionnement sont réelles. Il existe de nombreuses méthodes pour attaquer une chaîne d’approvisionnement, de l’insertion directe de code malveillant en tant que nouvelle contributeur, en passant par le détournement du compte d’un contributeur sans que d’autres personnes s’en aperçoive. Il est même possible de compromettre une clé de signature pour distribuer des logiciels qui ne font pas officiellement partie de la dépendance.
Une attaque de chaîne d’approvisionnement logicielle est rarement une fin en soi, il s’agit plutôt d’une opportunité pour un attaquant d’insérer des programmes malveillants ou de mettre une porte dérobée pour un accès futur.
Logiciels non mis à jour
Aujourd’hui, l’utilisation de code open source est importante et ne devrait pas diminuer pour le moment. Étant donné que nous n’arrêterons pas d’utiliser des logiciels open source, la menace pour la sécurité de la chaîne d’approvisionnement est principale provient des logiciels non corrigé. Sachant cela, comment pouvez-vous faire face aux risques que font porter les vulnérabilité des dépendances sur votre projet ?
- Connaître ce qui se trouve dans votre environnement. Cela nécessite de découvrir vos dépendances ainsi que toutes les dépendances transitives afin de comprendre les risques liés à ces dépendances, tels que les vulnérabilités ou les restrictions de gestion des licences.
- Gérer vos dépendances. Lorsqu’une nouvelle faille de sécurité est détectée, vous devez déterminer si vous êtes impacté et, le cas échéant, mettre à jour vers la dernière version et appliquer le dernier correctif de sécurité disponible. Il est particulièrement important de passer en revue les modifications qui introduisent de nouvelles dépendances ou d’auditer régulièrement les dépendances plus anciennes.
- Surveiller votre chaîne d’approvisionnement. Il s’agit d’auditer les contrôles que vous avez en place pour gérer vos dépendances. Cela vous aidera à appliquer des conditions plus restrictives à vos dépendances.
Nous aborderons différents outils et techniques fournis par NuGet et GitHub que vous pouvez utiliser dès aujourd’hui pour résoudre les risques potentiels au sein de votre projet.
Savoir ce qui se trouve dans votre environnement
Packages avec des vulnérabilités connues
Consommateur de packages 📦 | Auteur de package 📦🖊
.NET 8 et Visual Studio 17.8 ont ajouté NuGetAudit, qui avertira les packages directs avec des vulnérabilités connues lors de la restauration. .NET 9 et Visual Studio 17.12 ont également modifié la valeur par défaut pour avertir concernant les packages transitifs.
NuGetAudit nécessite une source pour fournir une base de données de vulnérabilités connues. Par conséquent, si vous n’utilisez pas nuget.org en tant que source de package, vous devez l’ajouter en tant que source d’audit.
Au moment où NuGet vous avertit, la vulnérabilité est déjà connue publiquement. Les attaquants peuvent utiliser cette divulgation publique pour développer des attaques contre les cibles qui n’ont pas corrigé leurs applications. Par conséquent, lorsque vous recevez un avertissement indiquant qu’un package que votre projet utilise présente une vulnérabilité connue, vous devez rapidement agir.
Graphe des dépendances NuGet
Consommateur de packages 📦
Vous pouvez afficher vos dépendances NuGet du projet en examinant directement le fichier projet de celui-ci.
Il se trouve généralement à l’un des deux emplacement suivants :
packages.config
, situé à la racine du projet.<PackageReference>
, situé dans le fichier projet.
Selon la méthode utilisée pour gérer les dépendances NuGet, vous pouvez également utiliser Visual Studio pour afficher vos dépendances directement dans Explorateur de solutions ou dans le Gestionnaire de package NuGet.
Pour les environnements CLI, vous pouvez utiliser la commande dotnet list package
pour répertorier les dépendances de votre projet ou de votre solution.
Vous pouvez également utiliser la commande dotnet nuget why
pour comprendre pourquoi les packages transitifs (ceux qui ne sont pas directement référencés par votre projet) sont inclus dans le graphique de package de votre projet.
Pour plus d’informations sur la gestion des dépendances NuGet, consultez la documentation suivante.
Graphique des dépendances de GitHub
Consommateur de packages 📦 | Auteur de package 📦🖊
Vous pouvez utiliser le graphe des dépendances de GitHub pour afficher les packages dont dépend votre projet et les référentiels qui dépendent de celui-ci. Ce graphe peut vous permettre de voir l’ensemble des vulnérabilités détectées dans les dépendances du projet.
Pour plus d’informations sur les référentiels des dépendances GitHub, consultez la documentation suivante.
Version des dépendances
Consommateur de packages 📦 | Auteur de package 📦🖊
Pour garantir une chaîne d’approvisionnement de dépendances sécurisée, vous devez vous assurer que tous vos outils et de dépendances sont régulièrement mis à jour vers la dernière version stable, car ils incluent souvent les dernières fonctionnalités et correctifs de sécurité aux vulnérabilités connues. Les dépendances comprennent le code dont vous dépendez, les fichiers binaires que vous consommez, les outils dont vous vous utilisez ainsi que d’autres composants. Cela peut inclure :
Gérer les dépendances
Dépendances NuGet déconseillées et vulnérables
Consommateur de packages 📦 | Auteur de package 📦🖊
Vous pouvez utiliser l’interface CLI dotnet pour répertorier les dépendances réputées déconseillées ou vulnérables qui pourraient se trouver dans votre projet ou solution.
Vous pouvez utiliser la commande dotnet list package --deprecated
ou dotnet list package --vulnerable
pour obtenir une liste de toutes les dépréciations ou vulnérabilités connues.
NuGetAudit peut vous avertir des dépendances vulnérables connues, et est activé par défaut lorsqu’une source fournit une base de données de vulnérabilités.
Dépendances GitHub vulnérables
Consommateur de packages 📦 | Auteur de package 📦🖊
Si votre projet est hébergé sur GitHub, vous pouvez tirer profit de GitHub Security pour rechercher des failles de sécurité et des erreurs de dans votre projet. Dependabot les corrigera en ouvrant une demande de tirage (pull request) sur votre codebase.
Intercepter les dépendances vulnérables avant qu’elles ne soient introduites est l’un des buts du mouvement « Shift Left ». La possibilité d’avoir des informations sur les dépendances, comme leur licence, leurs dépendances transitives et l’âge des dépendances par exemple, vous aident à atteindre ce but.
Pour plus d’informations sur les alertes et des mises à jours de Dependabot, consultez la documentation suivante.
Flux NuGet
Consommateur de packages 📦
Utilisez des sources de package que vous approuvez. Lorsque vous utilisez plusieurs flux sources NuGet privés et publics, un package peut être téléchargé à partir de l’un de ces flux. Pour vous assurer que votre génération est prévisible et protégée contre les attaques connues telles que la confusion de dépendances. Le fait de savoir de quel(s) flux proviennent vos packages est une meilleure pratique. Vous pouvez utiliser un flux unique ou un flux privé avec des capacités en amont de protection.
Pour plus d’informations à propos de la protection des flux de package, consultez 3 façon d’atténuer les risques lors de l’utilisation de flux de package privés.
Lorsque vous utilisez un flux privé, reportez-vous aux meilleures pratiques de sécurité pour la gestion des informations d’identification.
Stratégies de confiance client
Consommateur de packages 📦
Il existe des stratégies que vous pouvez choisir pour lesquelles l’utilisation de packages signés est obligatoire. Cela vous permet d’approuver un auteur de package, dès lors qu’il est signé, ou d’approuver un package s’il appartient à un utilisateur ou un compte spécifique signé par NuGet.org.
Pour configurer des stratégies de confiance client, consultez la documentation suivante.
Fichier de verrouillage
Consommateur de packages 📦
Verrouiller les fichiers stocke le code de hachage du contenu du package. Si le code de hachage de contenu d’un package que vous souhaitez installer correspond au fichier de verrouillage, il garantit la reproductibilité du package.
Pour activer les fichiers de verrouillage, consultez la documentation suivante.
Mappage de source du package
Consommateur de packages 📦
Le mappage de source de package vous permet de déclarer de manière centralisée la source à partir de laquelle chaque package de votre solution doit être restauré dans votre fichier nuget.config.
Pour activer le mappage de source de package, consultez la documentation suivante.
Sécuriser les ordinateurs
Autorisations d’annuaire
Consommateur de packages 📦
Sur Windows, Mac et certaines distributions Linux, les répertoires de base de compte d’utilisateur sont privés par défaut. Toutefois, certaines distributions Linux rendent par défaut les répertoires utilisateur lisibles par d’autres comptes sur le même ordinateur. En outre, il existe plusieurs options de configuration pour rediriger le dossier de packages globaux NuGet et le cache HTTP vers des emplacements autres que ceux par défaut. Les solutions, projets et référentiels peuvent également être créés en dehors du répertoire de base de l’utilisateur.
Si vous utilisez des packages qui ne se trouvent pas sur nuget.org, si un autre compte sur l’ordinateur peut lire les packages globaux NuGet ou les répertoires de cache HTTP, ou le répertoire de sortie de build du projet, ces packages peuvent être divulgués à des personnes qui ne sont pas censées avoir accès à ces packages.
Sur Linux, dotnet nuget update source
modifie les autorisations du fichier nuget.config pour qu’il soit lisible uniquement par le propriétaire du fichier.
Toutefois, si vous modifiez le fichier nuget.config d’une autre façon et que le fichier se trouve dans un emplacement où d’autres comptes peuvent le lire, il peut y avoir une divulgation d'informations sur l’URL source du package ou les informations d’identification de la source du package.
Vous devez vous assurer qu’aucun fichier nuget.config ne peut être lu par d’autres utilisateurs du même ordinateur.
Solutions dans le répertoire des téléchargements
Consommateur de packages 📦
Des précautions supplémentaires doivent être prises si vous travaillez sur des solutions ou des projets dans votre répertoire de téléchargements. NuGet accumule les paramètres à partir de plusieurs fichiers de configuration, et MSBuild importe généralement Directory.Build.props, Directory.NuGet.props, Directory.Build.targets et potentiellement d’autres fichiers, à partir de n’importe quel répertoire parent jusqu’à la racine du système de fichiers.
Le dossier des téléchargements présente un risque supplémentaire, car il s’agit généralement de l’emplacement par défaut auquel les navigateurs web téléchargent les fichiers d’Internet
Agents de build
Consommateur de packages 📦
Les agents de build (agents CI) qui ne sont pas réinitialisés à un état initial après chaque build présentent plusieurs risques qui doivent être pris en compte.
Pour en savoir plus sur les méthodes sécurisées de gestion des informations d’identification, consultez la documentation sur l’utilisation de packages à partir des flux authentifiés.
Pour en savoir plus sur la modification des répertoires dans lesquels NuGet stocke des données, consultez la documentation sur la gestion des packages globaux, du cache et des dossiers temporaires. Ces répertoires doivent être configurés sur un répertoire que l’agent CI nettoie après chaque build.
Notez que tous les packages utilisés par votre projet peuvent être laissés dans le répertoire de sortie de build de votre projet. Si votre projet utilise des packages de sources authentifiées, d’autres utilisateurs du même agent CI peuvent obtenir un accès non autorisé aux assemblys de package. Par conséquent, vous devez également nettoyer votre référentiel à la fin de votre build, même lorsque la build échoue ou est annulée.
Surveiller votre chaîne d’approvisionnement
Analyse du secret GitHub
Auteur de package 📦🖊
GitHub analyse les clés API NuGet dans les référentiels pour éviter une utilisation frauduleuse des secrets accidentellement commités.
Pour en savoir plus sur l’analyse des secrets, consultez À propos de l’analyse des secrets.
Signature d’auteur de package
Auteur de package 📦🖊
La signature de l’auteur permet à un auteur de package d’appliquer une empreinte sur un package. Cela permet au consommateur de vérifier qu’il provient bien de vous. Cela vous protège contre la falsification de contenu et sert de source unique de vérité sur l’origine et l’authenticité du package. Lorsque vous combinez des stratégies de confiance client, vous pouvez vérifier qu’un package provient d’un auteur spécifique.
Pour appliquer une signature d’auteur sur un package, consultez Signer un package.
Générations reproductibles
Auteur de package 📦🖊
Les générations reproductibles créent des fichiers binaires identiques octet-pour-octet à chaque fois que vous le générez. Ces fichiers contiennent des liens de code source et des métadonnées du compilateur qui permettent au consommateur de package de recréer directement le fichier binaire et de vérifier que l’environnement de génération n’a pas été compromis.
Pour en savoir plus sur les générations reproductibles, consultez Production de packages avec des liens source et les spécifications de Validation de génération reproductible.
Authentification à 2 facteurs (2FA)
Auteur de package 📦🖊
Tous les comptes sur nuget.org doivent activer l’A2F. L’A2F ajoute une couche de sécurité supplémentaire lors de la connexion au compte GitHub ou NuGet.org.
Réservation du préfixe d’ID de package
Auteur de package 📦🖊
Pour protéger l’identité de vos packages, vous pouvez réserver un préfixe d’ID de package à l’aide de votre espace de noms respectif pour associer un propriétaire correspondant si votre préfixe d’ID de package se trouve correctement sous les critères spécifiés.
Pour en savoir plus sur la réservation de préfixes d’ID, consultez Réservation de préfixe d’ID de package.
Dépréciation et retrait d’un package vulnérable
Auteur de package 📦🖊
Pour protéger l’écosystème de package .NET, faites de votre mieux pour déprécier et retirer votre package de la liste lorsque vous avez connaissance d’une vulnérabilité dans un package que vous avez créé. Cela le masquera aux utilisateurs qui recherchent des packages. Si vous consommez un package déconseillé et retiré de la liste, vous devez éviter d’utiliser ce package.
Pour savoir comment déprécier et retirer de la liste un package, consultez la documentation suivante sur la dépréciation et le retrait des packages.
Envisagez également de signaler la vulnérabilité à la base de données GitHub Advisories.
Résumé
Votre chaîne d’approvisionnement logicielle représente tout ce qui passe ou affecte votre code. Même si les compromissions de la chaîne d’approvisionnement sont réelles et de plus en plus communes, elles restent encore rares. Ainsi, la chose la plus importante que vous pouvez faire est de protéger votre chaîne d’approvisionnement en connaissant vos dépendances et en les gérant , et en surveillant votre chaîne d’approvisionnement.
Vous avez découvert les différentes méthodes proposées par NuGet et GitHub qui sont aujourd'hui disponibles pour visualiser, gérer et contrôler plus efficacement votre chaîne d'approvisionnement.
Pour plus d’informations à propos de la sécurisation des logiciels du monde, consultez le Rapport de sécurité « The State of the Octoverse 2020 ».