Principaux enseignements
- Le remplacement de la source de chargement suppose que l'élément de remplacement concerne le même contenu de caisse ; c'est pourquoi aucune modification du fichier de projet n'est nécessaire.
- Le tri effectué par le registre évalue une caisse en fonction de son contenu plutôt qu’en fonction de la réputation de son nom.
- Le chemin de vérification est un
.cargo/config.tomlmodification, sans modification deCargo.tomlouCargo.lock. - Les caisses « patched » constituent une exception, et le fait d'opter pour l'une d'entre elles représente un changement délibéré et manifeste.
Faire confiance à crates.io par défaut est rarement un choix délibéré. C'est simplement le réglage par défaut – jusqu'à ce que quelqu'un s'y intéresse de près. La question qui se pose alors généralement est de savoir quelle alternative adopter, et c'est là qu'un registre Cargo privé cesse d'être une solution évidente.
Ce terme recouvre au moins trois configurations différentes, et Cargo les traite de manière suffisamment distincte pour que le choix d'une configuration inadaptée entraîne des problèmes par la suite. L'une d'entre elles ne nécessite aucune modification de vos fichiers de projet. Une autre implique de modifier chaque manifeste déclarant les dépendances que vous souhaitez rediriger. La plupart des équipes ne parviennent à distinguer les unes des autres qu'une fois qu'elles sont déjà bien avancées dans leur tentative.
Il convient de signaler une exception avant toute autre chose, car c'est celle qui est découverte le plus tard. La vérification ne nécessite aucune modification du fichier de projet. Ce n'est pas le cas des crates patchées, et le fait d'opter pour l'une d'entre elles implique toujours une modification délibérée.
Ce que recouvre généralement un registre privé de fret
Trois approches sont abordées sous une même rubrique : le « vendoring », le remplacement de source (mirroring) et les registres alternatifs, y compris privés. La documentation de Cargo distingue le remplacement de source d'un registre privé, plutôt que de le considérer comme un type particulier de registre privé.
| Architecture | Le contenu peut différer de celui de crates.io | Nécessite des modifications dans le fichier Cargo.toml |
|---|---|---|
| Ajout de fichiers dans le référentiel | Oui, c'est à toi | Non, mais cela ajoute un vendor/ répertoire |
| Miroir de remplacement d'origine | Non, ça doit être la même chose | Non |
| Registre alternatif | Oui | Oui, par dépendance |
Le remplacement de la source est celui qui permet d'affirmer qu'il n'y a pas de changement dans le flux de travail, et cela s'explique par le fait que Cargo part du principe que le contenu des crates est identique des deux côtés.
La fonctionnalité de remplacement des sources de cargaison est conçue pour les miroirs. Elle part du principe que le fichier de remplacement contient les mêmes sources que l'original et n'autorise pas l'ajout de caisses que l'original ne contient pas. Il est important d'être précis sur ce point, car c'est là que de nombreuses descriptions de vendeurs vont trop loin.
Cargo ne revient pas en arrière pour vérifier si le remplacement correspond bien aux données de crates.io. Ce qui assure le respect des règles dans un projet réel, c'est Cargo.lock, car une somme de contrôle déjà enregistrée à cet endroit ne correspondra pas à une caisse dont le contenu a changé, et la compilation échouera au lieu d'accepter discrètement le substitut.
Cela ressemble à une contrainte. Or, pour un miroir de vérification, c’est justement le but recherché : le miroir de remplacement doit fournir à votre build exactement le même contenu de crate que celui qu’il a déjà résolu.
SecureChain fonctionne selon le même principe. Il recompile les crates à partir du code source, les vérifie et s'intègre à votre configuration existante, ce qui permet aux développeurs de continuer à utiliser les mêmes commandes Cargo qu'auparavant.
Deux façons dont Cargo vous permet de rediriger vos caisses
Le fichier de remplacement se trouve dans .cargo/config.toml et ne modifie en rien votre projet.
[source.crates-io]
replace-with = "securechain"
[source.securechain]
registry = "<your SecureChain registry index URL>"
Le registre alternatif constitue l'autre mécanisme, et son fonctionnement est, par nature, différent.
[registries.securechain]
index = "<your SecureChain registry index URL>"
Avec un registre alternatif, chaque dépendance doit le nommer.
[dependencies]
serde = { version = "1.0", registry = "securechain" }
Il s'agit d'une modification à effectuer pour chaque dépendance dans tous les manifestes déclarant l'une de ces crates, ce qui correspond exactement au coût de migration que la méthode de remplacement de la source permet d'éviter.
Retour à la réalité : un fournisseur qui affirme à la fois proposer des crates modifiées et que rien ne change dans vos fichiers de projet décrit une fonctionnalité que le remplacement standard des sources par Cargo ne prend pas en charge. Demandez quel est le mécanisme utilisé par l’intégration, et le reste de l’évaluation deviendra beaucoup plus simple.
Pourquoi le remplacement des sources permet de conserver la validité de votre fichier de verrouillage
La première question que se pose un ingénieur Rust rigoureux est de savoir si Cargo.lock interruptions. Ce n'est pas le cas dans le chemin de vérification, et la raison est importante, car c'est également l'argument le plus solide dont on dispose.
A .crate Le fichier est une archive tar compressée contenant le code source du crate. La vérification de la somme de contrôle effectuée par Cargo confirme que l'archive téléchargée correspond à la somme de contrôle attendue d'après les métadonnées du registre et le fichier de verrouillage, et c'est tout ce qu'elle fait. Elle ne recompile rien. Les étapes indépendantes de recompilation et de comparaison ont lieu en amont, sur un service tel que SecureChain, avant même qu'un crate ne soit mis à disposition via la source de remplacement.
Lorsqu'une recompilation s'écarte de l'artefact publié, cette divergence devient un élément à examiner plutôt qu'un détail ignoré en silence. Une divergence ne constitue pas en soi une preuve d'altération, car elle peut également résulter de particularités de l'empaquetage ou d'étapes de publication non reproductibles. L'important est qu'elle soit mise en évidence au lieu de passer inaperçue.
La propriété utile n'est donc pas que la vérification soit invisible. C'est plutôt que les crates vérifiées arrivent sans modification, tandis que tout élément inattendu devient visible au lieu d'être accepté en silence.
rm -rf ~/.cargo/registry
cargo build --locked
Si le cache du registre est vide et que, de plus, --locked permet d'obtenir une compilation réussie avec votre code inchangé Cargo.lock, la compatibilité est démontrée dans votre environnement et non sur une diapositive. --locked C'est cet indicateur qui importe ici, car il provoque un échec plutôt que de réécrire le fichier de verrouillage en arrière-plan. C'est le fait de vider d'abord le cache qui oblige à récupérer chaque crate et à vérifier à nouveau sa somme de contrôle.
Conseil de pro : Lancez le projet pilote avec --locked et --offline en plusieurs étapes distinctes. --locked prouve que le fichier de verrouillage existant peut être utilisé tel quel. --offline vérifie que la compilation s'effectue sans autre accès au réseau. Pour vous assurer qu'aucun fichier n'a été récupéré directement depuis crates.io, utilisez la journalisation des sorties ou une règle de pare-feu (voir la phase 4) plutôt que de vous fier à --offline seul.
Ce que le dépistage permet de détecter et ce qu'il ne permet pas de détecter
Un registre privé de fret justifie son existence face à deux menaces liées, dont aucune ne peut être écartée par une simple vérification d'un nom ou d'une somme de contrôle.
Le premier est l'usurpation d'identité, qui consiste à publier une « crate » sous un nom suffisamment proche d'un nom populaire pour qu'une faute de frappe ou un coup d'œil rapide à un Cargo.toml, parvient quand même à l'installer. Le deuxième cas est celui de la « prise de contrôle » : une bibliothèque à laquelle on fait confiance depuis des années change de mains, soit parce que son responsable se retire, soit à la suite d'un piratage de compte ou d'un transfert de propriété discret, et commence alors à diffuser un contenu différent sous un nom auquel votre équipe fait déjà confiance.
Aucun des deux ne repose sur une ligne de code vulnérable se trouvant quelque part dans un arbre de dépendances. Tous deux reposent sur le modèle par défaut de crates.io, où n'importe qui peut publier, et où un nom et son historique ne donnent aucune indication sur qui en a actuellement le contrôle.
Le filtrage effectué avant qu’un crate n’atteigne votre environnement de compilation vise précisément cet objectif. Le crate est recompilé à partir du code source et vérifié par rapport à des modèles de logiciels malveillants connus et à des comportements suspects ; il est ainsi évalué sur la base de son propre contenu, plutôt que de bénéficier d’une confiance par défaut liée à son nom. Cela réduit considérablement les risques. Cela ne garantit pas que tous les crates malveillants seront identifiés, et tout fournisseur qui ferait une telle promesse ferait de la publicité mensongère.
Il ne s'agit pas non plus d'une garantie que rien dans votre build n'exécutera jamais de code arbitraire. La vérification a lieu avant l'arrivée du crate. Une fois qu'il se trouve dans votre arborescence, votre propre cargo build fonctionne comme d’habitude.
| Couche | Qui se charge de le filtrer ou de le mettre en sandbox ? | Ce qu'il capture |
|---|---|---|
| Créer un dossier dans le registre avant l'installation | Le registre | Usurpation d'identité, prise de contrôle, modèles de logiciels malveillants connus |
Le vôtre cargo build |
Cargo ne le met pas en mode sandbox | build.rs et les macros proc continuent de s'exécuter à moins que vous n'ajoutiez un isolateur externe |
Comment les « patched crates » modifient l'intégration
C'est également à ce stade que la prise de contrôle cesse d'être une simple question de filtrage. Une caisse dont la propriété change discrètement de mains ne constitue pas un problème ponctuel de détection. Il s'agit d'une faille de maintenance persistante, et le filtrage d'une seule version ne suffit pas à la combler.
La poursuite de la correction des crates abandonnés par la communauté en amont constitue une offre distincte de la vérification, et elle donne lieu à des crates dont le contenu diffère délibérément de celui publié par crates.io. Un contenu différent implique des sommes de contrôle différentes, et le remplacement du code source rejette, par principe, tout ce qui ne correspond pas.
L'application de correctifs est donc soumise à une acceptation explicite pour chaque crate. Pour une dépendance déclarée dans votre propre manifeste, il suffit d'indiquer le nom du registre alternatif.
[dependencies]
abandoned-crate = { version = "1.2.4", registry = "securechain" }
Pour une crate qui n'apparaît que de manière transitive, cette déclaration n'a aucun effet, car elle ne concerne que la seule dépendance que vous avez indiquée. Une déclaration de niveau supérieur [patch] La redéfinition est le mécanisme prévu pour le cas transitif.
[patch.crates-io]
abandoned-crate = { version = "1.2.4", registry = "securechain" }
Parmi Cargo.toml sur les manifestes, « Cargo » indique [patch] uniquement à partir de celui situé à la racine de l'espace de travail, et de là, il s'applique à l'ensemble du graphe de dépendances. Il peut également se trouver dans .cargo/config.toml, même si la documentation de Cargo vous déconseille cette pratique pour tout élément partagé, car les fichiers de configuration ne sont généralement pas intégrés au système de contrôle de version.
Concrètement, un déploiement réel s'articule donc sur deux niveaux.
| Besoin | Mécanisme | Modifications apportées au fichier de projet |
|---|---|---|
| Caisses vérifiées, non modifiées | Remplacement de la source | Aucun |
| Caisses abandonnées rafistolées | Registre alternatif ou [patch] |
Une petite entrée explicite par caisse |
Il y a une chose que ce tableau ne mentionne pas et qui mérite d’être soulignée. Le fait d’opter pour une « crate » modifiée peut modifier la source et la somme de contrôle enregistrées dans Cargo.lock, ce qui entraîne la mise à jour du fichier de verrouillage ; cette mise à jour doit être validée et révisée comme n'importe quelle autre modification de dépendance. La vérification ne modifie pas le fichier de verrouillage, contrairement à l'application d'un correctif.
C'est une solution plus satisfaisante qu'une affirmation générale, car un acheteur de services de sécurité peut ainsi évaluer le coût des corrections avant de signer quoi que ce soit. Demander une petite modification ciblée pour chaque conteneur qu'il choisit de faire corriger est une demande raisonnable. En revanche, découvrir en cours de projet pilote que chaque manifeste doit être modifié ne l'est pas.
Les audits de bases de code du secteur rapportés par SC Media ont révélé que 93 % des bases de code analysées contenaient des composants n’ayant fait l’objet d’aucune activité de développement au cours des deux dernières années. Pour celles qui sont véritablement abandonnées au sein de ce groupe, il n’y a plus de responsable en amont pour publier une version corrigée, et le « backporting » implique de reconstruire le contexte à partir de zéro. Il faut reproduire le bogue, écrire un correctif qui ne modifie pas le comportement dont tout le monde dépend, puis le valider sans pouvoir s’appuyer sur l’examen ou le jugement d’un responsable de maintenance actif. La position de TuxCare avec SecureChain consiste ici à assurer une gestion à long terme plutôt qu’à se substituer au développement en amont, ce qui explique pourquoi ces deux fonctionnalités s’intègrent différemment.
Mise en place
Quatre phases, organisées de manière à ce que chacune apporte des éléments probants avant que la suivante n'élargisse le champ d'application.
| Phase | Action | Ce que cela prouve |
|---|---|---|
| 1 | Remplacer la source sur un service, vider le cache | Les sommes de contrôle sont toujours valides |
| 2 | cargo build --offline après la phase 1 |
La compilation s'effectue en utilisant uniquement ce qui a déjà été récupéré lors de la phase 1 |
| 3 | Déploiement vers CI sur l'ensemble des dépôts | Quels pipelines comportaient une configuration de source codée en dur ? |
| 4 | Bloquer l'accès à l'index public de crates.io et aux points de terminaison de téléchargement | Ce qui contournait discrètement la configuration |
C'est au cours de la phase 3 que ces déploiements tournent mal. Fusion des cargaisons .cargo/config.toml les fichiers du répertoire courant et de ses répertoires parents, puis, à défaut, $CARGO_HOME/config.toml, le fichier situé le plus en profondeur l’emportant et le répertoire racine occupant la dernière place. Une image CI peut tout de même introduire une configuration à laquelle personne ne s’attendait, et c’est le répertoire à partir duquel `cargo` a été lancé qui détermine quels fichiers sont pris en compte dans la fusion. Vérifiez la configuration effective sur le runner plutôt que de vous contenter de la déduire.
cargo +nightly -Z unstable-options config get --show-origin source
Cela indique la configuration effective de la source et l'origine de chaque valeur. Exécutez cette commande sur un agent de compilation plutôt que sur un ordinateur portable, car les deux sont généralement différents et seul l'un d'entre eux est documenté.
Remarque : Cela nécessite une exécution nocturne de Cargo avec -Z unstable-options, ce n'est donc pas quelque chose qu'il faille intégrer tel quel dans un pipeline de CI stable.
Conseil de pro : testez la phase 4 en environnement de préproduction pendant une semaine avant de basculer en production. Bloquez l’index « sparse » sur index.crates.io et les téléchargements sur static.crates.io ; si un élément de la flotte utilise encore le protocole Git, le dépôt d’index crates.io sur github.com doit également être bloqué. Les pipelines qui tombent en panne révèlent généralement des chemins dont personne ne soupçonnait qu’ils continuaient à récupérer directement depuis crates.io, et cette liste a davantage de valeur en tant que document qu’en tant qu’analyse rétrospective.
Quand un registre privé ne suffit pas à lui seul
La mise en miroir vérifiée, c'est-à-dire le remplacement de la source, résout le problème consistant à se demander « s'agit-il bien du même paquet ? ». Le crate qui se retrouve dans votre compilation est celui que votre fichier de verrouillage a déjà résolu. Cela ne vous indique pas si le crate méritait confiance au départ, et c'est précisément ce dont tirent parti les noms similaires ou les prises de contrôle de crates.
SecureChain pour Rust couvre ces deux aspects. Chaque crate est recompilée à partir du code source et son intégrité est vérifiée, puis elle fait l'objet d'un contrôle visant à détecter tout comportement malveillant ou suspect avant de vous parvenir. Ainsi, les versions victimes de typosquatting ou d'une prise de contrôle malveillante sont évaluées en fonction de leur contenu, et non pas jugées fiables sur la base de leur nom ou de leur historique.
Il continue également à corriger les éléments déjà présents dans votre pile lorsque les responsables de maintenance cessent de communiquer, et dès qu’un crate arrive en fin de vie, le service « Endless Lifecycle Support » fournit en continu les correctifs rétroportés afin qu’une dépendance abandonnée ne devienne pas, sans que personne ne s’en aperçoive, une dépendance non corrigée.
Découvrez le coût d'une couverture vérifiée et corrigée pour votre arborescence de dépendances réelle et demandez un devis.
FAQ
Qu'est-ce qu'un registre privé de fret ?
Un registre Cargo privé est un registre alternatif, interne ou géré par un fournisseur, destiné aux crates Rust. Il se distingue de l’intégration de crates dans votre dépôt via le « vendoring » et de la mise en miroir de crates.io via le remplacement de la source Cargo. Ces méthodes contrôlent d’une manière différente la provenance des crates, mais seul un registre alternatif fonctionne comme un registre privé au sens propre du terme selon Cargo.
La mise en miroir de crates.io via le remplacement des sources perturbe-t-elle le fichier Cargo.lock ?
Ce n'est pas le cas lorsque la source de remplacement fournit des crates vérifiées et non modifiées, car leur contenu est identique et les sommes de contrôle enregistrées correspondent toujours à celles de votre fichier de verrouillage existant. Les crates dont le contenu a été modifié ne peuvent en aucun cas être intégrées via le remplacement de la source.
Comment configurer le remplacement des sources dans Cargo ?
Ajouter un [source.crates-io] bloc avec replace-with en indiquant une source nommée, puis en définissant cette source à l'aide de l'URL de son index de registre, les deux dans .cargo/config.toml. Aucune modification n'a été apportée à Cargo.toml ou Cargo.lock sont nécessaires.
Le remplacement de la source permet-il de détecter les crates victimes de « typosquatting » ou de détournement ?
Le remplacement de source, à lui seul, ne suffit pas. Son rôle consiste à rediriger Cargo vers une source équivalente, tandis que le contenu de la « crate » reste inchangé. Détecter un nom similaire ou une « crate » ayant changé de propriétaire relève d'une fonction de filtrage, évaluée lors de la première reconstruction d'une « crate », puis à nouveau à chaque publication de nouvelles versions ; il ne s'agit pas d'une propriété du mécanisme de redirection.
Comment fonctionnent les crates « patched » avec Cargo ?
Le contenu des crates modifiées diffère de celui publié par crates.io ; elles ne peuvent donc pas être fournies par remplacement de source. Une dépendance directe peut pointer vers un registre alternatif, tandis qu'une dépendance de premier niveau [patch] La fonction « override » remplace la copie modifiée dans l'ensemble du graphe de dépendances, y compris les utilisations transitives. Dans tous les cas, le fichier de verrouillage enregistre la modification.
Comment puis-je vérifier moi-même l'affirmation de compatibilité ?
Effacer ~/.cargo/registry, puis exécutez cargo build --locked. Une compilation réussie avec vidage du cache, en utilisant votre fichier de verrouillage inchangé, montre que la source de remplacement est compatible avec l'ensemble des dépendances verrouillées et que les paquets téléchargés correspondent aux sommes de contrôle attendues par Cargo. L'exécution de cargo build --offline La commande « afterward » vérifie que la compilation s'est bien terminée sans autre accès au réseau ; toutefois, elle ne permet pas de vérifier la provenance des éléments déjà mis en cache. Il est donc recommandé d'utiliser la journalisation des sorties ou une règle de pare-feu à cette fin.



