Problèmes de désérialisation JSON en Java avec Jackson ObjectMapper
1 décembre 2021
0 minutes de lectureDans un précédent article de blog, nous avons examiné la plateforme de sérialisation personnalisée de Java et ses implications en matière de sécurité. Plus récemment, j’ai expliqué comment les améliorations apportées à Java 17 peuvent vous aider à prévenir les désérialisations non sécurisées. Aujourd’hui, toutefois, les utilisateurs dépendent moins de la sérialisation personnalisée de Java et privilégient plutôt JSON. JSON est le format de sérialisation des données le plus répandu : il est lisible par les humains et n’est pas propre à Java.
L’une des bibliothèques les plus utilisées est jackson-databind, qui vous fournit un ObjectMapper pour convertir vos objets en JSON et inversement.
Cette bibliothèque étant très populaire, il est important de savoir que jackson-databind a fait l’objet de nombreuses vulnérabilités signalées ces dernières années. Cela ne signifie toutefois pas que l’utilisation de Jackson ObjectMapper représente un risque pour la sécurité par défaut. Cet article explique le fonctionnement des vulnérabilités de désérialisation de Jackson et comment vous assurer que vous n’êtes pas concerné.
Mais avant d’aller plus loin, répondons à quelques questions que vous vous posez peut-être…
Qu’est-ce que la désérialisation ?
La désérialisation consiste à transformer les données d’un fichier ou d’un flux en un objet utilisable dans votre application. Il peut s’agir de données binaires ou de données structurées, comme JSON et XML. La désérialisation est l’opposé de la sérialisation, qui transforme des objets en flux d’octets ou en texte structuré.
À quoi sert Jackson ObjectMapper ?
Jackson ObjectMapper fait partie de la bibliothèque Jackson databind et sert à transformer du JSON en objets Java et inversement. C’est l’une des bibliothèques les plus connues et les plus utilisées de l’écosystème Java pour convertir du JSON en Java et vice versa. Elle est incluse automatiquement dans Spring Boot.
Jackson ObjectMapper est-il sécurisé ?
Oui, Jackson ObjectMapper est sécurisé et utilise des paramètres par défaut sûrs. Il est essentiel d’effectuer la mise à jour vers les versions les plus récentes afin d’éviter les problèmes de sécurité connus.
La création d’un ObjectMapper est-elle coûteuse ?
La création d’un ObjectMapper est assez coûteuse. Il est donc recommandé de réutiliser votre instance d’ObjectMapper. Jackson ObjectMapper étant thread-safe, vous pouvez le réutiliser en toute sécurité.
Utiliser Jackson ObjectMapper pour créer des objets Java à partir de JSON
Avec le code ci-dessous, nous pouvons créer un ObjectMapper et l’utiliser pour recréer un objet Person à partir d’une chaîne JSON provenant d’un fichier.
Tout cela est simple, et rien de particulièrement complexe ne se produit. En l’absence d’annotations, Jackson ObjectMapper utilise la réflexion pour effectuer le mappage POJO. Grâce à la réflexion, il fonctionne avec tous les champs, quel que soit leur modificateur d’accès. Si des getters et des setters sont disponibles, Jackson ObjectMapper les utilise pour effectuer le mappage.
Le typage par défaut dans Jackson
Bon nombre des vulnérabilités de la bibliothèque Jackson liées à la sérialisation JSON dépendent du typage par défaut, qui n’est pas activé par défaut. Vous devez l’activer explicitement. Cela signifie que, dans la plupart des cas, les vulnérabilités mentionnées dans cette liste n’affectent pas directement votre système.
Mais expliquons ce qu’est le typage par défaut et à quoi il sert.
Le typage par défaut est un mécanisme de Jackson ObjectMapper qui permet de gérer les types polymorphes et l’héritage. Si vous souhaitez désérialiser du JSON en POJO Java, mais que vous ne connaissez pas le sous-type de l’objet ou du champ, vous pouvez simplement désérialiser vers la superclasse.
Imaginons que vous ayez Coffee et Tea. Les deux classes ont la même superclasse, HotDrink. Si votre Breakfast contient une boisson de type HotDrink, mais que vous ne savez pas s’il s’agit de Coffee ou de Tea, vous pouvez utiliser le typage par défaut pour résoudre ce problème.
Dans cet exemple, j’ai activé le typage par défaut sur l’ObjectMapper afin de gérer le polymorphisme partout où j’utilise cet ObjectMapper. Vous pouvez également le faire sur un champ spécifique à l’aide de l’annotation @JsonTypeInfo.
Problèmes de sécurité liés au typage par défaut de Jackson ObjectMapper
Si le typage par défaut est activé globalement, il est donc possible de pousser l’héritage à l’extrême. Si votre Breakfast ne contient pas de HotDrink, mais un champ de type Object, alors n’importe quel objet présent dans le classpath peut être utilisé. Cela signifie également que nous pouvons désérialiser n’importe quel objet disponible dans le classpath. Il pourrait s’agir d’un objet gadget qui met en place une chaîne de gadgets et finit par permettre l’exécution de code à distance.
Ces chaînes de gadgets ressemblent beaucoup à celles décrites dans mon article de blog Sérialisation et désérialisation en Java. Simplifions le tout avec un seul gadget qui exécute immédiatement une commande lors de son initialisation. Voici ma classe SecondBreakfast ci-dessous, qui contient une boisson de type Object.
Si je désérialise mon SecondBreakfast avec le typage par défaut activé, je peux désérialiser un Object contenant du code arbitraire à exécuter.
Il s’agit d’un exemple simplifié. Trouver et créer une chaîne de gadgets n’est pas facile, mais c’est tout à fait possible. Compte tenu des bibliothèques et frameworks que nous utilisons, il est probable qu’une combinaison des classes présentes dans votre classpath puisse servir à créer une telle chaîne de gadgets.
En outre, un grand nombre de « classes malveillantes » bien connues ont déjà été identifiées. La désérialisation d’une telle classe est considérée comme dangereuse et suit essentiellement le schéma décrit ci-dessus. Pour référence, consultez la liste des vulnérabilités de désérialisation de la bibliothèque jackson-databind dans la Snyk Vulnerability Database.
Quel est l’impact sur mon application ?
D’accord, pas de panique : la situation n’est pas si grave. Tout d’abord, les responsables de la bibliothèque jackson-databind bloquent activement les « classes malveillantes » dans le SubTypeValidator. Ensuite, vous devez activer explicitement les types par défaut. Ce paramètre est donc désactivé par défaut, et la désérialisation polymorphe n’est même pas possible.
L’analyse à l’aide d’outils SCA comme Snyk fait apparaître la vulnérabilité dans les résultats. Une recherche rapide montre que ces problèmes ont été nombreux par le passé. Il est toujours judicieux de passer à la version la plus récente, car la bibliothèque est bien maintenue et les nouvelles « classes malveillantes » sont bloquées dès qu’elles sont découvertes. Cela dit, la meilleure solution reste de ne pas activer le typage par défaut de votre ObjectMapper Jackson.
L’assistant de triage Snyk à la rescousse
Snyk s’efforce actuellement de filtrer ces vulnérabilités lorsque votre code ne remplit pas les conditions préalables. Pour Jackson ObjectMapper, cela signifie que si votre code n’active pas le typage polymorphe, nous vous indiquons qu’il est peu probable que cette vulnérabilité particulière puisse être exploitée contre vous. Au moment de la rédaction de cet article, cette fonctionnalité n’est disponible que pour la vulnérabilité de désérialisation Jackson, mais l’équipe continue de l’améliorer et de l’étendre. Pour utiliser cette fonctionnalité, nous avons besoin de votre autorisation pour analyser votre code et vérifier que le typage par défaut n’est pas activé.

Les exemples de code utilisés dans cet article de blog sont publiés sur mon compte GitHub. N’hésitez pas à créer un fork ou à réutiliser ces exemples comme bon vous semble.
Désérialisez en toute sécurité !
Pour éviter les problèmes de désérialisation avec Jackson ObjectMapper, la meilleure solution consiste à empêcher le typage polymorphe. N’activez pas le typage par défaut de votre ObjectMapper. Connectez également votre projet à Snyk pour vérifier si vous utilisez une bibliothèque jackson-databind présentant des vulnérabilités connues. Dans la plupart des cas, vous pouvez facilement la remplacer par une version plus récente. Lorsque vous activez l’analyse du code, l’assistant de triage peut vous aider à déterminer si la vulnérabilité est susceptible ou non d’être exploitable.
Lancez-vous dans les compétitions Capture The Flag
Apprenez à résoudre des défis de capture du drapeau en regardant à la demande notre atelier virtuel d’initiation.
