In this article
Die 10 wichtigsten Best Practices für Node.js-Sicherheit
Was ist Node.js?
Node.js ist eine plattformübergreifende Open-Source-Plattform für die Entwicklung von Webanwendungen. Als JavaScript-Laufzeitumgebung basiert sie auf der V8-Engine von Chrome und ermöglicht es Entwicklern, skalierbare Webanwendungen schnell und einfach zu erstellen.
Was bedeutet Node.js-Sicherheit?
Node.js selbst ist eine sichere Plattform – viele Open-Source-Pakete von Drittanbietern im Ökosystem sind es jedoch möglicherweise nicht. Diese Pakete werden über den Node Package Manager (NPM) verwendet und sind anfällig für viele verschiedene Arten von Schwachstellen und andere Lizenz- und Sicherheitsrisiken von Node.js. Einige Node.js-Codebasen umfassen Tausende solcher Pakete, wodurch die darauf aufbauenden Anwendungen zahlreichen Risiken ausgesetzt sind.
Warum sollten Sie Node.js absichern?
NPM, das üblicherweise mit der Node.js-Laufzeitumgebung verwendet wird, gehört zu den größten Open-Source-Paket-Ökosystemen. Open-Source-Technologien können ein erhebliches Cybersicherheitsrisiko darstellen. Der Bericht „State of Open Source Security“ von Snyk zeigt beispielsweise, dass ein durchschnittliches Projekt 49 Schwachstellen in 79 direkten Abhängigkeiten aufweist. Außerdem führte ein Entwickler auf GitHub ein Sicherheitsexperiment durch, bei dem er sich Zugriff auf 14 % der NPM-Pakete verschaffen konnte. Weitere 54 % waren potenziell über Abhängigkeitsketten erreichbar.
Das zeigt, dass Node.js allein nicht sicher genug ist, um potenzielle Hackerangriffe auszuschließen. Zusätzlich zu diesen zehn Best Practices für NPM-Sicherheit empfehlen wir die folgenden Maßnahmen, um die Sicherheit von Anwendungen zu gewährleisten, die auf Node.js basieren.
Die 10 wichtigsten Best Practices für die Sicherheit von Node.js
Um den häufigsten Risiken von Node.js entgegenzuwirken, sollten Sie einige wichtige Best Practices umsetzen. Hier sind zehn besonders wertvolle Maßnahmen, mit denen Sie gängige Sicherheitsfallen in Node.js vermeiden können.
1. Protokollierung und Monitoring einrichten
Protokollierung und Monitoring sind für die durchgängige Sicherheit von Node.js äußerst wichtig. Durch die Überwachung Ihrer Logs erhalten Sie Einblick in die Vorgänge innerhalb Ihrer Anwendung und können verdächtige Aktivitäten untersuchen. Zu den wichtigen Protokollierungsebenen gehören „info“, „error“, „warn“ und „debug“. Um den manuellen Aufwand zu reduzieren, können Sie Module wie Bunyan und toobusy-js nutzen, um Protokollierung und Monitoring zu automatisieren.
2. Sorgen Sie für starke Authentifizierungsrichtlinien
Vielleicht ist Ihnen aufgefallen, dass bei mehreren der oben genannten potenziellen Angriffe ein böswilliger Akteur die Benutzerauthentifizierung umgeht oder ausnutzt. Starke Authentifizierungsrichtlinien sind ein wichtiger Schutz vor solchen Angreifern. Hier sind einige Richtlinien zur Authentifizierung:
Verlangen Sie Multi-Faktor-Authentifizierung (MFA) und Single Sign-on (SSO).
Verwenden Sie die Bibliotheken Scrypt oder Bcrypt anstelle der Node.js-Crypto-Bibliothek.
Setzen Sie einheitliche Richtlinien für die Sitzungsverwaltung um.
Verlangen Sie sichere Benutzerpasswörter.
Begrenzen Sie die Anzahl fehlgeschlagener Anmeldeversuche.
3. Blockieren Sie nicht den Event Loop
Wenn Sie umfangreiche Aufgaben in Ihrem Event Loop oder den Threads Ihres Worker-Pools ausführen, können Anfragen anderer Clients ins Stocken geraten und Ihr Durchsatz sinken. So stellen Sie sicher, dass Ihre Threads verfügbar bleiben:
Sorgen Sie dafür, dass Ihre JavaScript-Callbacks schnell ausgeführt werden.
Verringern Sie die Komplexität Ihrer Callbacks, indem Sie unabhängig vom Argument eine gleichbleibende Anzahl von Schritten sicherstellen. So erhält jeder Client in der Warteschlange eine faire Chance.
Begrenzen Sie bei komplexen Aufgaben die Eingaben und weisen Sie umfangreiche Eingaben zurück. Bei begrenzten Eingaben erfolgt die Ausführung anhand des Zeitrahmens für den ungünstigsten Eingabefall. So wird sichergestellt, dass der Thread nicht blockiert (natürlich müssen Sie zunächst sicherstellen, dass der Zeitrahmen für den ungünstigsten Eingabefall kurz genug ist, um eine Blockierung des Threads zu vermeiden).
Verwenden Sie keine synchronen APIs aus den Modulen für Verschlüsselung, Komprimierung, Dateisysteme oder Child-Prozesse. Sie benötigen viel Zeit für die Ausführung und können Ihren Event Loop blockieren.
4. Fehler sicher behandeln
Viele Probleme mit der Anwendungsleistung und -sicherheit lassen sich vermeiden, wenn Sie Ihren Code auf die Behandlung von Fehlern vorbereiten. Mit den folgenden Best Practices halten Sie Ihre Programme fehlerfrei:
Verwenden Sie zur Verwaltung asynchroner Fehler statt Callbacks eine zuverlässige Promise-Bibliothek oder Async/Await.
Individuelle oder String-basierte Fehlerbehandlung erhöht die Komplexität. Vereinfachen Sie die Fehlerbehandlung, indem Sie immer das integrierte Fehlerobjekt verwenden.
Die Fehlerbehandlung in Middleware kann zu doppeltem Code führen. Die Logik für die Fehlerbehandlung sollte zentral verwaltet werden.
Testen Sie Ihre Fehlerabläufe regelmäßig, damit Sie sicher sein können, dass sie weder Fehlalarme auslösen noch tatsächliche Fehler übersehen.
Verwenden Sie ein Prozessverwaltungstool, das den Prozess bei einem unbekannten Fehler neu startet. Pm2 und forever sind Beispiele für Prozessverwaltungstools für Node.js.
5. Senden Sie keine unnötigen Informationen
Wenn Sie Informationen an das Frontend senden, achten Sie darauf, dass Sie nur unbedingt erforderliche Daten übermitteln. Theoretisch können Sie zwar beliebige Informationen aus der Anzeige herausfiltern, Angreifer können jedoch weiterhin über das Backend auf verborgene Daten zugreifen. Sensible Daten sind nur dann sicher vor unbefugtem Zugriff, wenn Sie sie gar nicht erst senden – es sei denn, dies ist unbedingt erforderlich.
6. Begrenzen Sie die Größe von Anfragen
Die Standardgrenze für Anfragen in Node.js beträgt 5 MB. Um DDoS-Angriffe zu verhindern, bei denen Hacker Ihre Server mit Anfragen überfluten, können Sie die zulässige Größe von Node.js-Anfragen weiter begrenzen.
Dafür gibt es zwei einfache Möglichkeiten:
Konfigurieren Sie die Option „limit“ im body-parser-Paket, sodass nur kleine Payloads akzeptiert werden.
Legen Sie mithilfe von Reverse-Proxys oder Express-Middleware Größenbeschränkungen für bestimmte Inhaltstypen fest.
7. Validieren Sie Benutzereingaben
Ein Grund dafür, dass böswillige Akteure erfolgreiche XSS-Angriffe durchführen können, ist die fehlende Validierung von Benutzereingaben. Bereinigen Sie Ihre Benutzereingaben zunächst mit einem NPM-Paket wie DOMPurify. Verwenden Sie anschließend eine Formularvalidierungsbibliothek wie express-validator oder XSS-filters. Formularvalidierungsbibliotheken automatisieren die monotone Aufgabe, jede Eingabe in jeder Anfrage zu überprüfen. Kontextabhängige Ausgabefilter wie XSS-filters sind entwicklerfreundlich und kodieren nur die mindestens erforderliche Anzahl von Zeichen, um einen XSS-Angriff abzuwehren.
8. Sorgen Sie für eine sichere Deserialisierung
Node.js bietet keine fortgeschrittenen Formen der Objektserialisierung. Deshalb können Angreifer serialisierte Objekte verwenden, um Payloads zu übertragen. Implementieren Sie Integritäts- und Benutzerauthentifizierungsprüfungen und bereinigen Sie deserialisierte Daten, um dies zu verhindern. Verwenden Sie zusätzlich Anti-CSRF-Tokens, benutzerdefinierte Anfrage-Header, das SameSite-Flag in Cookie-Sitzungen und Schutzmaßnahmen, die auf Benutzerinteraktionen basieren.
9. Verwenden Sie Security-Linter und SAST-Tools
Um Schwachstellen zu beheben, die zu einem Angriff führen könnten, müssen Sie zunächst wissen, wo sie sich befinden. Mit Tools wie Linter-Plugins und Static Application Security Testing (SAST) können Sie diesen Prozess automatisieren und vermeiden, etwas zu übersehen.
Linter wie eslint-plugin-node-security analysieren Quellcode, um unsichere Praktiken zu erkennen und hervorzuheben. SAST-Tools wie Snyk Code überwachen Ihren Node.js-Code während der Entwicklung und weisen Sie auf potenzielle Schwachstellen hin.
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.
10. Führen Sie Node.js als Nicht-Root-Benutzer aus
Dies ist grundsätzlich eine gute Vorgehensweise, bei Node.js sollten Sie jedoch besonders darauf achten, es nicht als Root-Benutzer auszuführen. Wenn Sie Node.js als Nicht-Root-Benutzer ausführen, begrenzen Sie die potenzielle Angriffsfläche, die böswillige Akteure ausnutzen können.
Diese Empfehlung folgt dem Prinzip der geringsten Privilegien: Geben Sie Benutzern nur genau die Zugriffsrechte, die sie für ihre Arbeit benötigen. Root-Zugriff sollte nur in ganz bestimmten Situationen gewährt werden.
Snyk leistet einen Beitrag zur Sicherheit von Node.js
Seit Mai 2021 trägt Snyk zur Sicherheit des Node.js-Ökosystems bei und hat das Programm zur Offenlegung von Schwachstellen im Node.js-Ökosystem übernommen. Das engagierte Team von Sicherheitsanalysten und Forschern bei Snyk prüft Meldungen zu Schwachstellen in Node.js, verifiziert sie und kontaktiert die Maintainer der betroffenen Pakete, um den Prozess der verantwortungsvollen Offenlegung gemäß der Offenlegungsrichtlinie von Snyk einzuleiten.
Darüber hinaus helfen Ihnen die Produkte von Snyk, Schwachstellen in nur fünf Minuten zu finden und zu beheben. So verbessert Snyk die Sicherheit von Node.js:
Snyk Open Source hilft dabei, Schwachstellen in den Abhängigkeiten einer Node.js-Anwendung zu erkennen und Entwickler darauf hinzuweisen. So ist Ihr Code vor den wichtigsten Sicherheitsrisiken geschützt, die wir heute behandelt haben.
Snyk Code ist ein SAST-Tool, das Schwachstellen im Anwendungscode erkennt und Entwickler darauf hinweist.
Snyk Container hilft Entwicklern dabei, Schwachstellen in Containern und Kubernetes-Workloads während des gesamten SDLC zu finden.
Wenn Sie Node.js in Containern verwenden, finden Sie hier weitere von uns empfohlene Best Practices für die Containerisierung von Node.js-Anwendungen mit Docker.
Snyk für JavaScript-Sicherheit
Von Ihrer ersten Codezeile bis zu Ihrer letzten npm-Abhängigkeit schützt Snyk Ihre JavaScript-Anwendungen direkt in Ihrer IDE, CLI und Ihren Git-Workflows.
Häufig gestellte Fragen zur Sicherheit von Node.js
Ist Node.js sicher?
Die Node.js-Plattform ist von Grund auf sicher. Da sie jedoch über ihr Paketverwaltungssystem npm Open-Source-Pakete von Drittanbietern nutzt, ist sie anfällig für Cyberangriffe. Unternehmen müssen Best Practices wie die in diesem Artikel beschriebenen umsetzen, um die Sicherheit von Node.js zu gewährleisten.
Wie können Sie Node.js absichern?
Gute erste Schritte zur Absicherung von Node.js sind Praktiken wie die Validierung von Benutzereingaben, die Implementierung von Authentifizierung, die Begrenzung von Anfragegrößen sowie die Einrichtung von Protokollierung und Überwachung. Wenn Sie sich speziell Sorgen über Code-Injection-Angriffe machen, finden Sie hier fünf Möglichkeiten, Code-Injection in Node.js zu verhindern.
Kann Node.js gehackt werden?
Angreifer können Node.js-Anwendungen kompromittieren, indem sie Produktionsserver überlasten, bösartigen JavaScript-Code einschleusen oder zeitaufwendige Eingaben in Ihre Programme einspeisen. Auch die Open-Source-Natur von NPM macht Node.js anfällig für Sicherheitslücken.