flawopen.com/Désérialisation non sécurisée/PHP unserialize()
unserialize() de PHP est-il sûr pour des données non fiables ?
Ne transmettez pas de données non fiables à unserialize(), même avec allowed_classes. PHP peut restaurer des objets et appeler __unserialize() ou __wakeup() ; un attaquant peut exploiter les classes disponibles dans l’application ou son autoloader. Utilisez JSON pour les données non fiables. En mode associatif, les objets JSON deviennent des tableaux et ne créent pas de classes applicatives avec des méthodes magiques.
<?php // Cookie content is controlled by the client. $input = $_COOKIE['prefs'] ?? ''; $data = unserialize($input); // Restoring an object may invoke its // __unserialize() or __wakeup() method. // Later object destruction may invoke __destruct(). // The risk depends on available classes, // their serialized state, and reachable behavior.
<?php
$input = $_POST['prefs'] ?? null;
if (!is_string($input)) {
http_response_code(400);
exit;
}
try {
$data = json_decode(
$input,
true,
512,
JSON_THROW_ON_ERROR
);
} catch (JsonException $e) {
http_response_code(400);
exit;
}
if (!is_array($data)) {
http_response_code(400);
exit;
}
// Validate required keys and value types here.
Conditions d’une chaîne d’injection d’objets PHP
L’injection d’objets ne signifie pas une exécution automatique de code. La valeur sérialisée doit nommer une classe que PHP peut résoudre et que les options autorisent ; la restauration ou l’utilisation ultérieure doit aussi atteindre un comportement ayant un impact de sécurité. PHP peut appeler __unserialize() ou __wakeup() pendant la restauration ; __destruct() peut s’exécuter à la destruction et __toString() uniquement dans un contexte de chaîne.
Une chaîne Property-Oriented Programming (POP) relie des comportements déjà présents dans l’application ou ses dépendances chargées. L’exploitabilité dépend des classes réelles, des propriétés sérialisées, du chemin d’appel et du contexte d’exécution. Il faut démontrer une chaîne de gadgets pour la cible ; la seule présence de unserialize() ne suffit pas.
Pourquoi filtrer la chaîne ou utiliser allowed_classes ne suffit pas
Bloquer un marqueur comme O:, filtrer des noms de classe ou limiter la longueur ne valide pas sûrement la sérialisation PHP. Surtout, PHP déconseille explicitement de transmettre des données non fiables à unserialize(), quelle que soit la valeur de allowed_classes. Une classe interdite devient un objet __PHP_Incomplete_Class ; la structure est tout de même analysée. Pour des données anciennes de confiance, validez la forme obtenue et limitez la profondeur. Préférez JSON pour l’état client.
Questions fréquentes
Non. Cette option empêche la restauration normale des classes applicatives ; les objets interdits deviennent __PHP_Incomplete_Class. PHP déconseille toujours les données non fiables avec unserialize(), même avec cette option. Utilisez-la seulement en défense en profondeur pour des données héritées de confiance, validez le résultat et limitez max_depth. La documentation PHP précise que cette option ne s’applique pas aux énumérations.
Il peut authentifier l’intégrité de données produites par votre application si la clé reste secrète et si hash_equals() vérifie la signature avant la désérialisation. Rejetez une signature invalide avant l’analyse. Un HMAC ne chiffre pas et n’empêche pas le rejeu ; ajoutez expiration ou nonce si la fraîcheur est requise. Ne signez pas des données arbitraires fournies par l’utilisateur pour les rendre fiables.
Ils partagent le risque général de restaurer des objets depuis des données sérialisées, mais formats, hooks, résolution de classes et protections diffèrent. Évaluez chaque runtime et ses classes séparément ; une chaîne de gadgets d’une plateforme ne s’applique pas automatiquement aux autres.
Références
- Manuel PHP — unserialize()
- Manuel PHP — méthodes magiques
- Manuel PHP — décodage JSON
- Manuel PHP — __PHP_Incomplete_Class
- OWASP — injection d’objets PHP
- CWE-502 — désérialisation de données non fiables
- Python pickle est-il sûr avec des données non fiables ?
- Java ObjectInputStream est-il sûr avec des données non fiables ?