La désérialisation non sécurisée : notions et impact
Quand deux parties d’un système s’échangent des données, il faut souvent transformer un objet complexe en un texte ou une suite d’octets qui voyage facilement, puis le reconstituer à l’arrivée. C’est comme démonter un meuble pour le transporter et le remonter chez soi grâce à la notice. Ces deux opérations s’appellent la sérialisation et la désérialisation. Le danger apparaît quand c’est un inconnu qui fournit les pièces et dicte, d’une certaine façon, ce qui sera remonté.
Rappel légal et périmètre pédagogique
La désérialisation non sécurisée est l’une des failles dont l’impact peut être le plus lourd : elle peut mener à l’exécution de code sur le serveur. Cette leçon se limite volontairement aux notions : aucun exemple d’objet piégé ni de procédure d’exploitation n’est fourni. Toute expérimentation se fait dans des laboratoires prévus à cet effet (PortSwigger Web Security Academy, TryHackMe, HackTheBox) ou dans votre propre labo. Sur un système réel sans autorisation écrite, c’est une infraction (articles 323-1 à 323-3-1 du Code pénal).
Sérialiser et désérialiser, en clair
Une application manipule des objets : un utilisateur avec son nom, ses préférences, son panier. Pour les stocker dans un cookie, les transmettre à une autre application ou les enregistrer, elle les sérialise : elle les convertit en un format textuel ou binaire. À la réception, elle les désérialise : elle reconstruit l’objet d’origine.
Il existe de nombreux formats. Certains, comme JSON, sont limités aux données simples : textes, nombres, listes. D’autres, propres à un langage de programmation, sont plus puissants : ils décrivent aussi le type des objets à recréer, et peuvent déclencher du code pendant la reconstruction. C’est cette puissance qui crée le danger.
Où est le problème ?
La reconstruction d’un objet à partir de données externes n’est pas qu’un « remplissage de cases » : selon le format et le langage, le processus peut invoquer automatiquement des méthodes des classes de l’application (des fonctions de « réveil » ou de « nettoyage » appelées lors de la reconstruction). Si le format laisse l’émetteur choisir quelle classe instancier, quelqu’un qui contrôle les données choisit, en pratique, quel code de l’application sera exécuté et avec quelles valeurs.
Analogie : vous remontez un meuble avec la notice fournie par un inconnu. Si la notice vous demande d’assembler, à un moment, une pièce qui déclenche un mécanisme, vous l’exécutez sans le savoir. Le risque ne vient pas de l’idée de notice, mais du fait de faire confiance à une notice qui n’est pas la vôtre.
Les impacts possibles
| Impact | Description |
|---|---|
| Altération de données | Un objet sérialisé stocké chez le client (cookie, champ masqué) est modifié pour changer un rôle ou un prix, sans signature pour détecter la modification |
| Déni de service | Des structures volontairement très lourdes consomment mémoire et processeur à la reconstruction |
| Contournement de logique | La modification d’un objet « de confiance » change le comportement de l’application |
| Exécution de code à distance | Dans les cas les plus graves, l’enchaînement des méthodes appelées automatiquement permet l’exécution de commandes sur le serveur |
Ce dernier cas est celui qui a fait la réputation de la faille. Il dépend de l’existence, dans l’application et ses bibliothèques, de classes dont les méthodes peuvent être enchaînées de façon dangereuse : c’est pourquoi une bibliothèque vulnérable (leçon précédente) peut rendre une application exploitable sans qu’une seule ligne de son propre code soit en cause.
Reconnaître le risque
Un auditeur y pense lorsqu’il observe :
- un cookie ou un paramètre dont la valeur ressemble à un objet encodé (une longue chaîne qui n’est pas du simple texte, parfois encodée de façon à être transportable), et qui est renvoyée au serveur ;
- une API qui accepte des objets complexes dans un format propre à un langage ;
- des messages échangés entre composants (files de messages, tâches planifiées) sans vérification d’origine ;
- des fichiers de session ou de cache lus et reconstruits sans protection d’intégrité ;
- des messages d’erreur qui mentionnent des mécanismes de reconstruction d’objets.
La confirmation de l’existence d’une faille demande une grande prudence, car les tests peuvent déstabiliser le serveur. En audit réel, on privilégie la revue de configuration et de code (boîte grise ou blanche) et on convient avec le client des conditions d’un éventuel test pratique, dans un environnement de recette plutôt qu’en production.
Défendre : changer la manière d’échanger
- Ne jamais désérialiser des données non fiables avec un format capable d’instancier des objets arbitraires. C’est la règle numéro un.
- Préférer des formats de données simples (comme JSON) qui ne décrivent que des valeurs, et reconstruire les objets soi-même à partir de champs validés.
- Signer les données qui doivent voyager chez le client (par exemple, avec un code d’authentification de message dont la clé reste côté serveur) pour détecter toute modification ; mieux, ne rien stocker de sensible chez le client, et garder l’état dans la session côté serveur.
- Liste blanche de types autorisés lorsqu’on ne peut pas faire autrement.
- Exécuter avec le moindre privilège : un processus de désérialisation isolé et limité réduit l’impact.
- Tenir à jour les bibliothèques : beaucoup de corrections visent précisément ces mécanismes.
- Surveiller les exceptions de désérialisation, qui peuvent signaler des tentatives.
- Limiter la taille et la profondeur des données acceptées pour éviter le déni de service.
// À éviter : reconstruire un objet complet depuis une donnée fournie par le client
// $profil = unserialize(base64_decode($_COOKIE['profil']));
// À préférer : des données simples, validées champ par champ
$donnees = json_decode($_POST['profil'] ?? '', true);
$nom = is_array($donnees) && is_string($donnees['nom'] ?? null) ? substr($donnees['nom'], 0, 80) : '';
$profil = new Profil($nom); // l'objet est construit par l'application
Astuce
Un réflexe de revue de code : repérer les appels qui reconstruisent des objets à partir de données externes. Dans chaque langage, il existe une fonction identifiable dont la documentation officielle déconseille l’usage sur des données non fiables. Lisez cette mise en garde, elle est souvent explicite.
À vous de jouer
Exercice de raisonnement, sans aucune manipulation d’objet piégé.
- Une application stocke dans un cookie un objet sérialisé contenant le nom de l’utilisateur et son rôle, sans aucune signature. Quels risques identifiez-vous ?
- Proposez deux corrections alternatives.
- Rédigez le constat correspondant, en précisant ce qui a été observé et ce qui n’a pas été testé et pourquoi.
Voir une solution
1) Le client peut modifier l’objet (changer le rôle) : atteinte à l’intégrité et élévation de privilèges ; selon le format et les bibliothèques, risque plus grave à la reconstruction. 2) Garder l’état côté serveur (le cookie ne contient qu’un identifiant de session opaque), ou signer les données avec une clé serveur et les valider avant usage, en utilisant un format de données simple. 3) Constat type : « Le cookie de profil contient un objet sérialisé non signé incluant le rôle. Impact : modification possible du rôle par le client ; risque de désérialisation non sécurisée selon le format. Gravité élevée. Correction : état en session côté serveur ou données signées au format simple. Non testé : tout essai pratique pouvant déstabiliser le serveur, hors périmètre convenu avec le client. » Cette dernière phrase illustre le professionnalisme.
À retenir
- La désérialisation reconstruit des objets à partir de données ; avec des données non fiables et un format puissant, l’émetteur influence le code exécuté.
- Impacts : altération de données, déni de service, contournement de logique, parfois exécution de code à distance.
- Règle numéro un : ne pas désérialiser de données non fiables avec un format capable d’instancier des objets arbitraires.
- Préférer des formats simples, signer ce qui voyage chez le client, ou garder l’état côté serveur.
- Les tests pratiques sont délicats : on privilégie la revue de code et de configuration, et on convient d’un cadre avec le client.
Vous avez maintenant fait le tour des grandes familles de failles web. Il reste à transformer vos constats en actions : c’est l’objet du dernier chapitre, le rapport et la remédiation.