Mass-Assignment-Schwachstellen in Node.js vermeiden
28. März 2023
0 Min. LesezeitMass Assignment ist eine Schwachstelle, durch die Angreifer vorhersehbare Datensatzmuster ausnutzen und unzulässige Aktionen ausführen können. Mass Assignment tritt häufig auf, wenn Eigenschaften beim Binden von clientseitig bereitgestellten Daten an Datenmodelle nicht gefiltert werden. Schwachstellen dieser Art ermöglichen es Angreifern, zusätzliche Objekte in POST-Anfrage-Payloads einzufügen und so Eigenschaften zu ändern, die unveränderlich sein sollten.
Node.js ist eine Open-Source-Serverumgebung, die plattformübergreifend für die Entwicklung von Webanwendungen eingesetzt werden kann. Damit können Entwickler leistungsstarke, skalierbare Anwendungen schnell erstellen. Node.js ist eine bewährte und produktionsreife Plattform – Herausforderungen bei der Anwendungssicherheit ergeben sich durch die Supply-Chain-Sicherheit von Drittanbieterpaketen, die bei der Entwicklung von Anwendungen installiert werden. Für eine Node.js-Anwendung kommen mitunter Tausende Open-Source-npm-Pakete aus der npm-Registry zum Einsatz, wodurch zahlreiche Angriffsvektoren entstehen.
Mass-Assignment-Schwachstellen treten häufig in Node.js-Anwendungen auf, die Payloads in POST-Anfragen an die Datenbank senden. Angreifer können diese Schwachstellen für SQL-Injection-Angriffe oder andere Angriffe auf in Datenbanken gespeicherte Daten nutzen. Mit einer Mass-Assignment-Schwachstelle können Angreifer ein System vollständig übernehmen oder vertrauliche Daten stehlen. Daher ist es entscheidend, sich gegen diese Art von Angriff zu schützen.
Dieser Artikel zeigt anhand eines Node.js-Projekts, wie eine Mass-Assignment-Schwachstelle entsteht, wie Angreifer sie ausnutzen können und wie Sie eine Webanwendung davor schützen.
Mass-Assignment-Schwachstellen in Node.js beseitigen
In diesem Beispiel verwenden wir Mongoose, eine Object-Data-Modelling-Bibliothek (ODM) für Node.js und MongoDB. Sie verknüpft Objekte im Code mit Objekten in MongoDB, validiert Schemas und erleichtert die Verwaltung von Datenbeziehungen.
Wie oben beschrieben, müssen Sie den Schutz vor Mass Assignment in einer Node.js-MongoDB-Anwendung in Mongoose umsetzen. Im Folgenden sehen Sie ein Beispiel dafür, wie eine Mass-Assignment-Schwachstelle in einer Node.js-Anwendung ausgenutzt werden kann.
Voraussetzungen
Für dieses Projekt benötigen Sie:
Node.js installiert
Zugriff auf eine MongoDB-Datenbank und einen gültigen Verbindungsstring. Dieses Tutorial verwendet eine MongoDB-Atlas-Cloudumgebung. Sie können aber auch einen lokalen MongoDB-Server einrichten und den Verbindungsstring entsprechend anpassen.
Mass Assignment in Node.js
Öffnen Sie zunächst Ihr Terminal und führen Sie diesen Befehl aus:
Installieren Sie anschließend die Abhängigkeiten:
Um die Daten aus dem obigen Formular zu verarbeiten, benötigen wir im Ordner models eine Datei namens newUser.js, die das Benutzerschema verwaltet.
Dieses Modell umfasst alle Felder des Registrierungsformulars. Das zusätzliche Feld isAdmin vom Typ Boolean legt die Rolle eines Benutzers fest. Wenn Sie dieses Feld auf true setzen, erstellen Sie einen Benutzer mit Administratorrechten. Bei false wird ein Benutzer ohne Administratorrechte erstellt.
Erstellen Sie ein neues Verzeichnis namens routes und fügen Sie die Datei routes.js hinzu, um Benutzerdetails zu verarbeiten:
Der obige Code erfasst die Formulardaten und strukturiert sie anschließend mithilfe des Modells newUSer.
Dieser Code weist zwei Schwachstellen auf, die eine Mass-Assignment-Schwachstelle verursachen. Erstens verwendet er für ein vertrauliches Feld einen gängigen Namen und Typ: isAdmin. Zweitens enthält das Benutzermodell ein vertrauliches, ungenutztes Feld. Um die Schwachstelle auszunutzen, starten wir zunächst einen Server.
Erstellen Sie im Stammverzeichnis des Projekts eine Datei namens server.js und fügen Sie den folgenden Code ein. Ersetzen Sie dabei <APP_ID> durch den Wert aus Ihrem Verbindungsstring:
Starten Sie den Server mit node server.js.
Ein Angreifer kann diese Schwachstelle ausnutzen, indem er eine curl POST-Anfrage mit dem Feld isAdmin erstellt und dessen Wert auf true setzt, wie im folgenden Code gezeigt:
Mit der obigen Anfrage wird ein Benutzer namens Mike mit Administratorrechten erstellt. Dieser Benutzer kann sich nun mit seinen Zugangsdaten am System anmelden und alles tun, was auch ein Administrator tun kann.
Schutz vor Mass Assignment
Mit drei Anpassungen können wir die Anwendung besser vor Mass-Assignment-Angriffen schützen.
Schlanke Modelle erstellen
Schlanke Modelle enthalten nur die Eingaben, die ein Benutzer voraussichtlich hinzufügen soll, und schließen vertrauliche Felder aus.
Wie im obigen Beispiel besteht der erste und wichtigste Schritt darin, das vertrauliche Feld aus dem Modell newUser zu entfernen, wie unten gezeigt:
Wenn Angreifer Zugriff auf den Quellcode erhalten, können sie das vertrauliche Feld dann nicht sehen und für einen Angriff nutzen. Vermeiden Sie außerdem vorhersehbare Begriffe in der Datenbank, mit denen die Rolle eines Benutzers festgelegt wird – etwa isAdmin, admin und role –, da Angreifer sie erraten und einen Angriff starten könnten.
Benutzereingaben mit Schema-Validierung prüfen
Validierung mit underscore
Eine weitere Möglichkeit, Ihre Anwendung zu schützen, besteht darin, die Felder festzulegen und einzuschränken, die eine POST-Anfrage verarbeiten darf. Dieses Verfahren wird Allowlisting genannt und verwendet die Bibliothek underscore. Installieren Sie zunächst die Bibliothek:
Wechseln Sie in den Ordner routes und ersetzen Sie den Code in route.js durch diesen:
Im obigen Code verwenden wir die Funktion pick, um die Variablen festzulegen, die aus einer POST-Anfrage extrahiert werden. So verhindern wir, dass Angreifer das vertrauliche Feld isAdmin verwenden.
Die Herausforderung bei underscore besteht darin, dass die Anwendung die Daten erst verarbeiten muss, um festzustellen, ob sie gültig sind. Anders gesagt: Fehler werden nicht früh genug erkannt.
Validierung mit Zod
Für eine robuste Schema-Validierung sollten Sie Zod verwenden. Zod validiert das Schema und stellt sicher, dass die Daten genau der vorgegebenen Struktur, dem Muster und Datentyp entsprechen. Unvollständige oder fehlerhafte Daten erkennt Zod frühzeitig, sodass Anwendungsfehler vermieden werden. Außerdem können Sie einfach eine Fehlermeldung erstellen, die Benutzer über die fehlerhaften Eingaben und die Art des Fehlers informiert.
Der Codeausschnitt veranschaulicht die Funktionsweise von Zod. Beachten Sie, dass der folgende Ausschnitt in TypeScript geschrieben ist und daher eine zusätzliche Konfiguration erfordert.
Wenn ein Benutzer Daten eingibt, die nicht dem Schema entsprechen, wird der Fehler invalid_type_error ausgegeben. Lässt der Benutzer ein Feld leer, wird der Fehler required_error ausgegeben.
Weitere Beispiele für Mass-Assignment-Schwachstellen in ORMs
Sehen wir uns drei weitere Beispiele für Mass-Assignment-Schwachstellen in gängigen ORM-Lösungen an.
Mass-Assignment-Schwachstelle in Sequelize-Code
Sehen wir uns ein Beispiel für anfälligen Sequelize-Code an. Dieser Code definiert ein Benutzermodell, erstellt einen Benutzer und speichert die Benutzerdetails in der Datenbank:
Beim Erstellen eines neuen Benutzers ruft der Controller das obige Modell auf, wie unten gezeigt:
Der obige Code ist anfällig, weil er das vertrauliche Feld is_verified offenlegt. Angreifer können eine POST-Anfrage mit dem Feld is_verified und dem Wert true erstellen und so den Verifizierungsschritt umgehen.
Wir können die Mass-Assignment-Schwachstelle in diesem Code beseitigen, indem wir das Feld is_verified beim Erstellen des Benutzers weglassen. Der sichere Code sieht so aus:
Dadurch werden die zulässigen Variablen einer POST-Anfrage auf Benutzername, E-Mail-Adresse und Passwort beschränkt.
Mass-Assignment-Schwachstelle in Prisma-Code
Im Folgenden sehen Sie ein Beispiel für anfälligen Prisma-Code, der das vertrauliche Feld Role offenlegt.
Um einen Benutzer hinzuzufügen, erstellen wir eine Route namens add_user.
Diese POST-Anfrage erwartet im Body ein Benutzerobjekt. Der obige Code ist anfällig für Mass-Assignment-Angriffe, da Hacker das Feld role auf ADMIN setzen können, um Administratorrechte zu erlangen.
Wir können die Schwachstelle im obigen Code beseitigen, indem wir das vertrauliche Feld Role aus dem Modell ausschließen.
Mass-Assignment-Schwachstelle in MySQL-Code
Hier sehen Sie ein Beispiel für anfälligen MySQL-Code mit Mass Assignment, der das vertrauliche Feld isAdmin offenlegt:
Mit diesem Code wird der oben definierte Benutzer hinzugefügt:
Der obige Code weist eine Mass-Assignment-Schwachstelle auf, weil er das vertrauliche Feld isAdmin offenlegt und erlaubt, es in eine POST-Anfrage aufzunehmen. Angreifer können eine POST-Anfrage erstellen, die das Feld isAdmin auf true setzt und so einen Administratorbenutzer erstellt.
Wir können diese Schwachstelle beheben, indem wir das vertrauliche Feld beim Erstellen des Objekts user weglassen. Der sichere Code sieht so aus:
Der Standardwert false für das Feld isAdmin kann festgelegt werden, indem Sie die Tabelle mit dem folgenden Befehl ändern:
Ihren Node.js-Code sicher halten
Node.js ist sicher, doch die für die Entwicklung einer Webanwendung benötigten Pakete sind es mitunter nicht. Bei Node.js-Anwendungen, die Anfragen an eine Datenbank senden, zählt Mass Assignment zu den häufigsten Angriffsvektoren. Dadurch können böswillige Benutzer SQL-Injection-Angriffe ausführen, bei denen sie schädliche Anfragen an eine Datenbank senden.
Eingaben lassen sich jedoch einfach bereinigen, um Mass Assignment in Node.js zu verhindern. Sie können vertrauliche Felder nicht offenlegen, zulässige Felder einschränken oder die Bearbeitung bestimmter Felder blockieren.
Wenn Sie Eingaben von Benutzern nicht robust validieren, ist Ihr System Angriffen wie Prototype Pollution ausgesetzt. Solche Angriffe können schwache Validierungsmechanismen wie underscore umgehen. Achten Sie daher darauf, stets robuste Lösungen wie Zod einzusetzen.
Sehen Sie sich das vollständige Quellcodebeispiel in unserem GitHub-Repository an und führen Sie eigene lokale Sicherheitsexperimente durch, um zu erfahren, wie Sie Mass-Assignment-Schwachstellen in Node.js vermeiden.
Befolgen Sie Snyks Top 10 der Best Practices für Node.js-Sicherheit, um die Sicherheit Ihrer Node.js-Anwendung zu optimieren.
Starten Sie mit Capture the Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.
