Bcrypt – Passwörter sicher hashen in Node.js

Passwörter sicher hashen mit BcryptWill man Passwörter in einer Datenbank speichern, so empfiehlt es sich aus Sicherheits- und Datenschutzgründen, diese nicht direkt in der Datenbank zu speichern, sondern sie vorher durch eine Hashfunktion zu ziehen. Bei einer Hashfunktion handelt es sich um eine Art Verschlüsselung, bei der ein Passwort am Ende nicht mehr als Klartext, sondern als verschlüsselter Code erhalten ist.

Eine Hashfunktion ist immer eine mathematische Einwegfunktion, was bedeutet, dass man aus dem eingegebenen Passwort zwar einen Hash errechnen kann, aber aus dem Hash nicht (oder nur erschwert) das verwendete Passwort. Somit kann weder der Datenbankadministrator die Passwörter der Benutzer sehen, noch ein Angreifer dem es gelingt, sich Zugriff auf die Datenbank zu verschaffen und deren Inhalte auszulesen.

MD5 und SHA für Passwörter? #

Es gibt verschiedene Hashfunktionen, die wahrscheinlich bekanntesten heißen MD5, SHA, SHA-2 und SHA-3. Diese haben jedoch im Bezug zu Passwörtern den Nachteil, dass ein gleicher Eingabewert bei jedem Hashvorgang auch den gleichen verschlüsselten Hash-Code erzeugt. Somit kann man anhand des Hash-Codes z.B. erkennen, ob zwei Benutzer das gleiche Passwort haben, oder sogar ob es sich dabei um ein bekanntes Passwort handelt, und wenn ja um welches.

Während sie für andere Einsatzzwecke wie das Signieren von Dateien durchaus geeignet ist, sollten sie für die Verschlüsselung von Passwörtern nicht verwendet werden. Stattdessen sollte man Passwörter mit Hashfunktionen verschlüsseln, die speziell hierfür entwickelt wurden.

Bcrypt #

Eine solche Hashfunktion – die speziell für Passwörter entwickelt wurde – heißt Bcrypt. Anders als die vorher genannten Hashfunktionen erzeugt sie bei einem gleichem Eingabewert mit jedem Vorgang einen anderen Hash-Code. Dennoch kann geprüft werden, ob ein Passwort dem Code entspricht, was beim einloggen von Benutzern erforderlich ist. Dieses Verhalten wird durch eine Art Zufallsgenerator ermöglich, denn ein Bcrypt-Hash-Code enthält neben dem eigentlichem Hash auch einen sogenannten Salt (englisch wortwörtlich für Salz), der ein Zufallscode und Schwierigkeitsgrad in einem ist.

Schwierigkeitsgrad #

Und damit sind wir auch gleich beim nächstem Vorteil von Bcrypt, nämlich dem Schwierigkeitsgrad. Anders als bei anderen Hashfunktionen lässt sich mit Bcrypt der Schwierigkeitsgrad beliebig einstellen. Je höher der Schwierigkeitsgrad ist, umso schwieriger ist die Berechnung eines Hashes, und desto sicherer ist er.

Da der verwendete Schwierigkeitsgrad in jedem erzeugen Hash enthalten ist, kann man ihn ohne Probleme im laufendem Betrieb erhöhen, ohne die Passwörter doppelt zu prüfen oder zu verlangen, dass alle Benutzer ihr Passwort ändern müssen. Alle neu erzeugten Hashes verwenden dann den neuen Schwierigkeitsgrad, während die alten weiterhin mit dem vorherigen laufen, bis der hash neu erzeugt wird. Sobald ein Benutzer sein Passwort ändern würde, würde der neue Hash auch den neuen Schwierigkeitsgrad enthalten.

Für besonders hohe Sicherheitsanforderungen könnte man auch eine Funktion programmieren, die – nach dem erhöhen das Sicherheitsgrades – beim bloßen einloggen eines Benutzers den Hash mit dem neuen Schwierigkeitsgrad erneut berechnet.

Ein mit Bcrypt gehashtes Passwort kann übrigens bis zu 55 Zeichen enthalten. Falls das zu wenig sein sollte, oder man aus anderen gründen eine andere Passwort-Hashing sucht, sind Scrypt und PBKDF2 zwei gute Alternativen zu Bcrypt.

Bcrypt unter Node.js #

Um Bcrypt unter Node.js zu verwenden, steht das gleichnamige Modul bcrypt zur Verfügung. Zuerst installiert man es via NPM mit der Anweisung:

npm install bcrypt

Danach lädt man das Modul in das entsprechende Programm:

var bcrypt = require('bcrypt');

Um ein Passwort mit Bcrypt zu hashen, kann man nun die Funktion bcrypt.hash() verwenden:

var password = 'Ein streng geheimes Passwort';
bcrypt.hash(password, 10, function(err, hash) {
    if (!err) {
        // wenn alles okay ist
        console.log('der Hash lautet: ' + hash);
    } else {
        // wenn ein Fehler aufgetreten ist
        console.log('Fehler: ' + hash);
    }
});

Dabei erwartet die Funktion bcrypt.hash() als ersten Parameter das Passwort, als zweites den Schwierigkeitsgrad, und als letztes die Rückruf-Funktion. Diese bekommt wiederum als ersten Parameter einen Fehler übergeben (sofern aufgetreten), und als zweites den erzeugten Hash (sofern kein Fehler vorhanden ist).

Mit bcrypt.compare() kann man ein eingegebenes Passwort anschließend mit dem Hash überprüfen:

var password = 'Ein streng geheimes Passwort';
var hash = 'hier den Hash zum Überprüfen einsetzen';
bcrypt.compare(password, hash, function(err, res) {
    if (!err) {
        // wenn kein Fehler aufgetreten ist
        if (res === true) {
            // wenn das Passwort stimmt
            console.log('Das Passwort stimmt.');
        } else {
            // wenn das Passwort falsch ist
            console.log('Das Passwort ist falsch.');
        }
    } else {
        // wenn ein Fehler aufgetreten ist
        console.log('Fehler: ' + hash);
    }
});

Die Funktion bcrypt.compare() erwartet als ersten Parameter das zu überprüfende Passwort, als zweites den Hash, und als letztes wieder eine Rückruf-Funktion. Diese bekommt wie die vorherige Rückruf-Funktion als ersten Parameter einen eventuell aufgetretenen Fehler, und als zweiten entweder true (wenn das Passwort stimmt) oder false (wenn das Passwort falsch ist) übergeben.

Falls man Salt und Hash unabhängig voneinander generieren möchte, so kann man dazu die Funktion genSalt() verwenden:

bcrypt.genSalt(10, function(err, salt) {
    bcrypt.hash('Ein streng geheimes Passwort', salt, function(err, hash) {
        // ...
    });
});

Die restliche Verwendung ist dabei der von bcrypt.hash ohne bcrypt.genSalt gleich.

Wenn man Fehler ignorieren und nicht abfangen möchte, kann man die if(!err)-Abfrage übrigens weglassen. In die Beispiele habe ich diese Abfrage jedoch mit hinzugefügt, damit beim Austesten die aufgetretenen Fehler angezeigt werden, sofern es welche gibt.

Falls man eine synchron arbeitendes Programm schreiben möchte, kann man die gleichen Funktionen einfach ohne übergebene Rückruf-Funktion verwenden. Daraufhin wird das Skript angehalten, bis der Hash errechnet, geprüft, bzw. der Salt generiert wurde. In den meisten Fällen ist dieses Verhalten jedoch nicht erwünscht, weshalb man die asynchrone Verwendung einsetzen sollte.

VN:F [1.9.22_1171]
Bewertung: 3.7/5 (3 Bewertungen)
Bcrypt – Passwörter sicher hashen in Node.js, 3.7 out of 5 based on 3 ratings
Regelmäßige Beiträge über Node.js

nodecodeAbonniere den kostenlosen NodeCode-Newsletter, und bleibe auf dem laufenden über neue Beiträge zum Thema Node.js. Darunter:

  • Informationen und Neuigkeiten rund um Node.js und zugehörigen Modulen
  • Vorstellung von interessanten Frameworks und Bibliotheken
  • Anleitungen und Tutorials zu Node.js und weiterführenden Technologien
  • Sowie vieles mehr...

bereits ein erster Kommentar gehe zum kommentieren

  1. klebefolie /

    Vielen dank für den tollen Artikel und die ausführliche Information. Die Informationen sind ziemlich hilfreich.

    Gruß Anna

hinterlasse einen Kommentar