Einführung
Den Schutz von Website-Passwörtern zu gewährleisten, ist eine essentielle Fähigkeit, die jeder Entwickler haben sollte. JavaScript
bietet eine Option, um die sichere Speicherung und Verarbeitung von Passwörtern oder anderen sensiblen Daten mithilfe der Hashing-Algorithmen des BcryptJS
-Moduls von JavaScript
zu gewährleisten.
In diesem Tutorial lernen Sie mehr über BcryptJS
und das Hashing, um einen einfachen Express-Server einzurichten, der Passwörter als Hashes anstatt als Klartext in einer Datenbank speichert und sie zur Authentifizierung des Passworts abruft.
Voraussetzungen
Um dieses Tutorial fortzusetzen, sollten Sie folgende Voraussetzungen erfüllen.
-
Eine stabile Version von Node.js auf Ihrem Computer installiert, mit der Version 12.x oder höher. Sie können diese DigitalOcean-Anleitung verwenden, um die neueste Version von Node.js auf Ihrem Computer zu installieren.
-
Sie sollten wissen, wie man in JavaScript programmiert.
-
_Du solltest Express JS auf deinem Computer installiert haben. Du kannst diese Anleitung verwenden, um zu lernen, wie man einen Express-Server einrichtet.
-
Zuletzt benötigst du die MongoDB Community oder Atlas-Datenbank, um dieses Tutorial abzuschließen. Du kannst es mithilfe einer dieser DigitalOcean-Anleitungen zur_ Installation von MongoDB installieren.
Warum BcryptJS verwenden?
Bcrypt ist ein Hashing-Algorithmus zur Erstellung von Hashes für Passwörter, um sie im Falle eines Datenlecks zu speichern. Dieser fortschrittliche Hashing-Algorithmus verwendet Salze, wodurch er schwer zu knacken ist, z. B. durch Brute-Force-Angriffe.
BcryptJS ist die JavaScript-Implementierung des Bcrypt-Hashing-Algorithmus
, der es Ihnen ermöglicht, die Hash-Verschlüsselung zu verwenden, ohne sich mit komplexen Hashing-Funktionen befassen zu müssen. Einige der Gründe, die BcryptJS zu einer ausgezeichneten Wahl für die Passwortsicherheit machen, sind folgende:
-
Sicherheit – BcryptJS implementiert den Bcrypt-Algorithmus, einen langsamen Algorithmus (was beim Hashing eine gute Sache ist), der eine intensive Rechenleistung erfordert. Dies erschwert es Angreifern, den Passworthash zu knacken, und gewährleistet die Sicherheit von Passwörtern auch im Falle eines Datenlecks._
-
Salzen – BcryptJS übernimmt die Generierung zufälliger Salze für Passwörter, um die Speichersicherheit zu gewährleisten (Wir werden in dem nächsten Abschnitt mehr über Hashes und Salze erfahren). Salze machen den Hash eines relativ schwachen Passworts komplexer und erschweren das Entschlüsseln.
-
Einfache Verwendung – BcryptJS bietet JavaScript-Entwicklern ein Tool zum Verschlüsseln ihrer Passwörter, ohne dass sie ein tiefgreifendes Verständnis von Hashing benötigen._
In dem nächsten Schritt werden wir kurz über Hashes und Salts lernen.
Wie funktioniert das Hashing?
Bevor Sie diese Konzepte in Ihren Projekten verwenden, müssen Sie verstehen, wie Hashing und Salting funktionieren.
Hashing
Hashing wandelt einen einfachen String oder Klartext in eine Zeichenkette zufälliger Zeichen (Verschlüsselung) um. Dadurch wird eine sichere Speicherung und/oder Übertragung sensibler Daten ermöglicht. Hashing umfasst die folgenden Schlüsselschritte:
Eingabe von Daten – Zunächst werden Daten, die beliebigen Typs sein können (binär, Zeichen, dezimal, etc.), als Klartext oder String gespeichert.
Die Hash-Funktion – Die Hash-Funktion ist ein mathematischer Algorithmus, der Eingaben von den Daten entgegennimmt und sie in eine Zeichenkette oder Hash-Codes umwandelt. Hash-Funktionen sind deterministisch (sie produzieren für dieselbe Eingabe dieselbe Ausgabe) und Einweg-Funktionen (Das bedeutet, dass es nahezu unmöglich ist, die Ausgabe von Hash-Funktionen, also einen Hash, in seine Eingabedaten zurückzuentwickeln).
Kollisionsresistenz – Dies bedeutet, dass eine Hash-Funktion unter Berücksichtigung der Kollisionsresistenz erstellt wird, d.h. zwei unterschiedliche Eingaben können nicht den gleichen Ausgabewert (Hash-Code) haben.
Authentifizierung – Die Hash-Funktionen sind deterministisch und erzeugen für dieselbe Eingabe immer denselben Hash-Wert. Bei der Authentifizierung eines als Hash gespeicherten Passworts geht man daher im Allgemeinen davon aus, dass das zu authentifizierende Passwort mit dem in der Datenbank gespeicherten Hash-Wert übereinstimmen muss, um korrekt zu sein.
Salzen
Da Hashing seit Jahrzehnten existiert, gab es Entwicklungen wie Regenbogentabellen, die Milliarden von Datensätzen mit Datenzeichenfolgen und den entsprechenden Hashes auf der Grundlage verschiedener Hashing-Algorithmen enthalten.
Stellen Sie sich jetzt eine Situation vor, in der ein Benutzer beim Erstellen eines Kontos auf Ihrer Website ein schwaches Passwort wählt. Bei einem Datenleck kann ein Angreifer die Hashes Ihrer Benutzer nachschlagen und den Hash für das Benutzerkonto mit einem schwachen Passwort finden. Dies wäre in hochsicherheitsrelevanten Anwendungen katastrophal. Um dies zu verhindern, werden Salze verwendet.
Salzen ist eine zusätzliche Sicherheitsebene, die Hashes durch Hinzufügen einer zufälligen Zeichenfolge zum Hash eines Passworts vor der Speicherung in einer Datenbank absichert. Selbst wenn die Daten bei einem Datenleck veröffentlicht werden, wird es für einen Angreifer schwer sein, einen mit Salz versehenen Hash zu entschlüsseln. Betrachten Sie das folgende Beispiel:
Wie wir klar erkennen können, ist das Passwort, das mit einem Salt gespeichert wird, aufgrund der deterministischen Natur von Hashes unwahrscheinlicher zu knacken. Wenn ein Angreifer zum Beispiel diese Hash+Passwort-Zeichenfolge in einer Rainbow-Tabelle nachschlägt, erhält er nicht die tatsächliche Passwort-Zeichenfolge, sondern etwas völlig anderes.
Jetzt bist du bereit, BcryptJS zu verwenden und deine Passwörter auf industrieübliche Weise zu sichern.
Installieren von BcryptJS und anderen erforderlichen Modulen
Jetzt, da du über das Hashing und Salting Bescheid weißt, bleibt dir nur noch, deinen Computer zu nehmen und mit dem Programmieren zu beginnen. Die Projektstruktur wird wie folgt aussehen:

Zuerst erstellen wir ein npm-Projekt mit den folgenden Schritten:
-
Öffne einen Ordner und erstelle eine Datei namens
app.js.
-
Öffne ein Terminalfenster in diesem Ordner und gib den Befehl ein
Danach wirst du nach Eingaben gefragt, aber du kannst einfach Enter drücken, ohne Eingaben bereitzustellen.
- Dann erstelle 3 weitere Dateien, nämlich
auth.js
db.js
User.js
- In demselben Terminalfenster gib den folgenden Befehl ein, um die erforderlichen Pakete zu installieren.
Sie haben jetzt eine vollständige Projektmittelumgebung eingerichtet, der Sie in diesem Tutorial folgen können. Im nächsten Schritt erfahren Sie, wie Sie einen Server erstellen, um BcryptJS zur sicheren Speicherung und Authentifizierung von Passwörtern mit MongoDB zu verwenden.
Einrichten eines Servers mit Express JS
Jetzt, da Sie die Projektstruktur eingerichtet haben, können Sie einen Server erstellen, der bcrytjs
verwendet, um Passwörter sicher zu speichern und zu authentifizieren. Wir werden den Server mit den folgenden Schritten erstellen.
Schritt 1 – Eine Verbindung zur MongoDB-Datenbank herstellen
Um eine Verbindung zur mongoDB
herzustellen, verwenden wir die Community Edition. Um das Projekt organisiert zu halten, speichern Sie den Code für die Einrichtung einer Verbindung in der Datei db.js
.
Hier importieren Sie das Paket mongoose
, das eine API zum Verbinden von JavaScript mit MongoDB
bereitstellt. In diesem Fall handelt es sich bei der Verbindungs-URI um eine lokale Installation von MongoDB. Wenn Sie eine Cloud-Datenbank verwenden (wie Atlas), müssen Sie die URI nur auf die spezifische URI Ihrer Datenbank ändern.
Info
Eine URI ähnelt einer Server-URL mit dem Unterschied, dass eine URI den Namen und die Identität der Ressourcen und deren Standort im Internet identifizieren kann. Im Gegensatz dazu ist eine URL eine Teilmenge einer URI, die nur letzteres tun kann.
Die Funktion connectToMongo
ist eine async Funktion, weil mongoose.connect
ein Javascript-Versprechen zurückgibt. Diese Funktion gibt eine Verbindung bei erfolgreicher Ausführung zurück. Andernfalls wird ein Fehler zurückgegeben.
Zuletzt verwenden wir module.exports
, um diese Funktion zu exportieren, wenn das Modul db.js
importiert wird.
Schritt 2 – Erstellen eines Benutzerschemas
Sie benötigen ein grundlegendes Schema, um Benutzer mit einer MongoDB-Datenbank zu erstellen oder zu authentifizieren. Wenn Sie nicht wissen, was ein Schema ist, können Sie diesen ausgezeichneten DO-Leitfaden verwenden, um das Schema in MongoDB zu verstehen und zu erstellen. Wir werden nur zwei Felder für unser Schema verwenden, E-Mail
und Passwort
.
Verwenden Sie den folgenden Code in Ihrem Modul User.js
.
Wir erstellen zwei Felder in diesem Schema, email
und password
. Beide sind erforderliche Felder vom Datentyp String. Außerdem ist email
ein eindeutiges Feld, das bedeutet, dass eine E-Mail-Adresse nur einmal verwendet werden kann, um ein Konto auf diesem Server zu haben.
Zum Schluss exportieren wir ein Modell namens users
. Ein Modell repräsentiert ein Schema auf der Datenbankseite. Man kann sich ein Schema als eine Regel zum Definieren eines Modells vorstellen, während das Modell als eine Sammlung in der MongoDB-Datenbank gespeichert wird.
Man kann ein Schema mit der model()-Funktion der mongoose
-Bibliothek in ein Modell umwandeln.
Schritt 3 – Einrichten des Servers in app.js
Nachdem Sie die vorherigen Schritte befolgt haben, haben Sie erfolgreich ein Modell und ein Modul erstellt, um eine Verbindung zur MongoDB-Datenbank herzustellen. Jetzt lernen Sie, den Server einzurichten. Verwenden Sie den folgenden Code in Ihrer app.js
-Datei.
Hier importieren wir die Module express
und db.js
, um eine Verbindung zur MongoDB herzustellen. Dann verwenden wir das Middleware express.json()
, um JSON-Antworten zu verarbeiten. Die Routen werden in einem separaten Modul (auth.js
) erstellt, um den Code sauber und organisiert zu halten. Schließlich erstellen wir einen Endpunkt, auf dem der Server auf Port 3300
auf localhost lauscht. (Sie können jeden beliebigen Port verwenden)
Passwörter verschlüsseln und in einer MongoDB-Datenbank speichern
Bis zu diesem Punkt ist der Server fast fertig und jetzt werden Sie Endpunkte für den Server erstellen. Wir werden zwei Endpunkte erstellen – signup
und login
. Im Signup-Endpunkt nehmen wir die E-Mail und das Passwort eines neuen Benutzers entgegen und speichern es verschlüsselt für ein Passwort mit Hilfe von BcryptJS.
In der Datei auth.js
geben Sie den folgenden Code ein:
Wir importieren die erforderlichen Module und richten dann den Express Router ein, um den Endpunkt /signup
zu erstellen. Wir verwenden die Methode POST
, damit die Anmeldedaten nicht in der URL der Anwendung angezeigt werden. Danach erstellen wir ein Salt mit der Funktion genSalt
des Pakets scripts
; der Parameter, der an die Funktion genSalt() übergeben wird, enthält die Länge des Salt-Zeichens. Dann verwenden wir die Funktion hash() von BcryptJS, die einen erforderlichen Parameter, den zu hashenden Passwort-String, und ein optionales Argument, den Salt-String, annimmt. Danach gibt sie einen Hash zurück, der sowohl das Passwort
als auch das Salt
enthält.
Nachdem dies geschehen ist, verwenden wir die Funktion create() des Moduls mongoose
, um ein Dokument in unserer Datenbank zu erstellen, das durch die Regeln des Modells users definiert ist. Es wird ein Javascript
-Objekt benötigt, das E-Mail und Passwort enthält. Anstatt ihm einen einfachen String zu übergeben, geben wir jedoch secPass (Passworthash + Salt) weiter, um es in der Datenbank zu speichern. Auf diese Weise haben wir ein Passwort sicher in der Datenbank gespeichert, indem wir seinen Hash zusammen mit einem Salt verwenden, anstatt einen einfachen String zu verwenden. Schließlich geben wir eine JSON
-Antwort zurück, die das Benutzermodell enthält. (Diese Methode, um Antworten zu senden, gilt nur für die Entwicklungsphase; in der Produktion ersetzen Sie dies durch einen Authentifizierungstoken oder etwas Ähnliches).
Um diesen Endpunkt zu testen, müssen Sie zuerst den Server starten, was durch Eingabe des folgenden Befehls in das Terminal erfolgt:
Dieser Befehl führt Ihren Server auf localhost und Port 3300
(oder einem anderen gewünschten Port) aus. Anschließend können Sie eine HTTP
-Anfrage an die URL http://localhost:3300/auth/signup
mit dem folgenden Body senden:
Dies erzeugt die folgende Ausgabe/Antwort:
Hinweis: Der Passworthash und die ID werden nicht gleich sein, da sie immer eindeutig sind.
In dem folgenden Abschnitt erfahren Sie, wie Sie auf den gespeicherten Hash für das Passwort zugreifen und ihn mit einem beim Login/Authentifizierung bereitgestellten Passwort authentifizieren können.
Zugriff auf das verschlüsselte Passwort und Verwendung zur Authentifizierung
Bisher haben Sie gelernt, wie man BcryptJS,
Hashing,
Salting
verwendet und einen Express-Server
entwickelt, der neue Benutzer mit Passwörtern als Hashes speichert. Jetzt lernen Sie, wie Sie das gespeicherte Passwort verwenden und einen Benutzer authentifizieren können, wenn er versucht, sich bei der Anwendung anzumelden.
Fügen Sie eine Authentifizierungsmethode hinzu, indem Sie den folgenden Routenabschnitt in Ihrer auth.js
nach der /signup
-Route hinzufügen:
Hier verwenden wir den Unterpfad /auth/login
, um die Anmeldung für einen bereits vorhandenen Benutzer zu authentifizieren. Ähnlich wie der /auth/signup
-Endpunkt handelt es sich hierbei um eine asynchrone Funktion mit await, da BcryptJS Promises zurückgibt.
Zunächst verwenden wir die Funktion findOne
der Mongoose-Bibliothek, um ein Dokument in einer Sammlung anhand einer bestimmten Suchanfrage zu finden. In diesem Fall suchen wir den Benutzer anhand der E-Mail. Wenn kein Benutzer mit der angegebenen E-Mail vorhanden ist, wird eine Antwort mit dem Statuscode 400 für ungültige Anmeldeinformationen gesendet. (Es ist keine gute Praxis, während der Anmeldung anzugeben, welcher Parameter falsch ist, da Angreifer diese Informationen verwenden können, um vorhandene Konten zu finden).
Wenn der Benutzer mit der angegebenen E-Mail existiert, geht das Programm zur Passwortüberprüfung über. Hierfür bietet BcryptJS
die Methode compare()
an, die einen Rohstring als ersten Argument und einen Hash
(mit oder ohne Salt
) als zweites Argument annimmt. Sie gibt dann ein Boolean Promise
zurück; true
, wenn das Passwort mit dem Hash übereinstimmt, und false
, wenn sie nicht übereinstimmen. Anschließend können Sie eine einfache Überprüfung mit einer if-Anweisung durchführen und je nach Vergleichsergebnis Erfolg oder Fehler zurückgeben.
Zum Schluss exportieren Sie den Express Router
mit module.exports, damit er von dem Ausgangspunkt app.js
für die Routen verwendet werden kann.
Um diese Route zu testen, können Sie eine weitere HTTP
-Antwort an die URL http://localhost:3300/auth/login
mit dem folgenden Body senden:
Diese Anfrage gibt die folgende Antwort zurück:
Zum Schluss wird auth.js
wie folgt aussehen:
Fazit
In diesem Tutorial wurde ein Server erstellt, um die Verwendung von BcryptJS zur sicheren Speicherung und zum Zugriff auf Passwörter in einer Datenbank zu erläutern. Sie können dies weiter ausbauen, indem Sie:
-
Weitere Routen für andere Aufgaben wie das Abrufen von Benutzeranmeldeinformationen, das Aktualisieren von Benutzeranmeldeinformationen usw. implementieren.
-
Implementieren von Authentifizierungstokens, die als Antworten gesendet werden, usw.
Dies ist der Beginn Ihrer Reise, um Passwörter sicher zu behandeln. Sie können jederzeit weitere Sicherheitstechniken und -technologien hinzufügen, um sicherere und widerstandsfähigere Anwendungen zu erstellen.