FlawOpen

flawopen.com/Pollution de prototype/JSON.parse()

JSON.parse() provoque-t-il une pollution de prototype ?

CWE-1321 : pollution de prototypeGuide de référence
Réponse courte

Non. JSON.parse() crée une propriété propre nommée __proto__ ; l’analyse n’appelle pas le setter hérité et ne modifie aucun prototype. Le risque apparaît plus tard si un autre code copie cette clé par un setter, fusionne récursivement des clés non fiables ou écrit dans un chemin d’objet contrôlé par un attaquant.

COPIE NON SÛRE — CIBLE LOCALE
// JSON.parse crée des données ; il ne pollue pas un prototype.
const input = '{"__proto__":{"isAdmin":true}}';
const parsed = JSON.parse(input);

// Object.assign utilise Set sur la cible. Ici, il modifie seulement
// le prototype de cet objet local de démonstration.
const copied = Object.assign({}, parsed);

Object.getPrototypeOf(copied).isAdmin; // true
Object.prototype.isAdmin;              // undefined
TRAITEMENT SÛR — FORME CONNUE
// Analyser puis construire uniquement les champs acceptés.
const input = '{"theme":"dark","locale":"en","__proto__":{"isAdmin":true}}';
const parsed = JSON.parse(input);
const config = {
  theme:  parsed.theme,
  locale: parsed.locale,
};

// Pour les dictionnaires non fiables, éviter les setters hérités.
const options = Object.assign(Object.create(null), parsed);

Pourquoi JSON.parse() n’est pas le point de pollution

Une clé JSON et le setter de prototype d’un littéral d’objet sont deux opérations différentes. L’analyse JSON définit des propriétés propres sur la nouvelle valeur ; elle n’exécute pas obj.__proto__ = value. Les opérations suivantes peuvent agir autrement : Object.assign(target, source) affecte la cible ; une clé propre __proto__ peut donc appeler son setter hérité. Cela modifie le prototype de l’objet cible ; à lui seul, ce mécanisme ne modifie pas Object.prototype.

Après const o = JSON.parse('{"__proto__":{"a":1}}'), Object.hasOwn(o, "__proto__") renvoie vrai et Object.prototype.a reste indéfini. Une copie ultérieure vers une cible ordinaire peut donner un autre prototype à cette cible. La syntaxe spread crée des propriétés propres sans appeler le setter, mais ne protège pas contre les fusions récursives ou les chemins d’affectation non sûrs.

Où se trouve le véritable risque

Le JSON analysé est une donnée non fiable, pas un prototype pollué. Le risque dépend des points d’écriture suivants : fusion récursive, setter de chemin ou boucle de copie qui affecte des clés à un objet ordinaire. Une fusion récursive vulnérable peut suivre __proto__ ou constructor.prototype jusqu’à un prototype partagé ; une copie à un seul niveau peut ne modifier que sa cible. Vérifiez la fonction et l’objet cible avant de décrire l’impact.

Examinez où les clés non fiables sont écrites, pas seulement où le JSON est analysé : fusions profondes, setters de chemin et boucles for...in avec affectation. Refusez __proto__, constructor et prototype lorsque l’utilisateur contrôle les clés ; préférez une forme reconstruite après validation ou un dictionnaire sans prototype.

Questions fréquentes

Faut-il toujours utiliser un reviver pour supprimer __proto__ ?

Un reviver peut supprimer cette clé à l’analyse si l’application n’en a pas besoin. C’est une défense en profondeur, pas un remplacement de la correction des fusions et chemins non sûrs ; constructor.prototype et les entrées non JSON restent à examiner.

Express ou body-parser me protègent-ils ?

L’analyse du corps produit une valeur JavaScript ; elle ne sécurise pas les copies et fusions ultérieures. Vérifiez le parseur exact et les opérations qui suivent. Certains parseurs de query string construisent aussi des objets imbriqués depuis la notation entre crochets : c’est une autre source d’entrée.

JSON.stringify() présente-t-il un risque de pollution de prototype ?

Non. La sérialisation lit des valeurs et produit du texte JSON ; elle ne modifie pas de prototype. Le risque peut réapparaître si ce texte est analysé puis transmis à un point non sûr.

Références

À voir aussi Pollution de prototypes JavaScript : causes et correctifs JSON.parse() est-il plus sûr que eval() ? lodash.merge() : risque de pollution de prototypes ? Object.assign() et Prototype Pollution : que risque-t-on ?