FlawOpen

flawopen.com/Prototype Pollution/JSON.parse()

Verursacht JSON.parse() Prototype Pollution?

CWE-1321: Prototype PollutionReferenzleitfaden
Kurzantwort

Nein. JSON.parse() legt eine eigene Dateneigenschaft namens __proto__ an; das Parsen ruft den geerbten Setter nicht auf und ändert keinen Prototyp. Das Risiko entsteht erst, wenn späterer Code den Schlüssel über einen Setter kopiert, nicht vertrauenswürdige Schlüssel rekursiv zusammenführt oder in einen angreiferkontrollierten Objektpfad schreibt.

UNSICHERE KOPIE — LOKALES ZIEL
// JSON.parse erzeugt Daten; es vergiftet keinen Prototyp.
const input = '{"__proto__":{"isAdmin":true}}';
const parsed = JSON.parse(input);

// Object.assign verwendet Set am Ziel. Hier ändert es nur
// den Prototyp dieses lokalen Demonstrationsobjekts.
const copied = Object.assign({}, parsed);

Object.getPrototypeOf(copied).isAdmin; // true
Object.prototype.isAdmin;              // undefined
SICHERE VERARBEITUNG — BEKANNTE FORM
// Parsen und nur die von der Anwendung erlaubten Felder aufbauen.
const input = '{"theme":"dark","locale":"en","__proto__":{"isAdmin":true}}';
const parsed = JSON.parse(input);
const config = {
  theme:  parsed.theme,
  locale: parsed.locale,
};

// Bei nicht vertrauenswürdigen Schlüssel-Wert-Daten Setter vermeiden.
const options = Object.assign(Object.create(null), parsed);

Warum JSON.parse() nicht die Quelle der Pollution ist

Ein JSON-Schlüssel und der Prototyp-Setter eines Objektliterals sind verschiedene Vorgänge. Das JSON-Parsing definiert eigene Eigenschaften auf dem neuen Wert; es führt obj.__proto__ = value nicht aus. Spätere Operationen können anders wirken: Object.assign(target, source) weist Werte dem Ziel zu. Ein eigener Schlüssel __proto__ kann daher den geerbten Setter des Ziels aufrufen. Das ändert den Prototyp des Zielobjekts, aber für sich genommen nicht Object.prototype.

Nach const o = JSON.parse('{"__proto__":{"a":1}}') ist Object.hasOwn(o, "__proto__") wahr, während Object.prototype.a undefiniert bleibt. Eine spätere Kopie auf ein gewöhnliches Ziel kann diesem Ziel einen anderen Prototyp geben. Object Spread erstellt eigene Dateneigenschaften, ohne den Setter aufzurufen; er schützt aber nicht vor unsicheren rekursiven Merges oder Pfadzuweisungen.

Wo das eigentliche Risiko entsteht

Geparstes JSON sind nicht vertrauenswürdige Daten, kein vergifteter Prototyp. Das Risiko hängt von späteren Schreibstellen ab: rekursives Merge, Pfad-Setter oder Kopierschleife mit Zuweisung auf ein normales Objekt. Ein verwundbares rekursives Merge kann __proto__ oder constructor.prototype bis zu einem gemeinsam genutzten Prototyp verfolgen; eine einstufige Kopie ändert möglicherweise nur ihr Ziel. Prüfen Sie die genaue Funktion und das Zielobjekt, bevor Sie die Auswirkung beschreiben.

Prüfen Sie, wo nicht vertrauenswürdige Schlüssel geschrieben werden, nicht nur, wo JSON geparst wird: Deep-Merge-Funktionen, Pfad-Setter und zuweisende for...in-Schleifen. Lehnen Sie __proto__, constructor und prototype ab, wenn Nutzer Schlüssel kontrollieren können; bevorzugen Sie ein validiertes bekanntes Schema oder ein Dictionary ohne Prototyp.

Häufige Fragen

Sollte ich __proto__ immer mit einem Reviver entfernen?

Ein Reviver kann den Schlüssel beim Parsen entfernen, wenn die Anwendung ihn nicht benötigt. Das ist Defense in Depth, ersetzt aber nicht die Korrektur unsicherer Merges und Pfad-Setter; constructor.prototype und Nicht-JSON-Quellen können ebenfalls relevant sein.

Schützen mich Express oder body-parser?

Der Body-Parser erzeugt einen JavaScript-Wert; spätere Kopien oder Merges werden dadurch nicht sicher. Prüfen Sie den konkreten Parser und die nachfolgenden Operationen. Manche Query-String-Parser erzeugen zudem verschachtelte Objekte aus Klammernotation; das ist ein separater Eingabepfad.

Ist JSON.stringify() ein Risiko für Prototype Pollution?

Nein. Die Serialisierung liest Werte und erzeugt JSON-Text; sie ändert keinen Prototyp. Das Risiko kann zurückkehren, wenn dieser Text geparst und an eine unsichere Senke übergeben wird.

Quellen

Siehe auch JavaScript Prototype Pollution: Ursachen und Schutz Ist JSON.parse() sicherer als eval()? Ist lodash.merge() vor Prototype Pollution sicher? Object.assign() und Prototype Pollution: Was ist sicher?