Informatique fiable
Cinq ans d'apprentissage dans la création de logiciels plus sécurisés
Michael Howard
Cet article aborde les sujets suivants:
- Priorité du code en fonction de l’âge
- Utilisation d’outils d’analyse et d’automatisation
- Examen des menaces à partir d’angles multiples
- L’importance de la formation
|
Cet article utilise les technologies suivantes:
|

Sommaire
Il y a cinq ans, Bill Gates a rédigé une note à l’attention de tous les employés de Microsoft, expliquant l’importance de la création de logiciels plus sécurisés. Depuis, de nombreux employés de Microsoft ont travaillé à l’amélioration de la sécurité de leurs produits. En procédant ainsi, nous en avons appris beaucoup sur les éléments nécessaires à la création de logiciels plus sécurisés.
La sécurité n’est pas un domaine statique. Elle évolue constamment suite aux actions des attaquants, aux réactions des défenseurs et à mesure que chaque partie en apprend sur les techniques de l’autre. La sécurité est une course aux armements. Pour rester en tête et anticiper les actions des attaquants, nous devons, en tant que défenseurs, tirer les leçons de nos erreurs et créer de meilleures façons d’empêcher les utilisateurs d’être corrompus.
Alors qu’avons-nous appris au cours des cinq années passées ? La plupart de ces leçons sont tout à fait évidentes mais, comme tant de choses évidentes, il est parfois utile que quelqu’un les porte à notre attention.
Le code ne suffit pas
L’objectif essentiel de l’industrie du logiciel, ou plus précisément de l’industrie de la qualité de logiciel, est l’obtention d’un code correct. Cela ne me dérange pas particulièrement, mais la plupart des failles de sécurité ne sont pas du tout des problèmes de code. Beaucoup sont liées à des problèmes de conception. Si vous vous concentrez uniquement sur la recherche de problèmes de sécurité dans le code, vous manquerez une classe entière de vulnérabilités. C’est l’une des raisons pour lesquelles Microsoft rend obligatoire l’analyse de modélisation des menaces et surfaces d’attaque dans le cadre du Cycle de vie de développement de la sécurité (Security Development Lifecycle, SDL). La modélisation des menaces est une technique d’analyse qui contribue à identifier et à atténuer les faiblesses de conception d’un produit. L’analyse de surface d’attaque se concentre sur les portions d’un produit logiciel exposées aux utilisateurs non approuvés, qu’ils soient locaux ou distants. Un produit doté d’une grande surface d’attaque a davantage de code exposé aux utilisateurs non approuvés par rapport à un produit avec une petite surface d’attaque. (Vous trouverez plus d’informations à l’adresse
msdn.microsoft.com/msdnmag/issues/04/11/AttackSurface.)
La vulnérabilité de saturation de la mémoire tampon de RPC de DNS décrite dans le Bulletin de sécurité Microsoft MS07-029 (voir
microsoft.com/technet/security/Bulletin/MS07-029.mspx) peut autoriser un attaquant à prendre le contrôle intégral du système concerné. Il y avait certainement un problème de code dans ce cas. Cependant, le code était accessible aux utilisateurs anonymes et distants alors qu’il aurait dû être restreint aux administrateurs. Par conséquent, le problème était une combinaison de vulnérabilité de code et de conception. J’ai analysé cette vulnérabilité dans le blog SDL (voir
blogs.msdn.com/sdl/archive/2007/06/28/lessons-learned-from-ms07-029-the-dns-rpc-interface-buffer-overrun.aspx).
Leçons tirées Il est essentiel de créer des modèles de menace pour découvrir les faiblesses de conception potentielles et déterminer la surface d’attaque de votre logiciel. Vous devez vous assurer que toutes les menaces matérielles sont atténuées et que la surface d’attaque est aussi réduite que possible.
Réparez tout d’abord le code ancien
Pour ce qui a trait à la révision du code, je préfère classer le code par potentiel de vulnérabilité. J’ai écrit un article pour IEEE Security & Privacy, intitulé « A Process for Performing Security Code Reviews, » qui décrit les mesures de hiérarchisation de la révision de code (vous trouverez un lien à ce document sur mon blog à l’adresse
blogs.msdn.com/michael_howard/archive/2006/08/01/686029.aspx).
La première priorité est le code ancien, car il est beaucoup plus susceptible de comporter des failles de sécurité que le code plus récent. Les menaces évoluent constamment. Le code ancien (y compris le code généré il y a quelques années seulement) a été généré lorsque les menaces étaient différentes de ce qu’elles sont aujourd’hui. De plus, les techniques utilisées pour générer le code ancien ne disposent pas des dernières techniques et méthodes recommandées de défense. De même, le code hérité a été généré à l’aide de bibliothèques plus anciennes et moins sécurisées. Et enfin, le code ancien a été généré avec une conscience des circonstances plus réduite, à une époque où la plupart des développeurs avaient peu d’expérience en matière de sécurité, voire aucune.
Mon conseil est simple : tout code ancien doit être révisé manuellement pour trouver les failles de sécurité. Ceci est en fait l’objectif de la phase de focalisation sur la sécurité du SDL ici, chez Microsoft. Bien que l’objectif principal du SDL soit de réduire le risque d’ajout à un produit de nouvelles vulnérabilités par les développeurs, la focalisation sur la sécurité est conçue pour forcer les équipes de développement à rechercher des problèmes dans le code ancien.
Aucune autre mesure effectuée n’est aussi importante pour la hiérarchisation de la révision de code, qu’il s’agisse de la complexité du code, du nombre de lignes de code ou encore du code « churn » (couverture de code). L’indicateur principal de densité de vulnérabilité potentielle est simplement l’âge du code.
Leçons tirées Identifiez tous vos fichiers de code source et classez-les par âge, où l’âge correspond à la date de « naissance » du code. Exécutez une analyse statique et révisez manuellement le code, en commençant par le code le plus ancien.
Mettez au rebut ! Éliminez ! Éradiquez !
Parfois, une fonctionnalité peut ne pas être suffisamment sécurisée dans l’environnement de menace actuel. La fonctionnalité peut avoir été acceptable il y a quelques années, mais elle est aujourd’hui non sécurisée, non pas en raison de vulnérabilités de code, mais plutôt en raison des modifications de l’environnement informatique d’aujourd’hui.
Le service Alerter de Windows® en constitue un bon exemple : celui-ci affiche l’état de l’impression et envoie de petits messages qui apparaissent sur l’écran d’un autre utilisateur. Ceci s’est transformé très rapidement en un mécanisme indésirable, et nous avons par conséquent rapidement pris la décision radicale de désactiver par défaut le service Windows XP SP2, puis de le supprimer complètement de Windows Vista®.
Les protocoles hérités IPX et SPX constituent un autre bon exemple. (Oui, je sais que IPv4 est également ancien et possède ses propres problèmes.) Dans Windows Vista, nous avons simplement supprimé la prise en charge du client Microsoft® pour réseaux NetWare car le code était ancien et inutilisé par la plupart des utilisateurs.
Progressivement, vous constaterez que Microsoft supprime soigneusement les vieilles fonctionnalités. Puisque certains utilisateurs s’appuient sur des fonctionnalités, il est important de peser le risque face au degré d’utilité.
Leçons tirées Identifiez les fonctionnalités anciennes pouvant à long terme constituer un problème embêtant et proposez une planification de mise au rebut de ces fonctionnalités. La première étape peut être de continuer à livrer la fonctionnalité, mais de la désactiver par défaut. Ensuite, dans la version suivante du produit, la fonctionnalité peut être entièrement supprimée, mais mise à disposition sous la forme d’un téléchargement Web pour ceux qui en ont absolument besoin. Pour terminer, arrêtez la prise en charge de la fonctionnalité. N’oubliez pas de garder vos clients informés.
Les outils sont essentiels... jusqu’à un certain point
Dans le passé, j’ai été extrêmement critique en ce qui concerne les outils. En fait, ce ne sont pas les outils eux-mêmes, mais plutôt la dépendance excessive dont font preuve certains développeurs à l’égard de ces outils. Par outils, je veux parler de l’analyse de code statique, l’analyse binaire et autres, qui peuvent contribuer à isoler des failles de sécurité. En vieillissant, j’ai adopté une position plus tolérante envers ceux-ci.
Si vous avez une grande quantité de code, disons par exemple plus d’un million de lignes, il devient très difficile de réviser tout ce code manuellement. Les outils sont pratiques car ils peuvent analyser rapidement de grandes quantités de code. Les outils, cependant, ne peuvent en aucun cas se substituer à l’intellect humain, et beaucoup d’outils ont tendance à manquer des vulnérabilités car ils essaient de conserver un taux de résultats positifs et négatifs erronés aussi bas que possible. Et, pour être tout à fait honnête, beaucoup d’outils d’analyse de sécurité créent une telle quantité d’erreurs et d’avertissements qu’il peut être très difficile de discerner les bogues réelles du bruit.
Bien sûr, si vous voyez un grand nombre de problèmes, ceci ne signifie pas que vous pouvez tout simplement négliger le résultat de l’outil ! Lorsque nous exécutons une analyse de cause initiale d’une faille de sécurité, nous nous demandons toujours pourquoi le problème n’a pas été détecté par nos outils. Il existe trois raisons possibles : L’outil n’a pas trouvé la vulnérabilité, l’outil l’a trouvée mais a affecté par erreur une priorité basse au problème et l’outil a en fait trouvé le problème mais une intervention humaine lui a affecté une mauvaise priorité. Cette analyse nous permet de peaufiner nos outils et notre formation au fil du temps.
Les outils d’analyse sont également très bons lorsqu’il s’agit de déterminer le potentiel de failles de sécurité dans le code. Imaginons que vous avez deux produits, chacun comprenant environ 100 000 lignes de code C++. Vous exécutez vos outils sur chaque base de code. Pour cet exemple, supposez que les outils que vous utilisez sont les commutateurs de compilateur /W4 et /analyze. La première base de code produit 121 avertissements /W4 et 19 avertissements /analyze, tandis que la deuxième base de code compte 235 avertissements /W4 et 65 avertissements /analyze. Selon vous, quel est l’ensemble de code qui nécessite la plus grande quantité de révision ?
Pour terminer, les outils sont excellents lorsqu’ils sont exécutés sur du code nouveau ou modifié avant l’archivage, car ils peuvent servir de surveillants de code et trouver certaines catégories de bogues très tôt au cours du processus.
Leçons tirées Les outils d’analyse peuvent vous aider à déterminer le degré d’attention que vous devez porter à votre code. Vous pouvez également utiliser le résultat de l’analyse pour déterminer les risques de code généraux. Utilisez des outils lors de l’archivage pour découvrir les bogues à un stade avancé. Exécutez souvent les outils afin que vous puissiez vous occuper rapidement des nouveaux problèmes. Si vous n’exécutez pas les outils pendant plusieurs mois, il est possible que vous ayez à vous occuper de centaines d’avertissements à la fois.
Automatisez !
Le début d’une opération d’amélioration de sécurité comporte une grande quantité de travail manuel (la révision manuelle du code, la révision manuelle de la conception etc.). Pour réellement améliorer votre travail, vous devez automatiser une partie aussi grande que possible du processus.
Dans notre équipe, nous avons créé de nombreux outils sur mesure, ainsi qu’un site Web interne pour rassembler les données des outils afin que l’équipe de sécurité centrale puisse consulter les résultats des outils. Lorsqu’une amélioration de SDL est proposée, la proposition doit inclure une méthode d’automatisation de l’amélioration. Les principales raisons de l’utilisation de l’automatisation sont l’évolutivité et l’utilisation constante. Si vous disposez d’une grande quantité de code, vous devez automatiser. En outre, si vous souhaitez que des parties d’un processus soient constamment répétées, l’automatisation constitue définitivement la voie à suivre.
Leçons tirées Efforcez-vous d’exiger autant que possible la mise en œuvre d’une automatisation. Créez ou achetez des outils qui analysent le code et chargent les résultats dans un site central pour qu’ils soient analysés par des experts de la sécurité.
Vous n’arriverez jamais à obtenir un nombre de failles de sécurité égal à zéro.
C’est triste, mais vrai. Vous ne réussirez jamais à réduire le nombre de failles de sécurité à zéro. Je me souviens de l’une des premières mises à jour de sécurité que nous avons publiées pour Windows Vista. Certains utilisateurs étaient étonnés car ils pensaient que Microsoft avait déclaré avoir résolu le problème de la sécurité avec Windows Vista. Premièrement, je ne connais personne ayant fait cette déclaration et deuxièmement, un nombre de failles de sécurité égal à zéro est tout bonnement impossible.
Même si un nombre de failles de sécurité nul serait une bonne chose, il est fou de penser pouvoir arriver à un tel résultat. Le fait est que l’environnement technologique est en mouvance constante, les menaces sont une cible mobile et la recherche de la sécurité est une opération continue. J’ai dit précédemment que la sécurité était une course aux armements. Nous ajoutons des défenses à nos produits et les attaquants s’y adaptent.
Votre code peut sembler être totalement dénué de vulnérabilité aujourd’hui, mais tout peut changer du jour au lendemain lors de la découverte d’un nouveau type de vulnérabilité. Par exemple, le 15 octobre 2003, Microsoft a émis un bulletin de sécurité remédiant à une vulnérabilité de scripts inter-site (XSS) d’Outlook® Web Access incluse dans Microsoft Exchange 5.5. Au mois de mars de l’année suivante, Sanctum (acheté depuis par Watchfire, puis IBM) a publié un document présentant une nouvelle vulnérabilité similaire au script inter-sites appelée fractionnement de réponse HTTP (HTTP response splitting). Six mois plus tard, Microsoft a publié une autre mise à jour de sécurité Outlook Web Access dans Microsoft Exchange 5.5 pour résoudre une vulnérabilité de fractionnement de réponse HTTP. Que s’est-il donc passé ? Pour simplifier, lorsque le bulletin a été publié, les problèmes de fractionnement de réponse étaient inconnus, mais le contexte a changé.
Leçons tirées Assurez-vous que les personnes de votre organisation se rendent compte que votre objectif est de réduire le nombre de failles de sécurité, mais que vous n’atteindrez jamais un nombre de problèmes de sécurité égal à zéro tant qu’il y a des attaquants à la recherche de nouvelles techniques et vulnérabilités.
La sécurité est un combat sans fin.
Vous ne pourrez jamais dire « Nous en avons terminé avec la sécurité, ce problème est maintenant résolu ». Il s’agit d’un prolongement du point précédent, avec un angle toutefois légèrement différent. Il est fondamentalement important que vous assuriez la formation continue de vos ingénieurs. Si vous ne le faites pas, les compétences pourraient s’atténuer et le degré d’urgence pourrait diminuer progressivement. La sécurité est essentielle et la protection des systèmes est incontournable. Comme je l’ai déclaré dans le point précédent, de nouvelles menaces et de nouvelles vulnérabilités sont constamment découvertes, et vous devez par conséquent toujours traiter la sécurité comme une tâche qui n’est jamais terminée.
Vous devez également vous rendre compte que la sécurité n’a plus un caractère spécial. La sécurité fait simplement partie du travail à effectuer.
Leçons tirées Continuez à assurer la formation continue de vos ingénieurs et assurez-vous qu’ils sont toujours conscients de l’importance de la résolution des problèmes de sécurité.
Il n’y a pas de remède magique.
Les gens me demandent souvent « quel est l’élément le plus important du SDL » ? Réponse : tous. Si une portion du SDL s’était avérée inutile, elle aurait été supprimée du SDL. Chaque portion du SDL mène à une réduction du nombre de vulnérabilités de sécurité. Par conséquent, lorsque vous entendez une personne dire qu’elle possède une tâche unique, magique, pour assurer la sécurité, telle que l’exécution d’outils d’analyse statique ou la formation du personnel, elle ne couvre pas toutes ses bases de sécurité. Les outils d’analyse sûrs et statiques ont leur place, et la formation des utilisateurs est essentielle, mais cela ne suffit pas. La sécurité doit être complète et doit faire partie du processus.
Leçons tirées Veillez à adresser les problèmes de sécurité sous tous les angles disponibles. Sinon, vous devez modifier votre processus !
La règle selon laquelle le nombre d’yeux améliore la vision est correcte.
Le célèbre défenseur de l’Open Source, Eric Raymond, a déclaré que plus le nombre d’yeux est grand, plus les bogues sont apparents. Il a raison. Mais je pense que cette déclaration simplifiée ignore un point important. Elle devrait se poursuivre par « à condition que les yeux soient motivés et éduqués ».
Chez Microsoft, nous pouvons exiger du personnel qu’il adopte les améliorations de processus car ces exigences font partie du travail. C’est la motivation. Nous assurons la formation sous de nombreuses formes, telles que les formations en direct, les ateliers et la formation en ligne. Cela suffit amplement pour garder les ingénieurs au courant de ce qui se passe sur le front de la sécurité.
Leçons tirées Plus le nombre de personnes examinant le code sera important et mieux ce sera, pourvu que cette tâche soit effectuée en observant une certaine infrastructure. Vous devez vous assurer que les développeurs assurant la révision du code aient une raison de s’adapter à votre processus actuel, et ceux-ci doivent être formés aux menaces de sécurité les plus récentes.
Le déni de service d’aujourd’hui est l’exploit de demain
Beaucoup de fournisseurs de logiciels, y compris Microsoft, ont appris ceci à leurs dépens. Les ingénieurs peuvent examiner un problème de code et le rejeter rapidement car ce problème est « seulement une attaque de déni de service ». Souvenez-vous que le monde de la recherche en sécurité évolue constamment et que les suppositions concernant certaines classes de vulnérabilité peuvent changer du jour au lendemain.
Leçons tirées Ne pas rejeter trop rapidement un problème de déni de service. Avec un peu de travail, les utilisateurs malveillants peuvent transformer certaines vulnérabilités de déni de service en véritables vulnérabilités d’exécution de code.
Réflexions finales
S’il y a une chose que j’ai apprise au cours des quelques années passées, c’est que lorsqu’il est question de sécurité, il faut être préparé à avoir ses idées et son point de vue constamment discutés et être actif pour se tenir au courant des derniers problèmes en date. Si vous prenez à cœur les leçons apprises dans cet article, vous vous en tirerez sans problème.
Michael Howard est responsable de programme de sécurité chez Microsoft. Il travaille principalement à l’amélioration des processus sécurisés et sur les méthodes recommandées. Il a co-écrit de nombreux ouvrages sur la sécurité, parmi lesquels Writing Secure Code for Windows Vista, The Security Development Lifecycle, Writing Secure Code et 19 Deadly Sins of Software Security.