En décembre 2020, SolarWinds a révélé que son produit Orion avait fait l’’objet d’’une cyberattaque à grande échelle, par laquelle les assaillants sont parvenus à accéder à l’’infrastructure de nombreux clients de SolarWinds, dont plusieurs agences gouvernementales. L’’ampleur de cette violation a suscité une vive attention concernant les vulnérabilités de la chaîne d’’approvisionnement, ainsi que le rôle de la dépendance vis-à-vis de tiers dans la sécurité d’’un système logiciel. Bien qu’’aucune de ces menaces ne soit inédite, le regain de vigilance accordé à ce domaine au vu des événements actuels a fait naître chez les organisations un fort désir d’’améliorer leur posture de sécurité dans l’’espoir de ne pas êtredevenir la prochaine cible. En tant qu’’équipe d’’ingénierie logicielle, votre interaction la plus fréquence avec la chaîne d’’approvisionnement concerne le choix des bibliothèques externes destinées à être intégrées à vos applications.
Une bibliothèque externe bien maintenue peut représenter un atout considérable pour les initiatives de développement : elle permet d’’économiser d’’innombrables heures de travail pour les ingénieurs, en vous permettant de vous concentrer sur les principaux facteurs de différenciation de votre propre produit, plutôt que de devoir réimplémenter des fonctionnalités communes. À l’’inverse, les bibliothèques dont la mise en œuvre est défaillante peuvent être difficiles à utiliser, introduire des vulnérabilités en matière de sécurité qui créent des risques pour votre organisation et vos clients, voire dans certains cas extrêmes, interférer avec le fonctionnement de parties non liées à votre service ou compromettre à mal l’’ensemble de votre architecture. Je vais présenter ici un grand nombre des considérations que j’’ai utilisées pour évaluer les bibliothèques du point de vue de la robustesse de leurs pratiques techniques et de leurs implications probables en matière de sécurité. Ces approches ont vocation à êtreconstituer des points de départ et non à imposer de quelconques prescriptions. Trouvez une approche qui réponde à vos propres besoins. Bien qu’’il n’’existe dans ce domaine aucune solution miracle, le fait de vous assurer que votre projet repose uniquement sur des dépendances de haute qualité peut réduire considérablement votre surface de vulnérabilité et rendre votre produit à la fois plus facile à développer et à maintenir.
Portée de la bibliothèque
Cet examen initial est essentiel, car il permet de déterminer si une évaluation approfondie est nécessaire ou appropriée. Quelle est la fonctionnalité de la bibliothèque ? Quelle est l’’importance de cette fonctionnalité au regard du fonctionnement de votre produit ? Une bibliothèque simple, dont l’’encombrement est réduit, nécessite beaucoup moins d’’attention qu’’une vaste infrastructure étroitement intégrée à votre propre code. De plus, certains indicateurs qui seraient des signaux d’’alerte majeurs pour une fonctionnalité clé (par exemple, des mises à jour peu fréquentes) peuvent au contraire être normaux ou escomptés dans le cas de petites bibliothèques uniquement destinées à accomplir une tâche extrêmement réduite.
Une question annexe concerne le mode d’’exploitation prévu de cette bibliothèque. Les dépendances de développement (par exemple un outil d’’analyse statique, ou un composant extrait d’’un cadre de test unitaire) présentent beaucoup moins de risques que les dépendances d’’exécution. Si les défaillances de votre pipeline de construction sont susceptibles de retarder la sortie d’’une version ou de causer d’’autres problèmes à court terme auxpour les développeurs, elles n’’ont aucune incidence directe sur les utilisateurs et ne constituent généralement pas un risque du point de vue de la sécurité de l’’application en elle-même.
Historique de maintenance
Le moyen le plus rapide d’’évaluer l’’état de santé général d’’un projet est d’’examiner l’’historique de contrôle de ses sources. Quand la dernière version a-t-elle été publiée ? À quelle fréquence les versions sont-elles publiées, et quel est le taux de validations dans le référentiel du code source ? J’’aime que des projets soient mis à jour fréquemment, car cela me donne davantage confiance dans la probabilité que la bibliothèque continuera à être maintenue à l’’avenir. À l’’inverse, un projet resté en sommeil pendant une longue période peut contenir des bogues non corrigés, ou donner lieu à des problèmes de compatibilité avec les nouvelles versions des dépendances communes, voire avec le moteur d’’exécution du langage lui-même.
Il est également très utile de consulter le journal des modifications d’’une bibliothèque. Les changements introduits au fil des versions sont parfois décrits sur la page correspondante. Dans certains autres cas, le journal des modifications est un fichier situé au niveau supérieur du référentiel du code source. Si cette information n’’est pas aisément accessible, c’estil s’agit d’un signal important qui appelle à la vigilance. Je cherche à obtenir des descriptions claires de ce qui a été modifié d’’une version à l’’autre et à savoir si les incompatibilités en amont ont été clairement documentées. Toutefois, une fréquence élevée de changements incompatibles avec les versions précédentes, ou de corrections de bogues dans les fonctionnalités de base, estconstitue en soi une source d’’inquiétude car elle suggère que le développeur a failli dans son travail de planification et de débogage des modifications avant publication.
Relations avec les responsables de la maintenance
Une évaluation plus approfondie peut consister à examiner le suivi des problèmes d’’un projet et d’’autres canaux de communication publics. Dans quelle mesure les responsables de la maintenance sont-ils à l’’écoute des utilisateurs ? Sont-ils cordiaux et réceptifs aux commentaires, ou adoptent-ils plutôt un ton pugnace ? Quel est le ratio de dossiers ouverts et de dossiers clos ? Les responsables répondent-ils activement aux préoccupations des utilisateurs, ou les rapports de bogue restent-ils en suspens durant de longues périodes ? La documentation est-elle complète et oriente-t-elle efficacement l’’utilisateur vers les meilleures pratiques de mise en œuvre ? Existe-t-il des preuves de l’’existence d’’une communauté dynamique autour de ce projet ? Par exemple, est-ce au responsable principal qu’’incombe entièrement la charge de l’’assistance aux utilisateurs, ou d’’autres membres de la communauté sont-ils désireux et capables d’’en prendre au moins partiellement le relais ? Un projet qui donne lieu à une relation saine avec sa communauté a beaucoup plus de chances de répondre aux besoins spécifiques des utilisateurs et de s’’adapter rapidement à un environnement en pleine évolution.
Dépendances transitives
Cette évaluation demande certes un peu plus d’’efforts que le simple comptage de la fréquence des publications, mais elle fournit une mine d’’informations. La première chose que je veux comprendre, c’’est le nombre de dépendances supplémentaires sur lesquelles s’’appuie une bibliothèque, et en particulier si elle fait appel à des dépendances inutiles. Les dépendances qui fournissent une fonctionnalité clé pour une bibliothèque sont beaucoup moins préoccupantes que le fait de faire appel à de nombreuses bibliothèques supplémentaires pour des tâches sans rapport entre elles. Chaque dépendance additionnelle signifie une complexité accrue et un risque supplémentaire pour la chaîne d’’approvisionnement. En cas de doute, un outil d’’évaluation simple consiste à installer la bibliothèque dans un conteneur docker et à noter combien de bibliothèques supplémentaires sont ajoutées au cours du processus.
Dans cette catégorie, la plus grande préoccupation est la facilité avec laquelle les dépendances sont actualisées à mesure que de nouvelles vulnérabilités sont découvertes. Pour cette raison, un élément important de l’’évaluation consiste à noter si une dépendance est restrictive (c’’est-à-dire, satisfaite uniquement par une version spécifique d’’une bibliothèque) ou permissive (satisfaite par une gamme de versions). Les dépendances restrictives constituent une préoccupation majeure, car elles peuvent rendre les efforts de correction difficiles, voire nous obliger à déclasser des bibliothèques dont nous dépendons pour d’’autres fonctionnalités. Il est également important de savoir dans quelle mesure ces dépendances transitives sont à jour. Une dépendance versionnée qui spécifie une version vieille de deux mois est beaucoup moins préoccupante que si elle référence une version remontant à deux ans. Dans le même ordre d’’idées, l’’un des signes qui évoquent un projet bien géré est la présence d’’un historique des actualisations fréquentes qui maintiennent les dépendances à jour.
Dépendances des langages de programmation
Méfiez-vous tout particulièrement des paquets écrits dans un certain langage et qui comportent des dépendances supplémentaires dans un autre langage (par exemple des bibliothèques Python liées à des extensions C compilées en interne). Si les dépendances secondaires impliquent un langage ou un environnement de programmation que vous connaissez moins bien, il vous sera plus difficile d’’évaluer leur qualité globale. De plus, les différents langages supposent souvent des conventions d’’empaquetage différentes. Or, les responsables de la maintenance de projets mixtes ne maîtrisent pas toujours les règles de bonne pratique de tous les langages de programmation qu’’ils utilisent, ce qui rend les mises à jour et les correctifs encore plus compliqués.
Bibliothèques cryptographiques
Les bibliothèques cryptographiques méritent une attention particulière en raison de la complexité algorithmique qu’’elles impliquent, ainsi que de l’’impact élevé de leurs vulnérabilités potentielles. Examinez ces bibliothèques avec une attention particulière et assurez-vous de vous fier exclusivement à des bibliothèques qui ont fait l’’objet d’’une évaluation approfondie et reposent sur une longue expérience. Parmi les choix sûrs, citons OpenSSL pour C et C++, BouncyCastle pour Java et la bibliothèque cryptographique de PyCA pour Python. Vos options peuvent être limitées par la politique de sécurité ou les exigences de conformité de votre entreprise. Soyez au fait des vulnérabilités connues des bibliothèques cryptographiques et informez-vous régulièrement des nouvelles versions. Parmi toutes vos dépendances tierces, ce sont celles qui ont la plus grande incidence en termes de sécurité.
Qualité du code et de la documentation
Cette section et la suivante concernent des évaluations nécessitant un niveau d’’effort élevé, mais celui-ci est parfois justifié dans les cas à haut risque. Lorsque je veux me faire une idée de la qualité globale du code d’’un projet, j’’essaie de trouver un code source qui exploite une fonctionnalité dont je connais déjà en profondeur les caractéristiques, et j’’évalue la qualité d’’écriture de cette partie réduite de la base de code. Parfois, j’’examine la qualité de la documentation du projet, en me concentrant sur la clarté du rédacteur et sa capacité à communiquer efficacement des concepts complexes. Dans un cas comme dans l’’autre, l’’objectif est de déterminer si les responsables font preuve d’’une grande attention aux détails ou s’’ils ont plutôt tendance à prendre des raccourcis. On s’’attend ici à ce que le degré de soin apporté à une partie du projet soit représentatif de l’’état de l’’ensemble.
À titre d’’exemple concret, si j’’ai choisi d’’examiner la gestion du protocole SSL par un projet Python, je peux remarquer ce qui suit :
- Les développeurs utilisent-ils les paramètres de connexion SSL par défaut, ou essaient-ils de les personnaliser pour obtenir des paramètres plus sûrs ?
- S’’ils font des adaptations, dans quelle mesure les changements sont-ils judicieux ?
- Permettent-ils à l’’utilisateur d’’effectuer des personnalisations supplémentaires ?
- S’’ils autorisent les personnalisations, réutilisent-ils les objets SSLContext de la bibliothèque standard de Python ou essaient-ils de réinventer la roue ?
Dans une évaluation comme celle-ci, je veux voir des principes de conception solides, la réutilisation d’’idiomes standard, et m’’assurer que l’’auteur puisse prévoir les besoins potentiels des utilisateurs et fournir une extensibilité appropriée pour y répondre.
Traitement des vulnérabilités
Je l’’ai listé cet élément en dernier car il s’’agit généralement d’’une impression que je me forge au fil du temps et qui peut être moins utile pour une première évaluation. Cela dépend aussi fortement de l’’ampleur de l’’utilisation et de la pertinence de la sécurité d’’une bibliothèque particulière. Néanmoins, cela peut certainement être un facteur dans la décision de continuer à utiliser une bibliothèque existante ou d’’essayer de migrer vers un remplacement.
En d’’autres termes, j’’essaie d’’évaluer la réactivité du responsable du projet en matière de correction des vulnérabilités et la facilité avec laquelle nous pouvons bénéficier de ces correctifs dans nos propres déploiements. Un projet qui fait fréquemment l’’objet de divulgations de vulnérabilités est quelque peu inquiétant, mais il pourrait tout aussi bien s’’agir d’’un facteur de large utilisation et de pertinence en matière de sécurité plutôt que de la qualité globale du code et des pratiques de maintenance. Un meilleur indicateur est l’’action qui est adoptée lorsqu’’une vulnérabilité a été découverte. Les correctifs sont-ils intégrés rapidement aux nouvelles versions ? Est-il facile d’’effectuer une mise à niveau lorsque des versions corrigées sont publiées ? Si le projet apporte souvent des changements radicaux, notamment s’’il rompt régulièrement la rétrocompatibilité, retransfère-t-il les correctifs aux anciennes versions ? Si la bibliothèque fait partie d’’une distribution Linux, la responsabilité du rétroportage des correctifs incombe généralement aux mainteneurs de la distribution plutôt qu’’au développeur d’’origine, mais les mêmes questions peuvent s’’appliquer à la façon dont l’’empaqueteur gère la bibliothèque (les distributions font souvent une distinction entre les paquets principaux avec une maintenance active et les paquets plus périphériques, qui suivent généralement les versions amont avec des modifications minimales appliquées).
Lorsqu’’une bibliothèque fait preuve d’’une mauvaise gestion des vulnérabilités ou fonctionne d’’une manière qui rend difficile l’’utilisation des correctifs de sécurité, je recommande souvent à mon équipe de migrer vers une autre bibliothèque.
Conclusions
L’’évaluation de la qualité globale d’’un projet logiciel et de la communauté qui l’’entoure est une compétence essentielle qui ne fera que gagner en pertinence à mesure que les projets logiciels deviendront plus interdépendants. Il s’’agit également d’’une compétence très individuelle ; vous obtiendrez souvent les meilleurs résultats en étudiant les décisions prises par les responsables des bibliothèques dans vos domaines d’’expertise. Étant donné que la validation complète de chaque détail d’’un fournisseur potentiel est une tâche encore plus difficile que de construire la fonctionnalité soi-même, le processus d’’évaluation consiste à établir un degré de confiance et à prendre des mesures pour s’’assurer que cette confiance n’’est pas mal placée. En fin de compte, apprendre à contrôler les dépendances de tiers estconstitue un élément important de la mise en place d’’une culture d’’ingénierie qui prend en charge la sécurité et la fiabilité de votre produit.
À propos de l’’auteur
Jacob Emmert-Aronson est ingénieur principal au sein de l’’équipe Mindmeld, qui fait partie de l’’organisation Webex Intelligence. C’’est un expert en matière de sécurité informatique, de DevOps et de maintenance des logiciels, et sa spécialité consiste à comprendre de quelle manière ces sujets se croisent.
Vous souhaitez rejoindre l’’équipe MindMeld ? Envoyez un e-mail à mindmeld-jobs@cisco.com
Consultez notre page d’’accueil ou contactez-nous directement pour obtenir une assistance.
Cliquez ici pour en savoir plus sur les offres de Webex et créer un compte gratuit.