ToolPal
Ein Kombinationsschloss auf einer Tastatur als Symbol für Passwortsicherheit

bcrypt-Passwort-Hashing: Der praktische Leitfaden für Entwickler

📷 Pixabay / Pexels

bcrypt-Passwort-Hashing: Der praktische Leitfaden für Entwickler

Alles, was Sie über bcrypt für Passwortsicherheit wissen müssen — Kostenfaktoren, Implementierung in Node.js/Python/PHP und häufige Fehler, die Sie vermeiden sollten.

DVon Daniel Park7. April 20266 Min. Lesezeit

Wenn Sie jemals Benutzerpasswörter speichern mussten, wurden Sie wahrscheinlich aufgefordert, „bcrypt zu verwenden". Es ist seit über zwei Jahrzehnten die Standardempfehlung, und das aus gutem Grund. Aber zu verstehen, warum es funktioniert — und wie man es richtig verwendet — ist das, was eine sichere Implementierung von einer trennt, die nur sicher aussieht.

Dieser Leitfaden behandelt alles Praktische: wie bcrypt tatsächlich funktioniert, welchen Kostenfaktor Sie wählen sollten, wie Sie es in mehreren Sprachen implementieren, und die Fehler, die die Passwortsicherheit still untergraben.

Was bcrypt ist (und warum es existiert)

bcrypt wurde 1999 von Niels Provos und David Mazières speziell für das Passwort-Hashing entworfen. Dieser Kontext ist wichtig. Es wurde nicht gebaut, um schnell zu sein — es wurde gebaut, um langsam auf eine kontrollierte, einstellbare Weise zu sein.

Die Kernerkenntnis hinter bcrypt ist, dass schnelles Hashing eine Schwachstelle ist, wenn es um Passwörter geht. Ein Allzweck-Hash wie SHA-256 kann auf moderner Hardware Milliarden von Hashes pro Sekunde berechnen. Das ist großartig für Checksummen und Datenintegrität. Es ist schrecklich für Passwörter, weil ein Angreifer, der Ihre Passwortdatenbank stiehlt, mit Commodity-GPUs Milliarden von Versuchen pro Sekunde testen kann.

bcrypt löst das durch die Einführung eines Kostenfaktors — ein Parameter, der steuert, wie viel Arbeit der Algorithmus leistet. Sie bestimmen, wie langsam das Hashing ist. Hardware wird jedes Jahr schneller, sodass Sie den Kostenfaktor im Laufe der Zeit erhöhen können, um Schritt zu halten.

Wie bcrypt tatsächlich funktioniert

Wenn Sie bcrypt.hash("mypassword", 10) aufrufen, passieren intern mehrere Dinge:

  1. Ein zufälliger 16-Byte-Salt wird generiert. Dieser Salt ist für jede Hash-Operation einzigartig.
  2. Passwort und Salt werden in das Eksblowfish-Key-Setup eingegeben. Das ist bcrypts Kernalgorithmus — eine modifizierte Version des Blowfish-Verschlüsselungsalgorithmus mit einer teuren Schlüsselerweiterungsphase.
  3. Das Key-Setup wird 2^Kosten-mal wiederholt. Mit Kostenfaktor 10 sind das 1.024 Iterationen. Mit Kosten 12 sind es 4.096 Iterationen. Jedes Inkrement verdoppelt die Arbeit.
  4. Der resultierende Hash wird als 60-Zeichen-String kodiert, der Algorithmusversion, Kostenfaktor, Salt und Hash enthält.

Die Ausgabe sieht so aus:

$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy

Aufschlüsselung:

  • $2b$ — bcrypt-Version
  • 10 — Kostenfaktor
  • Die nächsten 22 Zeichen — der base64-kodierte Salt
  • Die verbleibenden Zeichen — der Hash

Da der Salt in den Hash-String eingebettet ist, müssen Sie ihn nicht separat speichern. Die bcrypt.compare()-Funktion extrahiert den Salt aus dem gespeicherten Hash und verwendet ihn, um das Eingabe-Passwort zu hashen — keine manuelle Salt-Verwaltung erforderlich.

Warum schnelle Hash-Funktionen das falsche Werkzeug sind

Entwickler speichern manchmal Passwörter mit MD5, SHA-1 oder SHA-256. Diese Algorithmen sind weit verbreitet und gut verstanden, sodass die Wahl vernünftig erscheint. Das stimmt nicht.

Das Problem ist nicht, dass diese Algorithmen für ihre beabsichtigten Zwecke gebrochen sind. Das Problem ist, dass sie so designed wurden, schnell zu sein, und schnell ist genau das Falsche für die Passwortspeicherung.

Im Jahr 2012 demonstrierte der Sicherheitsforscher Jeremi Gosney das Cracken von 90% einer durchgesickerten 6,4-Millionen SHA-1-Passwort-Hash-Datenbank in unter einer Stunde. Mit moderner Hardware und Tools wie Hashcat kann ein Angreifer mit einer guten GPU MD5-Hashes mit über 10 Milliarden Versuchen pro Sekunde testen. SHA-256 ist nicht viel besser — etwa 4 Milliarden pro Sekunde.

bcrypt bei Kosten 10 reduziert das auf etwa 20.000 Versuche pro Sekunde. Das ist der ganze Punkt.

Den richtigen Kostenfaktor wählen

Der Kostenfaktor ist die wichtigste Tuning-Entscheidung, die Sie mit bcrypt treffen werden.

Kosten 10 ist der weit verbreitete empfohlene Standard. Auf einem modernen Server erzeugt es einen Hash in etwa 100-300ms. Das ist unmerklich langsam für einen anmeldenden Benutzer, bedeutet aber, dass ein Angreifer nur einige Tausend Passwörter pro Sekunde pro Kern testen kann.

Kosten 12 vervierfacht die Rechenzeit ungefähr im Vergleich zu 10. Es ist eine vernünftige Wahl für Anwendungen mit erhöhten Sicherheitsanforderungen — Banking, Gesundheitswesen, alles, was sensible Finanzdaten verarbeitet — wo Sie 400-1000ms Login-Zeiten akzeptieren können.

Kosten 14 und darüber ist für Webanwendungen normalerweise übertrieben. Bei Kosten 14 dauert das Hashen mehrere Sekunden, was die Benutzererfahrung spürbar beeinträchtigt.

Gehen Sie niemals in der Produktion unter 8. Einige alte Tutorials zeigen Kosten 5 oder 6 als Beispiele. Diese Werte sind zu schnell und bieten unzureichenden Schutz.

Bcrypt in Node.js implementieren

const bcrypt = require('bcrypt');

const COST_FACTOR = 10;

// Passwort hashen
async function hashPassword(plaintext) {
  const hash = await bcrypt.hash(plaintext, COST_FACTOR);
  return hash; // Diesen String in Ihrer Datenbank speichern
}

// Beim Login verifizieren
async function verifyPassword(plaintext, storedHash) {
  const match = await bcrypt.compare(plaintext, storedHash);
  return match; // true oder false
}

// Verwendungsbeispiel
const hash = await hashPassword('hunter2');
console.log(hash); // $2b$10$...

const valid = await verifyPassword('hunter2', hash);
console.log(valid); // true

Bcrypt in Python implementieren

import bcrypt

COST_FACTOR = 10

def hash_password(plaintext: str) -> bytes:
    password_bytes = plaintext.encode('utf-8')
    hashed = bcrypt.hashpw(password_bytes, bcrypt.gensalt(rounds=COST_FACTOR))
    return hashed

def verify_password(plaintext: str, stored_hash: bytes) -> bool:
    password_bytes = plaintext.encode('utf-8')
    return bcrypt.checkpw(password_bytes, stored_hash)

# Verwendung
hashed = hash_password("hunter2")
print(hashed)  # b'$2b$10$...'

print(verify_password("hunter2", hashed))  # True
print(verify_password("wrong", hashed))    # False

Bcrypt in PHP implementieren

<?php
$options = ['cost' => 10];

// Hashen
$hash = password_hash($plaintext, PASSWORD_BCRYPT, $options);

// Verifizieren
$valid = password_verify($plaintext, $hash);

// Prüfen, ob Hash aktualisiert werden muss
if (password_needs_rehash($hash, PASSWORD_BCRYPT, $options)) {
    $newHash = password_hash($plaintext, PASSWORD_BCRYPT, $options);
    // $newHash in der Datenbank speichern
}
?>

Häufige Fehler, die bcrypt untergraben

Das Passwort bei jeder Login-Verifizierung neu hashen. Das ist ein erheblicher Leistungsfehler. Wenn ein Benutzer sich anmeldet, sollten Sie sein Passwort mit bcrypt.compare() gegen den gespeicherten Hash vergleichen. Hashen Sie das Passwort nicht erneut und vergleichen Sie die zwei Hashes — das wird nie übereinstimmen, weil jedes Mal ein neuer zufälliger Salt generiert wird.

Das Klartextpasswort speichern. Offensichtlich, aber es passiert.

MD5 oder SHA für die Passwortspeicherung verwenden. Auch mit manuell hinzugefügtem Salt geben schnelle Hashes Angreifern viel zu viel Durchsatz.

Das 72-Byte-Limit nicht beachten. bcrypt schneidet die Eingabe stillschweigend bei 72 Bytes ab.

Einen zu niedrigen Kostenfaktor verwenden. Wenn Sie Kosten 4 verwenden, weil es schneller ist, verfehlen Sie den Punkt. Die Langsamkeit ist eine Sicherheitseigenschaft, kein Fehler.

Wann Sie Argon2 stattdessen verwenden sollten

bcrypt ist seit 25 Jahren die sichere Standardwahl, aber es ist nicht die moderne Spitzenklasse. Argon2 — speziell Argon2id — gewann 2015 den Password Hashing Competition und behebt bcrypts Hauptschwäche.

bcrypt ist CPU-gebunden: Ein Angreifer mit GPUs kann das Cracken relativ günstig parallelisieren, weil der Algorithmus nicht viel Speicher benötigt. Argon2 ist speicherintensiv: Es erfordert eine konfigurierbare Menge RAM pro Hash-Operation. GPUs haben pro Rechenkern weit weniger Speicher als eine CPU, sodass speicherintensive Algorithmen das Spielfeld erheblich nivellieren.

Zusammenfassung

  • bcrypts Stärke kommt von intentioneller Langsamkeit, nicht von kryptografischer Komplexität
  • Verwenden Sie immer bcrypt.compare() (oder das Äquivalent Ihrer Sprache) zur Verifizierung — niemals hashen und vergleichen
  • Kostenfaktor 10 ist der richtige Standard für die meisten Anwendungen; alle paar Jahre neu bewerten
  • bcrypt behandelt Salting automatisch — Sie müssen Salts nicht verwalten
  • Seien Sie sich der 72-Byte-Kürzungsbegrenzung für ungewöhnlich lange Passwörter bewusst
  • Für neue Projekte ist Argon2id die Überlegung wert; für bestehende bcrypt-Systeme bleiben Sie dabei

Passwortspeicherung ist einer der wenigen Bereiche, in denen die sichere Option — bcrypt mit einem vernünftigen Kostenfaktor — auch einfach korrekt zu implementieren ist. Die meisten Schwachstellen in diesem Bereich entstehen durch das Ignorieren des Rates, nicht durch Fehler im Algorithmus selbst.

Häufig gestellte Fragen

D

Über den Autor

Daniel Park

Senior frontend engineer based in Seoul. Seven years of experience building web applications at Korean SaaS companies, with a focus on developer tooling, web performance, and privacy-first architecture. Open-source contributor to the JavaScript ecosystem and founder of ToolPal.

Mehr erfahren

Artikel teilen

XLinkedIn

Verwandte Beiträge