Unsachgemäße Kontrolle der Modifikation von Objektprototyp-Attributen (Prototype Pollution)
Beschreibung
Unsachgemäße Kontrolle der Modifikation von Objektprototyp-Attributen, auch bekannt als Prototype Pollution, tritt auf, wenn ein Produkt Benutzereingaben empfängt, die Eigenschaften von Objektprototypen auf eine Weise bestimmen, die zu einer Änderung des Prototyps führen kann. In JavaScript erben alle Objekte Eigenschaften von einem Prototyp-Objekt. Wenn ein Angreifer den Prototyp modifizieren kann (typischerweise Object.prototype), beeinflusst diese Modifikation alle Objekte, die von diesem Prototyp erben. Dies kann zu unerwartetem Verhalten führen, einschließlich Eigenschaftsüberschreibungen, Umgehung von Sicherheitsprüfungen, Denial of Service oder sogar Remote-Code-Ausführung.
Risiko
Prototype Pollution erzeugt mehrere Risikokategorien. Sie kann Sicherheitsprüfungen umgehen, die auf Eigenschaftsexistenz oder -werte angewiesen sind. Angreifer können schädliche Eigenschaften auf Objekten einfügen, die später in sicherheitssensitiven Kontexten verwendet werden. In serverseitigen JavaScript-Umgebungen kann dies zu Remote-Code-Ausführung führen. Das Risiko wird durch die weitverbreitete Verwendung von Objekt-Merging-Utilities und JSON-Parsing in modernen JavaScript-Anwendungen verstärkt.
Lösung
Frieren Sie Object.prototype ein, wenn möglich. Validieren und bereinigen Sie alle Benutzereingaben, die zur Objekterstellung oder -modifikation verwendet werden. Verwenden Sie Map anstelle von einfachen Objekten für Benutzerdaten. Implementieren Sie Allowlists für erlaubte Eigenschaftsnamen. Verwenden Sie sichere Bibliotheken für tiefes Merging und Klonen. Erstellen Sie Objekte mit null-Prototyp (Object.create(null)) bei der Verarbeitung von Benutzerdaten. Aktualisieren Sie regelmäßig Abhängigkeiten, um bekannte Prototype-Pollution-Schwachstellen zu patchen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Informationsleck - Angreifer können auf sensible Daten zugreifen, indem sie Eigenschaften manipulieren, die Zugriffskontrollprüfungen steuern. |
| Integrität | Bereich: Integrität Datenmodifikation - Die Prototyp-Verschmutzung kann zu unbeabsichtigten Datenänderungen in der gesamten Anwendung führen. |
| Verfügbarkeit | Bereich: Verfügbarkeit DoS: Crash/Exit/Neustart - Modifizierte Prototypen können Anwendungsabstürze oder unendliche Schleifen verursachen. |
Beispielcode und Lösung
Verwundbarer Code
// Verwundbar: Rekursives Objekt-Merging ohne Prototyp-Schutz
function verwundbarMerge(target, source) {
for (let key in source) {
if (typeof source[key] === 'object' && source[key] !== null) {
if (!target[key]) target[key] = {};
verwundbarMerge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
// Angreifer-Eingabe
const schädlichePayload = JSON.parse('{"__proto__": {"isAdmin": true}}');
// Das verschmutzt Object.prototype
const benutzerConfig = {};
verwundbarMerge(benutzerConfig, schädlichePayload);
// Jetzt hat JEDES Objekt isAdmin = true
const benutzer = {};
console.log(benutzer.isAdmin); // true! Sicherheitsumgehung!
// Verwundbar: Pfadbasierter Eigenschaftszugriff
function verwundbarSet(obj, pfad, wert) {
const schlüssel = pfad.split('.');
let current = obj;
for (let i = 0; i < schlüssel.length - 1; i++) {
// VERWUNDBAR: Keine Prüfung auf __proto__ oder constructor
if (!current[schlüssel[i]]) {
current[schlüssel[i]] = {};
}
current = current[schlüssel[i]];
}
current[schlüssel[schlüssel.length - 1]] = wert;
}
// Angreifer kann Prototyp verschmutzen
verwundbarSet({}, '__proto__.schädlich', 'Payload');
console.log({}.schädlich); // 'Payload'
Sichere Lösung
// Sicher: Rekursives Merging mit Prototyp-Schutz
function sicheresMerge(target, source) {
// Sicher: Nur eigene Eigenschaften verarbeiten
for (const key of Object.keys(source)) {
// Sicher: Gefährliche Schlüssel ablehnen
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
continue;
}
if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
if (!target[key] || typeof target[key] !== 'object') {
target[key] = {};
}
sicheresMerge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
// Sicher: Object.create(null) für Benutzerdaten verwenden
function sichererBenutzerSpeicher() {
// Erstellt Objekt ohne Prototyp - immun gegen Prototype Pollution
const speicher = Object.create(null);
return speicher;
}
// Sicher: Map anstelle von Objekten verwenden
function sichererMapSpeicher() {
// Map erbt keine Eigenschaften von Object.prototype
const speicher = new Map();
return speicher;
}
// Sicher: Object.freeze verwenden, um Prototyp-Modifikation zu verhindern
Object.freeze(Object.prototype);
// Sicher: Pfadbasierter Zugriff mit Schutz
function sichererSet(obj, pfad, wert) {
const verboteneSchlüssel = new Set(['__proto__', 'constructor', 'prototype']);
const schlüssel = pfad.split('.');
// Sicher: Alle Pfadteile validieren
for (const schlüsselTeil of schlüssel) {
if (verboteneSchlüssel.has(schlüsselTeil)) {
throw new Error(`Verbotener Schlüssel: ${schlüsselTeil}`);
}
}
let current = obj;
for (let i = 0; i < schlüssel.length - 1; i++) {
// Sicher: hasOwnProperty verwenden
if (!Object.prototype.hasOwnProperty.call(current, schlüssel[i])) {
current[schlüssel[i]] = Object.create(null);
}
current = current[schlüssel[i]];
}
current[schlüssel[schlüssel.length - 1]] = wert;
}
// Sicher: Eingabevalidierung mit Schema
function validiereBenutzerEingabe(eingabe, schema) {
const validiert = {};
for (const [schlüssel, regeln] of Object.entries(schema)) {
// Sicher: Nur erlaubte Schlüssel aus Schema
if (Object.prototype.hasOwnProperty.call(eingabe, schlüssel)) {
const wert = eingabe[schlüssel];
if (typeof wert === regeln.type) {
validiert[schlüssel] = wert;
}
}
}
return validiert;
}
Ausgenutzt in der Praxis
jQuery Prototype Pollution (2019)
Eine Prototype-Pollution-Schwachstelle in jQuery vor Version 3.4.0 ermöglichte es Angreifern, Object.prototype zu verschmutzen, was Millionen von Websites betraf, die die Bibliothek verwendeten.
Lodash Prototype Pollution (2019)
Eine kritische Prototype-Pollution-Schwachstelle in Lodash betraf über 4 Millionen Projekte und ermöglichte Angreifern, Eigenschaften in Object.prototype über die defaultsDeep-Funktion einzufügen.
Tools zum Testen und Ausnutzen
-
Burp Suite - Web-Sicherheitstesting-Tool, das Prototype-Pollution testen kann.
-
ppfuzz - Spezialisiertes Tool zum Scannen auf Prototype-Pollution-Schwachstellen.
-
ppmap - Scannen auf Client-seitige Prototype-Pollution-Schwachstellen.
CVE-Beispiele
-
CVE-2019-11358 - jQuery-Prototype-Pollution ermöglicht Eigenschaftsinjektion über extend-Funktion.
-
CVE-2020-8203 - Lodash-Prototype-Pollution betrifft zipObjectDeep.
-
CVE-2021-25928 - sails-Paket-Prototype-Pollution ermöglicht Remote-Code-Ausführung.
Referenzen
-
MITRE Corporation. "CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')." https://cwe.mitre.org/data/definitions/1321.html
-
Portswigger. "Prototype Pollution." https://portswigger.net/web-security/prototype-pollution
-
OWASP. "Prototype Pollution Prevention Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Prototype_Pollution_Prevention_Cheat_Sheet.html