FlawOpen

flawopen.com/Désérialisation non sécurisée/Sécurité du pickle Python

pickle.load() est-il sûr avec des données non fiables ?

CWE-502 : désérialisation de données non fiablesPage de référence
Réponse courte

Non. Considérez pickle comme un programme dans un colis, pas comme un simple enregistrement : le chargement peut déclencher la reconstruction avant la validation de l’objet. Utilisez un format limité aux données pour toute entrée franchissant une frontière de confiance.

DANGEREUX — des octets non fiables peuvent déclencher du code
import pickle

# Never accept pickle bytes from a request, upload,
# shared cache, or other untrusted source.
obj = pickle.loads(untrusted_bytes)
OPTION PLUS SÛRE — analyser les données puis valider leur schéma
import json

def parse_profile(raw: bytes) -> dict[str, str]:
    if len(raw) > 65_536:
        raise ValueError("Payload too large")

    try:
        value = json.loads(raw)
    except (json.JSONDecodeError, UnicodeDecodeError):
        raise ValueError("Invalid JSON") from None

    if not isinstance(value, dict) or set(value) - {"display_name", "theme"}:
        raise ValueError("Invalid profile")

    name = value.get("display_name")
    theme = value.get("theme")
    if not isinstance(name, str) or len(name) > 80:
        raise ValueError("Invalid display name")
    if theme not in {"light", "dark"}:
        raise ValueError("Invalid theme")

    return {"display_name": name, "theme": theme}
Flux pickle :
Suite d’octets propre à Python décrivant la reconstruction d’objets, avec des références aux globaux et au comportement de reconstruction.
Unpickling :
Interprétation du flux et reconstruction du graphe d’objets ; des fonctions peuvent être appelées.
Frontière de confiance :
Point où un utilisateur, service, téléversement ou stockage partagé peut contrôler ou modifier les octets.
CWE-502 :
Désérialisation de données non fiables ; l’impact dépend de la possibilité de fournir ou modifier les données chargées.
Étape 1

Des octets non fiables atteignent pickle

Un téléversement, une requête, un cache ou un artefact peut transmettre des données pickle contrôlées ou altérées au processus.

Étape 2

L’unpickler résout les globaux

L’interpréteur traite les instructions de reconstruction ; find_class() peut importer et renvoyer des globaux nommés, y compris des fonctions.

Étape 3

Le chargement déclenche un comportement

Les instructions peuvent appeler des fonctions pendant load() ou loads(), avant la validation de l’objet retourné.

Étape 4

L’impact dépend des droits du processus

Le comportement s’exécute avec les droits du processus Python. Réseau, secrets, fichiers et isolation déterminent le rayon d’impact.

Pourquoi le chargement pickle franchit une frontière d’exécution de code

Un flux pickle peut nommer des globaux et des fonctions de reconstruction. Pendant l’unpickling, Unpickler.find_class() résout les globaux, y compris les fonctions ; des opcodes peuvent déclencher la reconstruction. Le danger est pickle.load() ou pickle.loads() lui-même : aucun appel execute séparé ne suit. Le code obtenu dispose des droits du processus. C’est le comportement documenté du format ; n’utilisez pas pickle pour échanger des données non fiables.

Ce que JSON corrige — et ne corrige pas

La documentation Python avertit que charger des données pickle non fiables ou modifiées peut exécuter du code arbitraire, tandis que décoder du JSON ne crée pas à lui seul cette voie d’exécution. JSON ne valide pas l’entrée : limitez sa taille, exigez le type supérieur et les champs attendus, validez les valeurs selon un schéma et appliquez l’autorisation séparément. Si un ancien flux doit encore charger pickle, authentifiez les octets exacts avec une clé protégée avant le chargement ; une signature prouve l’origine et l’intégrité uniquement selon les hypothèses liées à la clé, et ne rend pas sûr un contenu malveillant signé par une source fiable. Migrez vers un format de données.

Questions fréquentes

Un Unpickler restreint sécurise-t-il le pickle fourni par un attaquant ?

Redéfinir find_class() peut réduire le risque en limitant les globaux, mais prouver qu’un chargeur est sûr pour tous les protocoles et comportements accessibles est difficile. Pour des octets contrôlés par l’utilisateur, préférez un format de données.

JSON doit-il aussi être validé ?

Oui. JSON évite l’exécution de code propre à pickle lors du décodage, mais il faut valider types, champs, tailles, valeurs et autorisations. Séparez analyse JSON et règles métier.

Références principales

À voir aussi Désérialisation non sécurisée : risques et défense Ruby YAML.load est-il sûr ? Versions de Psych et safe_load .NET BinaryFormatter : risques et migration Sécurité d’ObjectInputStream en Java : désérialisation sûre Newtonsoft.Json TypeNameHandling : configuration sûre ? PHP unserialize() et les données non fiables