L’un des domaines prioritaires pour le développement de PVS-Studio est de couvrir les catégories du Top Ten 2017 de l’OWASP dans l’analyseur C#. Nous prévoyons également de couvrir le Top Ten 2021 à l’avenir. Le plus inhabituel pour nous est la catégorie A9:2017 : Utilisation de composants avec des vulnérabilités connues. Cette catégorie a la position A6 dans la version préliminaire de l’OWASP 2021. La mise en œuvre des règles pour cette catégorie est une tâche importante pour notre analyseur. Il nous permet de classer PVS-Studio comme un outil SCA (Software Composition Analysis). Quelle approche de mise en œuvre devrions-nous choisir? Trouvons-le !
Utilisation de composants présentant des vulnérabilités connues
La catégorie de menace A9 (devenue A6 dans la version préliminaire de l’OWASP 2021) est dédiée à l’utilisation de composants présentant des vulnérabilités connues. Ce sont les composants qui ont les entrées correspondantes dans la base de données CVE. CVE (Common Vulnerabilities and Exposures) est une base de données d’enregistrements sur les vulnérabilités réelles des logiciels, du matériel, des composants de service, etc.
A9 est assez atypique du point de vue de sa couverture en PVS-Studio. C’est parce que l’architecture existante de l’analyseur est conçue pour rechercher les erreurs dans le code lui-même. L’architecture utilise des arbres syntaxiques, des modèles sémantiques et diverses technologies telles que l’analyse des flux de données et autres. Ces technologies étaient généralement suffisantes pour mettre en œuvre des règles de diagnostic qui couvriraient certaines catégories du Top Ten 2017 de l’OWASP.
Par exemple, sur la base du mécanisme de flux de données existant, nous avons mis en place une analyse de souillure et diverses règles de diagnostic associées :
Chacune de ces règles recherche des vulnérabilités potentielles dans le code et fonctionne en parcourant un arbre syntaxique. Parallèlement, ils correspondent à une ou plusieurs catégories du Top Ten 2017 de l’OWASP. Vous pouvez trouver la liste complète des correspondances ici.
La situation avec A9 est complètement différente. Du point de vue des projets C#, l’implémentation de la règle pour A9 est une vérification de toutes les bibliothèques de dépendances de projet pour CVE. En d’autres termes, pour chaque dépendance, nous devons vérifier s’il existe une entrée correspondante dans la base de données CVE.
Cette tâche va bien au-delà du parcours habituel de l’arbre syntaxique et de l’étude de la sémantique du code. Cependant, nous sommes déterminés à couvrir cette catégorie. Par ailleurs, il est très important que la mise en œuvre de la règle A9 permette à PVS-Studio de positionner l’analyseur comme une solution SCA.
Analyse de la composition logicielle
En général, les outils SCA sont conçus pour vérifier le projet pour les dépendances problématiques.
Par exemple, si un projet dépend d’une bibliothèque open source, il est extrêmement important de prendre en compte la licence sous laquelle cette bibliothèque est distribuée. Les violations des conditions d’utilisation peuvent causer d’énormes dommages à l’entreprise.
Un autre problème possible est la présence de vulnérabilités dans la bibliothèque. Dans le contexte de SCA, nous parlons de vulnérabilités connues — CVE. Il est presque impossible de déterminer l’utilisation d’une dépendance qui contient une vulnérabilité non enregistrée :). Il n’est pas difficile de deviner que si nous utilisons une bibliothèque avec un [publicly known] vulnérabilité, nous pouvons rendre un produit vulnérable à diverses attaques.
Par ailleurs, utiliser des bibliothèques dont la maintenance a été interrompue est une approche dangereuse. Potentiellement, ces dépendances contiennent également des vulnérabilités. Cependant, les développeurs ne les connaissent probablement pas. Il est hors de question de corriger de telles vulnérabilités : personne ne le fera.
SCA et PVS-Studio
Nous arrivons progressivement à la question principale, à savoir comment implémenter la fonctionnalité SCA. Tout d’abord, nous devons dire que nous allons développer ces fonctionnalités dans le cadre de la couverture de la catégorie A9:2017 (Using Components with Known Vulnerabilities). Ainsi, nous allons rechercher les dépendances avec des vulnérabilités connues en premier lieu. Cependant, l’analyseur PVS-Studio dispose déjà de règles de diagnostic qui avertissent les développeurs des licences copyleft :
Il est possible qu’au fil du temps nous implémentions d’autres fonctionnalités SCA.
La détection des composants présentant des vulnérabilités connues se compose de deux parties. La première étape consiste à obtenir toutes les dépendances (directes et transitives) du projet, puis à rechercher les CVE qui leur correspondent. La première partie de ce plan semble simple. La deuxième partie, par contre, est plus difficile.
Pour le moment, nous prévoyons d’implémenter la fonctionnalité spécifiée pour l’analyseur C#. Il est facile d’obtenir la liste des dépendances d’un projet C#. Roslyn nous aide beaucoup — notre analyseur est construit sur sa base. Pour être plus précis, le facteur principal est l’utilisation de la même plateforme de build (MSBuild) et d’un compilateur pour tous les projets C#. Dans le même temps, Roslyn est étroitement lié à MSBuild. Cela rend l’obtention de la liste des dépendances triviale.
Étant donné que l’écosystème de C++ et Java est beaucoup plus diversifié, l’obtention de la liste des dépendances va être plus difficile. Nous le ferons une autre fois :).
Eh bien, nous avons les dépendances du projet. Comment pouvons-nous comprendre lesquels d’entre eux ont des vulnérabilités ? En outre, nous devons garder à l’esprit que la vulnérabilité peut n’être pertinente que pour des versions de bibliothèque spécifiques. Évidemment, nous avons besoin d’une sorte de base de données, où les dépendances, les versions et les CVE correspondants seraient stockés.
La question principale de la mise en œuvre : comment trouver (ou, peut-être, créer) une base de données qui nous permette de comparer les informations disponibles sur les dépendances du projet avec un CVE spécifique ? La réponse à cette question dépend des outils que vous utilisez.
Utiliser une base de données ouverte CPE
La première option que nous avons étudiée est l’approche utilisée dans OWASP Dependency Check. La démarche est simple : pour chaque dépendance, cet utilitaire recherche un identifiant correspondant dans la base de données CPE (Common Platform Enumeration). En fait, la base de données CPE est une liste contenant des informations sur les produits, leurs versions, les fournisseurs, etc. Pour implémenter SCA, nous devons obtenir les correspondances CPE et CVE. Ainsi, obtenir une liste CVE consiste simplement à rechercher l’entrée correspondante dans la base de données CPE.
Vous pouvez trouver la base de données CPE et la conformité CVE sur le site officiel National Vulnerability Database. L’un des moyens d’obtenir les informations nécessaires consiste à utiliser l’API Rest. C’est décrit ici. Par exemple, la requête suivante nous permet d’obtenir les 20 premiers éléments de la base de données CPE incluant les CVE correspondants :
https://services.nvd.nist.gov/rest/json/cpes/1.0?addOns=cves
Voici un exemple de CPE pour ActivePerl :
{
"deprecated": false,
"cpe23Uri": "cpe:2.3:a:activestate:activeperl:-:*:*:*:*:*:*:*",
"lastModifiedDate": "2007-09-14T17:36Z",
"titles": [
{
"title": "ActiveState ActivePerl",
"lang": "en_US"
}
],
"refs": [],
"deprecatedBy": [],
"vulnerabilities": [ "CVE-2001-0815", "CVE-2004-0377" ]
}
La partie la plus importante ici est la valeur « cpe23Uri ». Il contient des informations importantes pour nous dans un certain format et, bien sûr, des « vulnérabilités » (bien qu’elles ne fassent pas partie de la liste CPE). Pour plus de simplicité, nous lisons la chaîne « cpe23Uri » comme suit :
cpe:2.3:a:<vendor>:<product>:<version>:<update>:...
Selon la spécification, un trait d’union à la place de l’un des fragments signifie une valeur « NA » logique. Autant que je sache, cela peut être interprété comme « la valeur n’est pas définie ». Le caractère « * » mis à la place d’un fragment signifie « TOUT ».
Lorsque nous implémentons une solution basée sur le CPE, la principale difficulté est de trouver le bon élément pour chaque dépendance. Le problème ici est que le nom de la bibliothèque (obtenu lorsque nous avons analysé les liens du projet) peut ne pas correspondre à l’entrée CPE correspondante. Par exemple, la liste CPE contient des entrées avec le « cpe23Uri » suivant :
cpe:2.3:a:microsoft:asp.net_model_view_controller:2.0:*:*:*:*:*:*:*
cpe:2.3:a:microsoft:asp.net_model_view_controller:3.0:*:*:*:*:*:*:*
cpe:2.3:a:microsoft:asp.net_model_view_controller:4.0:*:*:*:*:*:*:*
cpe:2.3:a:microsoft:asp.net_model_view_controller:5.0:*:*:*:*:*:*:*
cpe:2.3:a:microsoft:asp.net_model_view_controller:5.1:*:*:*:*:*:*:*
Après avoir traité les entrées, l’analyseur conclut qu’elles sont toutes liées à différentes versions d’un produit portant le nom « asp.net_model_view_controller » publié par une société appelée Microsoft. Toutes ces entrées correspondent à une vulnérabilité avec l’identifiant CVE-2014-4075. Cependant, la bibliothèque dans laquelle la vulnérabilité a été découverte s’appelle « System.Web.Mvc ». Très probablement, nous obtiendrons ce nom de la liste des dépendances. Dans CPE, le nom du produit est « Microsoft ASP.NET Model View Controller ».
Par ailleurs, il faut prendre en compte le vendeur, dont l’identifiant fait partie intégrante des écritures CPE. Cela pose également des problèmes, car la dépendance réelle ne fournit pas toujours les informations nécessaires sous une forme adaptée à l’analyse. Sans parler de la conformité de ces informations avec toute entrée de CPE.
Vous pouvez deviner que des problèmes similaires surviennent avec la version de la bibliothèque.
Un autre problème est que de nombreux enregistrements dans la base de données ne sont pas pertinents lorsque nous recherchons des correspondances. Prenons comme exemple l’entrée donnée au début de cette section :
cpe:2.3:a:activestate:activeperl
ActivePerl est une distribution du langage Perl d’ActiveState. La probabilité que quelque chose comme ça soit une dépendance à un projet C#… eh bien, est faible. Il y a beaucoup d’entrées « inutiles » (dans le contexte de l’analyse de projets C#). Il est difficile de dire comment nous pouvons apprendre à l’analyseur à les distinguer des plus utiles.
Malgré les problèmes mentionnés, l’approche basée sur le CPE peut encore être efficace. Sa mise en œuvre devrait être beaucoup plus délicate qu’une simple paire de comparaisons de chaînes. Par exemple, le contrôle de dépendance OWASP fonctionne de manière intéressante. Pour chaque dépendance, cet outil collecte des chaînes de preuves qui peuvent correspondre aux valeurs du fournisseur, du produit et de la version du CPE souhaité.
Utiliser GitHub Advisory
Nous avons trouvé une autre approche pour rechercher des CVE. Nous enquêtons sur GitHub Advisory pour trouver les entrées qui correspondent à la dépendance que nous devons vérifier. GitHub Advisory est une base de données de vulnérabilités (CVE) découverte dans des projets open source stockés sur GitHub. La liste complète des postes est disponible ici.
Après nous être familiarisés avec le CPE, nous avons compris que la méthode d’enregistrement des données est extrêmement importante lorsque nous choisissons la source de données. Nous devons admettre que dans ce cas, GitHub Advisory est beaucoup plus pratique que CPE. Peut-être que cette base de données a été créée à l’origine pour être utilisée par divers outils SCA. Quoi qu’il en soit, diverses solutions comme GitHub SCA et SCA de Microsoft utilisent cette base de données.
Pour un accès programmatique à GitHub Advisory, nous devons utiliser GraphQL. C’est une technologie puissante, mais nous devons noter qu’il est beaucoup plus facile de comprendre l’API Rest. Néanmoins, épuisé par l’explorateur GraphQL de GitHub, j’ai finalement réussi à faire une requête qui renvoie presque ce que je voulais. À savoir, il génère une liste de packages et des CVE correspondants. Voici un des éléments que j’ai reçu :
{
"identifiers": [
{
"value": "GHSA-mv2r-q4g5-j8q5",
"type": "GHSA"
},
{
"value": "CVE-2018-8269",
"type": "CVE"
}
],
"vulnerabilities": {
"nodes": [
{
"package": {
"name": "Microsoft.Data.OData"
},
"severity": "HIGH",
"vulnerableVersionRange": "< 5.8.4"
}
]
}
}
Évidemment, je n’ai pas fait la requête la plus optimale, j’ai donc obtenu un peu d’informations supplémentaires à la sortie.
Si vous êtes un expert en GraphQL, veuillez écrire dans les commentaires comment vous construirez une requête qui vous permettra d’obtenir une liste de…