Protéger ses APIs contre log4shell avec 42Crunch

Protéger ses APIs contre log4shell avec 42Crunch

Rédigé par Pierrick Prévert, Head of Pre-Sales EMEA, 42Crunch

Le 9 décembre 2021, la vulnérabilité log4shell a été dévoilée et a rapidement hanté les équipes de sécurité à travers le monde. Cette vulnérabilité présente sur un composant très largement utilisé dans la pile technologique des entreprises est exploitable trivialement, a un impact massif allant jusqu’à l’exécution de code (RCE). Tous ces éléments expliquent sa note CVSS de 10 – la plus haute possible. Il s’agit d’une des pires vulnérabilités dont j’ai été témoin dans ma carrière : un attaquant peut l’exploiter efficacement avec un investissement minimal. Ces derniers jours, d’autres vulnérabilités sont apparues ciblant la bibliothèque log4j.

Beaucoup d’articles ont été écrits sur log4shell et les vulnérabilités suivantes afin d’expliquer ce qu’elles font et comment, ou encore comment détecter des tentatives d’exploitation.

Dans cet article nous prenons une approche différente : nous montrons comment un modèle de sécurité positif réduit considérablement la surface d’attaque et limite, ou bloque, ce type d'injection. Nous montrons aussi comment une telle approche peut être implémentée pour sécuriser les APIs de la phase de développement jusqu’aux environnements de production avec 42Crunch.

Création d’un contrat d’API

Adopter une approche de sécurité positive commence avec la création d’un contrat d’API. Imaginez un contrat d’API comme le plan d’une API : une liste de règles de ce qu’une API accepte et ce qu’elle répond. Par définition, dans un modèle de sécurité positif, tout ce qui n’est pas défini est rejeté.

Traditionnellement, deux approches sont utilisées pour créer un contrat d’API:

●      “Design first” : le contrat est d’abord écrit, puis l’API est développée conformément au contrat

●      “Code first” : l’API est d’abord développée et un contrat d’API est généré à partir du code

Bien que nous préconisons généralement une approche “Design first” comme d’un point de vue de la sécurité cela facilite grandement la définition d’un modèle de menaces, 42Crunch s’intègre aussi simplement avec les deux approches.

Regardons l’extrait d’un contrat vulnérable d’API écrit en format OpenAPI specification v3:

Aucun texte alternatif pour cette image


Ici, ce contrat possède une vulnérabilité dans la façon dont la propriété user est définie. Pourquoi ?

Ce contrat définit un endpoint login, qui accepte des requêtes POST contenant un objet JSON avec une propriétéuser de type string. Le problème ici est que la propriété user n’est pas contrainte. Sa longueur maximale n’étant pas définie, elle peut être une chaîne de caractères de 100Mo. Aussi, cette chaîne de caractères peut être composée de tous les caractères possibles que ce soit $, é, !, des guillemets, des emojis, etc. Cela ouvre potentiellement la porte à des injections.

Un audit de sécurité de 42Crunch sur ce contrat, réalisé par exemple grâce à un de nos plugins gratuits pour IDEs (Visual Studio CodeIntelliJEclipse), trouvera les problèmes suivants sur la propriété user. Extrait:

●      String schema has no pattern defined : Possible exploit scenario: If you do not define a pattern for strings, any string is accepted as the input. This could open your backend server to various attacks, such as SQL injection.

●      String schema has no maximum length defined : Possible exploit scenario: If you do not limit the length of strings, attackers can send longer strings to your API than what your backend server can handle. This could overload your backend server and make it crash. In some cases, this could cause a buffer overflow and allow for executing arbitrary code. Long strings are also more prone to injection attacks.

Aucun texte alternatif pour cette image

Regardons maintenant comment ces problèmes de définition se manifestent dans une implémentation.

Exploitation d’une API mal conçue

Pour rendre cette vulnérabilité concrète, nous avons développé une implémentation de ce endpoint qui utilise une version vulnérable de log4j (2.14.1), susceptible d’être exploitée par log4shell. Cet endpoint logge l’utilisateur (la propriété user) se connectant, ne retournant que {"msg": "OK"} au client. Le code Java ressemble à:

Aucun texte alternatif pour cette image

Exécutons maintenant une simple requête sur cette API avec curl:

Aucun texte alternatif pour cette image

Dans les logs de l’API nous pouvons voir :

Aucun texte alternatif pour cette image

Maintenant, à la place de l’utilisateur xliic essayons une injection. Comme cette API possède une version vulnérable de log4j et que le paramètre n’est pas contraint, un attaquant peut injecter dans la propriété user une chaîne d’interpolation JNDI, telle que la vulnérabilité log4shell:

Aucun texte alternatif pour cette image

Les logs de l’application affichent l’erreur suivante, montrant que la vulnérabilité a été déclenchée. Ici, l’attaque échoue uniquement parce que l’API ne peut pas résoudre le nom de domaine inexistant “willnotwork”:

Aucun texte alternatif pour cette image

Améliorer le contrat d’API et sa posture de sécurité

Il est important de comprendre ce qui s’est passé. Plusieurs vulnérabilités critiques sont présentes dans cette application :

  1. Une version vulnérable de la bibliothèque log4j
  2. Une mauvaise définition et validation des données qui permettent l’injection (cf. OWASP API8:2019)

A cause de cette validation défectueuse, l’exploitation de la vulnérabilité de log4j est rendue triviale. La surface d’attaque d’une organisation s’étend à chaque fois qu’une entrée ou qu’une sortie d’une application n’est pas formellement contrainte ou validée. Aucune mécanisme de détection d’exploit ne remplira jamais ce trou de sécurité.

Aucun texte alternatif pour cette image

Comment ce paramètre peut-il être contraint?

Le plus grand problème que les entreprises rencontrent quand elles cherchent à répondre à cette question, est l’incapacité des équipes de sécurité, à qui échoit la responsabilité de mettre en place ces contraintes, de savoir ce qu’une API est censée faire ou accepter. Cette méconnaissance les amène à ne pas pouvoir mettre en place une politique de sécurité efficace, sinon par des outils de détection d’attaque inefficaces : IPs louches, identification de trafic suspicieux, etc. Dans les rares cas où les équipes de sécurité ont cette connaissance, elles ont alors à implémenter des règles manuellement et les changer manuellement à chaque itération d’une API.

Or, dans une entreprise, les développeurs de l’API ont la connaissance de ces contraintes. Améliorer la posture de sécurité revient à implémenter un cercle vertueux entre les équipes de développement et les équipes de sécurité, en partageant ce savoir dans un format structuré pour permettre l’automatisation de la sécurité.

Dans notre exemple, le rapport d’audit de 42Crunch donne des recommandations de remédiation du contrat d’API. En suivant ces recommandations, un développeur spécifie les contraintes métier (pattern et maxLength) de la propriété user.

Aucun texte alternatif pour cette image

Le pattern limite la propriété user à des chaînes de caractères qui commencent avec  une lettre minuscule ou une majuscule et continue avec un ou plusieurs chiffre et lettre. Par exemple, sont autorisées "abc123" et "Hworld1". Cependant, "0hey" n’est pas autorisé, parce que user ne peut pas commencer avec nombre. "a$bc" ne l’est pas non plus, comme le caractère "$" n’est pas autorisé. Aussi, la propriété user est maintenant contrainte à 64 caractères.

En pratique, en formalisant ces contraintes, nous avons créé une définition formelle des paramètres autorisés par notre API que nous pouvons utiliser. Le score d’audit de notre API est désormais de 100/100.

Valider l’implémentation en assurant la conformité

Quoi que le contrat d’API déclare, il n’a que peu de valeur si l’implémentation diffère. Une étape essentielle dans la mise en œuvre d’une approche de sécurité positive est de s’assurer que chaque définition formelle est correctement implémentée. A 42Crunch, c’est le rôle du Conformance scanner : valider que l’API implémente les contraintes spécifiées dans le contrat d’API. 

Lançons maintenant le Conformance scanner sur l’implémentation vulnérable:

Aucun texte alternatif pour cette image

Dans les logs nous pouvons voir quelques tests effectués par le scanner:

Aucun texte alternatif pour cette image

Dans le rapport de scan, 15 problèmes sont trouvés, parmi lesquels les deux suivants:

●      Test: The generated value does not follow the property pattern for strings [FAILURE] : In this test, the scanner generated a user property that does not match the pattern allowed. The API did not reject the request, indicating that pattern constraints on this parameter are not implemented.

●      Test: The generated value does not follow the property maxLength for strings [FAILURE] : In this test, the scanner generated a user property that does not match the maximum length defined. The API did not reject the request, indicating maximum length constraints on this parameter are not implemented.

Aucun texte alternatif pour cette image

Ici, le scan de conformité nous a permis d’identifier que l’API ne valide pas les contraintes définies dans le contrat. En conséquence l’API est, comme nous l’avons vu plus tôt, vulnérable à des injections telles que log4shell.

Nous avons vu qu’un plugin d’audit est disponible pour les IDEs des développeurs. Les audits ainsi que les scans de conformité peuvent aussi être intégrés grâce à des plugins natifs dans les chaînes de CI/CD pour permettre aux équipes de sécurité d’ériger des barrières de sécurité lors du build, afin que de tels problèmes ne se retrouvent jamais en production.

Aucun texte alternatif pour cette image

Appliquer le contrat pour protéger l’API

Imaginons que cette implémentation vulnérable est en production. Comment cette API peut-elle être protégée pendant que l’implémentation est corrigée pour assurer la conformité au contrat sécurisé ? Ce temps nécessaire à la correction est un problème pour les entreprises.

Pour résoudre ce problème, 42Crunch a développé un firewall à très basse latence qui s’autoconfigure à partir d’un contrat API. Ce firewall ne transmettra au serveur API ainsi qu’au client API que le trafic qui est conforme au contrat, mettant effectivement en oeuvre un modèle de sécurité positif. Aussi, ce firewall permet l’ajout de politique de sécurité telles que rate limiting, validation de token JWT, etc. qui peuvent être injectées dans le contrat en security-as-code.

Autre que la latence, une autre différence majeure avec un WAF traditionnel est cette définition formelle d’une API. En regardant une requête et un contrat un ingénieur en sécurité pourra prédire la décision du firewall. Si le contrat le permet, c’est autorisé. Si le contrat ne le permet pas, alors ce sera bloqué. Il n’y a pas de zone grise, pas de supposition, aucun faux positif ou faux négatif, par définition.

Essayons les requêtes précédentes avec le firewall:

Aucun texte alternatif pour cette image

Cette requête passe sans problème, comme la propriété user est conforme aux contraintes exprimées dans le contrat.

Aucun texte alternatif pour cette image

Ici la requête est bloquée par le firewall car elle n’est pas conforme au contrat. La tentative d’injection dans la propriété user ne correspond pas aux contraintes exprimées, la requête est donc bloquée par le firewall. L’API possède toujours des vulnérabilités : à la fois log4j et la couche de validation des données doivent être patchées. Cependant, en mettant en œuvre un mode de sécurité positif, la surface d’attaque a été réduite et l’API est protégée.

Conclusion

Les points à retenir :

●      La sécurité doit être implémentée tout au long du cycle de vie logiciel : “shift left” et “shield right”

●      Réduire la surface d’attaque des APIs commence par la validation des données 

●      La validation des données doit être implémentée dans un modèle de sécurité positif

●      Un modèle de sécurité positif évite les suppositions et permet l’automatisation

Les étapes d’implémentation d’un modèle de sécurité positif :

●      Définir les entrées et sorties d’une API dans un contrat

●      Vérifier la conformité de l’implémentation avec les contrats

●      Imposer la conformité du contrat en production

Identifiez-vous pour afficher ou ajouter un commentaire

Autres pages consultées

Explorer les sujets