Skip to content
Zurück zum Blog
Sicherheit

bcrypt-Fehler „72 Bytes“: Warum auch kurze Passwörter scheitern

bcrypt 5.0 wirft „password cannot be longer than 72 bytes“ schon bei 14 Byte. Schuld ist eine interne 255-Byte-Sonde von passlib. Kostenloses bcrypt-Tool.

12 Min. Lesezeit

bcrypt-Fehler „72 Bytes“: Warum auch kurze Passwörter scheitern

Zwei völlig verschiedene Probleme erzeugen dieselbe Meldung, und nur eines davon hat überhaupt etwas mit Ihrem Passwort zu tun.

Wenn Ihr Passwort tatsächlich über bcrypts 72-Byte-Limit liegt, liest bcrypt die ersten 72 Bytes und verwirft den Rest. Wir haben zwei 82 Bytes lange Passwörter mit identischen ersten 72 Bytes unter einem festen Salt gehasht. Beide ergaben $2a$10$abcdefghijklmnopqrstuu.hioaszd4nGKdJlcuRzR1xqPIcN/X.S, und bcrypt.compareSync(p2, hash(p1)) lieferte true. Das zweite Passwort meldet sich beim Konto des ersten an.

Wenn Ihr Passwort offensichtlich kurz ist und Sie trotzdem dies bekommen:

password cannot be longer than 72 bytes, truncate manually if necessary (e.g. my_password[:72])

dann benennt die Meldung die Ursache falsch (sinngemäß: „Das Passwort darf nicht länger als 72 Bytes sein, kürzen Sie es notfalls manuell“). Unter passlib 1.7.4 mit bcrypt 5.0.0 löst bereits ein 14 Bytes langes Passwort sie aus.

Der Schuldige ist dort eine fest verdrahtete 255-Byte-Selbsttest-Sonde in passlib. Sie läuft einmal, wenn das Backend initialisiert wird, also bevor Ihr Passwort den Hashing-Aufruf überhaupt erreicht. bcrypt 5.0.0 lehnt die Sonde ab, die Ausnahme entkommt, und Sie lesen eine Beschwerde über ein Passwort, das niemand getippt hat.

Eines vorweg: Der __about__-Monkey-Patch, der die Suchergebnisse zu diesem Fehler beherrscht, behebt das Problem nicht. Wir haben ihn in einem sauberen Prozess erneut ausgeführt, den Patch vor import passlib angewendet, und der ValueError kam unverändert zurück.

Triage in 30 Sekunden: Welcher Fall sind Sie

Ihr PasswortWann der Fehler auftrittUrsacheWeiter zu
Länger als 72 BytesBeim Aufruf von hashWirklich zu lang. bcrypt 5.0 wirft einen Fehler, bcrypt 4.x kürzt stillAbschnitte 2 und 3
Unter 72 Bytes, mit passlibBeim ersten Aufruf im ProzessDie 255-Byte-Sonde von passlib. Hat nichts mit Ihrem Passwort zu tunAbschnitt 4
Enthält Chinesisch, Japanisch oder EmojiSieht kurz aus, ist es nichtZeichen sind keine BytesAbschnitt 3
Fiel nach einem Abhängigkeits-Upgrade ausNach dem DeploymentDer Breaking Change in bcrypt 5.0Abschnitte 4 und 5

Wenn Sie in Zeile 2 stehen, überspringen Sie das Folgende. In den nächsten beiden Abschnitten hilft Ihnen nichts, und die Lösung sieht anders aus.

Was bcrypts 72-Byte-Limit mit Ihrem Passwort macht

Warum bcrypt bei 72 aufhört

bcrypt baut auf Blowfish auf und übergibt Ihr Passwort als Blowfish-Schlüssel. Blowfish expandiert seinen Schlüssel in ein P-Array aus 18 Teilschlüsseln zu je 32 Bit. Das sind 18 × 4 = 72 Bytes Schlüsselmaterial, und die Expansionsschleife springt an den Anfang des Schlüssels zurück, sobald sie alle 18 Plätze gefüllt hat.

Die Obergrenze ist also strukturell. Sie ist keine faule Implementierung und kein konfigurierbarer Puffer, den jemand zu erhöhen vergessen hat. Jede konforme bcrypt-Implementierung auf jeder Plattform hat dasselbe Limit, weshalb Ihnen die Zahl 72 in Python, Node, Go, Java und PHP gleichermaßen begegnet.

Zwei verschiedene Passwörter, ein Hash

bcrypt password truncation ist eine Sicherheitseigenschaft, keine lästige Längenbeschränkung.

Mit bcryptjs 3.0.3 und dem festen Salt $2a$10$abcdefghijklmnopqrstuv haben wir zwei Passwörter zu je 82 Bytes gehasht:

PasswortWertBytes
p1"A"×72 + "XXXXXXXXXX"82
p2"A"×72 + "ZZZZZZZZZZ"82

Beide ergaben denselben Digest:

$2a$10$abcdefghijklmnopqrstuu.hioaszd4nGKdJlcuRzR1xqPIcN/X.S

Zwei verschiedene Passwörter, ein Hash: true. Und die Konsequenz daraus:

bcrypt.compareSync(p2, hash(p1))  // true

Ein Angreifer, der die ersten 72 Bytes einer langen Passphrase kennt, kann Beliebiges anhängen und sich anmelden. Jedes Byte jenseits der Grenze trägt exakt null zur Stärke des gespeicherten Hashes bei, egal wie sorgfältig Ihre Nutzer es gewählt haben. Wenn Sie einen vorhandenen Hash gegen ein Kandidatenpasswort prüfen wollen, ohne ein Skript zu schreiben, können Sie bcrypt-Hashes im Browser erzeugen und verifizieren und dasselbe Verhalten selbst beobachten.

Wo die Grenze tatsächlich verläuft

Wir haben den Schnittpunkt Byte für Byte eingegrenzt, mit gemeinsamem Präfix und genau einem abweichenden Byte danach:

Identische Präfix-BytesByte N+1 weicht ab beiGleicher Hash?
7071false
7172false
7273true
7374true

Byte 72 zählt noch. Byte 73 ist das erste, das nicht mehr zählt. Dazwischen wird nichts ausgeblendet und nichts teilweise vermischt. Mit Ihrer eigenen Bibliothek können Sie das billig nachprüfen.

Zeichen sind keine Bytes

bcrypt zählt UTF-8-Bytes, Ihre Nutzer tippen Zeichen. Bei ASCII fallen beide Zahlen zufällig zusammen, deshalb trifft es Teams erst, wenn sie außerhalb eines englischsprachigen Marktes ausliefern.

ZeichentypBeispielBytes pro Zeichen72 Bytes entsprechen
Lateinische ASCII-BuchstabenA172 Zeichen
Chinesische Han-Zeichen324 Zeichen
Japanische Kana324 Zeichen
Emoji🔒418 Zeichen
Kyrillischя236 Zeichen
Deutsche Umlauteü236 Zeichen

Wir haben beide Extreme bestätigt: Bei einem chinesischen Passwort werden Unterschiede nach dem 24. Zeichen ignoriert (true), bei einem Emoji-Passwort Unterschiede nach dem 18. (true).

Eine chinesische Passphrase aus 25 Zeichen sieht in einem Passwortfeld großzügig aus. Sie hat die Grenze längst überschritten. Wer 20 Emoji wählt, liegt seit zwei Zeichen darüber und wird es nie erfahren.

Bytelänge im eigenen Code messen

Längenprüfungen, die gegen Zeichenzahlen geschrieben sind, laufen durch, während der zugrunde liegende Wert bereits zu lang ist. Messen Sie Bytes:

# Python
len(pw.encode("utf-8"))
// Node.js
Buffer.byteLength(pw, "utf8")
// Go
len([]byte(pw))

In Browsern ohne Buffer liefert new TextEncoder().encode(pw).length dieselbe Zahl. Setzen Sie diese Prüfung vor Ihren Hashing-Aufruf und geben Sie eine echte Validierungsmeldung zurück, statt die Bibliothek um 3 Uhr nachts entscheiden zu lassen. Falls Sie ohnehin gerade Ihre Mindestlängen-Richtlinie überarbeiten: wie Passwortstärke tatsächlich gemessen wird erklärt, was eine Längenregel bringt und was nicht.

Warum auch kurze Passwörter scheitern: die 255-Byte-Sonde von passlib

Der zweite Fall treibt die meisten Leute in die Suchmaschine: Ihr Passwort ist vierzehn Zeichen lang, und die Bibliothek besteht darauf, es liege über 72 Bytes.

Reproduktion

Drei Zeilen, unter Python 3.14.5 mit bcrypt 5.0.0 und passlib 1.7.4:

from passlib.hash import bcrypt
bcrypt.hash("short-password")   # 14 Bytes
# ValueError: password cannot be longer than 72 bytes, truncate manually if necessary (e.g. my_password[:72])

Vierzehn Bytes hinein, eine Beschwerde über 72 Bytes heraus. Der passlib bcrypt error ist echt, aber die Zahl darin beschreibt etwas völlig anderes.

Der vollständige Aufrufstapel

Der Ablauf lässt sich durch passlib 1.7.4 nachverfolgen:

  1. Der erste Aufruf löst die Backend-Initialisierung aus: _calc_checksum_stub_requires_backend()set_backend().
  2. _load_backend_mixin liest bcrypt.__about__.__version__. Das Attribut existiert nicht, also wird ein AttributeError ausgelöst. passlib schluckt ihn und gibt (trapped) error reading bcrypt version aus.
  3. Die Initialisierung läuft weiter in _finalize_backend_mixin (passlib/handlers/bcrypt.py:421), das detect_wrap_bug(IDENT_2A) aufruft.
  4. detect_wrap_bug (dieselbe Datei, :378) prüft eine fest verdrahtete 255-Byte-Sonde.
  5. bcrypt 5.0.0 wirft ValueError für alles über 72 Bytes, also fliegt die Sonde sich selbst um die Ohren.
  6. Die Ausnahme wandert nach oben bis zu Ihrer Aufrufstelle. Sie sehen eine Meldung über 72 Bytes, in der es nie um Ihre Eingabe ging.

Die gesamte Abfolge passiert einmal pro Prozess, beim ersten Hashen oder Verifizieren. Deshalb ist der Fehler zuverlässig reproduzierbar und unempfindlich dagegen, was Sie übergeben.

Wie die Sonde aussieht

secret = (b"0123456789" * 26)[:255]

Diese Konstante stammt aus dem Wraparound-Bug in bcrypt unter BSD, den Openwall 2012 offengelegt hat und bei dem lange Schlüssel umliefen und zu schwächeren Hashes kollabierten. passlib prüft beim Start, ob das gerade geladene Backend diesen Mangel trägt, und weigert sich, einem betroffenen Backend zu vertrauen.

detect_wrap_bug ist kein passlib-Bug. Es ist defensiver Code, der tut, wofür er geschrieben wurde, und dabei einen Testvektor verwendet, der seit über einem Jahrzehnt gültig ist. Geändert hat sich, dass bcrypt 5.0.0 eine 255 Bytes lange Eingabe jetzt als Fehler behandelt statt als etwas zu Hashendes, wodurch aus einem bestandenen Selbsttest ein unabfangbarer wird. Die Diskussion in pyca/bcrypt Issue #1082 behandelt den Zusammenstoß der beiden Bibliotheken.

Warum der __about__-Patch nichts behebt

Suchen Sie nach diesem Fehler, und man wird Ihnen immer wieder erzählen, bcrypt habe __about__ entfernt und dessen Wiederherstellung repariere passlib. Beide Hälften davon sind falsch. Die Messung dazu:

Versionhasattr(bcrypt, "__about__")Gibt trapped-Warnung auspasslib funktioniert
bcrypt 5.0.0FalseJaNein (ValueError)
bcrypt 4.3.0FalseJaJa

bcrypt 4.3.0 hat ebenfalls kein __about__. Es gibt dieselbe Zeile (trapped) error reading bcrypt version aus. Und passlib läuft damit ohne Klagen. Das fehlende Attribut ist folglich nicht die Trennlinie zwischen funktionierend und kaputt. Die geänderte ValueError-Semantik in 5.0.0 ist es.

Das heißt, der populäre Patch kann nicht funktionieren, und er tut es auch nicht:

import bcrypt, types
bcrypt.__about__ = types.SimpleNamespace(__version__=bcrypt.__version__)  # vor dem Import von passlib
from passlib.hash import bcrypt as pl
pl.hash("short-password")
# weiterhin ValueError: password cannot be longer than 72 bytes, ...

Wir haben das in einem sauberen Prozess ausgeführt, mit dem Patch vor import passlib, gerade damit niemand das Scheitern auf die Import-Reihenfolge schieben kann. Es scheitert trotzdem. Alles, was der Patch erreicht, ist das Stummschalten einer harmlosen Warnung. Die 255-Byte-Sonde aus Schritt 4 ist eine eigene Stufe, die __about__ von Anfang an nie konsultiert hat, und sie detoniert so oder so.

Was bcrypt 5.0 tatsächlich geändert hat

Der bcrypt 5.0 breaking change ist eine einzige Verhaltenszeile mit großem Wirkungsradius:

Eingabebcrypt 4.3.0bcrypt 5.0.0
72 BytesOKOK
73 BytesOK (still gekürzt)ValueError
100 BytesOK (still gekürzt)ValueError
255 BytesOK (still gekürzt)ValueError

Die Kürzung in der 4.x-Spalte ist keine Redewendung. Unter 4.3.0 kommen hash(73 Bytes) und hash(100 Bytes) aus demselben Präfix gleich heraus: true.

bcrypt 5.0 ist hier also die korrektere Bibliothek. Schlüsselmaterial stillschweigend wegzuwerfen ist schlimmer, als den Dienst zu verweigern, und den Dienst zu verweigern ist das, was eine Hashing-Bibliothek tun sollte, wenn sie die übergebene Eingabe nicht respektieren kann. Schmerzfrei macht das die Aktualisierung nicht. Code, der jahrelang still Bytes verlor, wirft nun Fehler, und wenn dieser Codepfad hinter passlib liegt, wirft er, noch bevor Ihre Eingabe überhaupt beteiligt ist.

Aus dieser Tabelle folgen zwei Dinge, und sie landen bei unterschiedlichen Teams. Wenn Sie bcrypt direkt aufrufen, ist die Aktualisierung sichtbar: Sie bekommen eine Ausnahme bei Registrierung oder Login, an einer Codestelle, die Ihnen gehört, mit einem Stacktrace, der auf Ihren eigenen Hashing-Aufruf zeigt. Setzen Sie eine Bytelängenprüfung davor, und Sie sind an einem Nachmittag fertig.

Wenn Sie über passlib gehen, ist die Aktualisierung unsichtbar, bis sie total ist. Der Ausfall ist nicht proportional dazu, wie viele Ihrer Nutzer lange Passwörter haben, denn er hängt überhaupt nicht von Benutzereingaben ab. Jedes Hashen und jedes Verifizieren im Prozess schlägt fehl, vom ersten Aufruf an, in einer Codebasis, in der sich an der Passwortbehandlung nichts geändert hat. Deshalb taucht das als Deployment-Zwischenfall auf statt als Fehlerbericht, und deshalb schickt der Meldungstext die Leute an genau die falsche Stelle.

Die Behebung

Wenn Sie den Code ändern können

Werfen Sie passlib raus und rufen Sie bcrypt direkt auf. Die letzte Veröffentlichung von passlib war 1.7.4 und um das Projekt ist es lange still, die Schicht bringt Ihnen in einem Projekt, das nur bcrypt braucht, also sehr wenig:

import bcrypt

password = "correct horse battery staple".encode("utf-8")
hashed = bcrypt.hashpw(password, bcrypt.gensalt(rounds=12))

bcrypt.checkpw(password, hashed)  # True

hashpw und checkpw nehmen beide Bytes entgegen, kodieren Sie also an der Grenze und lassen Sie den Rest Ihres Codes mit str arbeiten. Es gibt keine Backend-Erkennung und keine Selbsttest-Sonde, also auch keinen Fehler über ein Passwort, das Sie nie geliefert haben. Wenn Sie den entstehenden Hash in Augenschein nehmen oder einen aus Ihrer Anwendung verifizieren wollen: Der bcrypt-Generator läuft vollständig in Ihrem Browser. Server, die bcrypt für HTTP-Basic-Auth einsetzen, unterliegen derselben strukturellen Einschränkung in einem anderen Dateiformat, was der htpasswd-Leitfaden durchgeht.

Wenn Sie den Code heute nicht ändern können

Pinnen Sie unter 5:

bcrypt<5

Wir haben bcrypt 4.3.0 mit passlib 1.7.4 überprüft, und es funktioniert. Machen Sie sich aber klar, was Sie sich damit eingekauft haben. Das ist ein Druckverband, keine Reparatur. Sie bleiben auf einer Version, deren Verhalten bei einem bcrypt long password darin besteht, Bytes still zu verwerfen, also genau bei dem Problem, dessen Beendigung der Anlass für 5.0 war. Setzen Sie ein Datum auf den Pin und planen Sie den Umzug.

Wenn Ihre Nutzer wirklich lange Passphrasen tippen

Hashen Sie das Passwort zuerst einmal mit SHA-256, kodieren Sie den Digest base64 und geben Sie das an bcrypt weiter:

import base64, hashlib, bcrypt

def prehash(password: str) -> bytes:
    return base64.b64encode(hashlib.sha256(password.encode("utf-8")).digest())

hashed = bcrypt.hashpw(prehash(pw), bcrypt.gensalt(rounds=12))
bcrypt.checkpw(prehash(pw), hashed)

Die Ausgabe ist immer 44 Bytes lang, bequem unter 72, wie lang die Eingabe auch ist. Und sie stellt die Eigenschaft wieder her, die die Kürzung zerstört hatte: Die beiden 82 Bytes langen Passwörter aus dem Einstieg ergeben so checkpw(prehash(p2), hash(prehash(p1))) = False. Die Kollision ist weg.

Der base64-Schritt leistet echte Arbeit, lassen Sie ihn also nicht weg. Ein roher SHA-256-Digest ist beliebiges Binärmaterial und kann NUL-Bytes enthalten, die bcrypt-Implementierungen uneinheitlich behandeln. base64 gibt Ihnen eine NUL-freie ASCII-Zeichenkette fester Länge. Wenden Sie dieselbe Funktion bei Registrierung und Login an, sonst verifiziert kein einziger bestehender Hash mehr.

Was Sie nicht tun sollten

Zwei Schritte wirken verlockend und richten beide Schaden an.

Der __about__-Monkey-Patch funktioniert nicht. Abschnitt 4 enthält die Messung. Wenn jemand in Ihrem Team ihn gerade einfügen will, sparen ihm die vier Zeilen weiter oben einen Nachmittag.

Selbst mit pw[:72] zu kürzen ist schlimmer, als gar nichts zu tun. Es verwandelt einen lauten Fehler zurück in einen stillen und erzeugt die Kollision aus Abschnitt 2 in Ihrem eigenen Code neu. Sie würden genau das Verhalten von Hand nachbauen, dessen Beseitigung der Anlass für bcrypt 5.0 war, und anders als die Bibliotheksversion wird Ihre niemanden warnen. Wenn Sie lange Passwörter unterstützen müssen, hashen Sie vor. Wenn nicht, prüfen Sie die Bytelänge und lehnen Sie mit einer klaren Meldung ab.

Was ist mit den Hashes, die schon in Ihrer Datenbank liegen

Welche Zeilen betroffen sind

Nur Konten, deren Besitzer sich mit einem Passwort über 72 Bytes registriert haben. Bei den meisten Endkundenprodukten ist das eine kleine Menge, und bei allem rein Englischsprachigen sind es meist Passphrasen-Enthusiasten. Bei Produkten mit Nutzern, die Chinesisch, Japanisch oder Emoji tippen, greift Abschnitt 3 und die betroffene Menge kann deutlich größer sein, als eine byteblinde Prüfung vermuten lässt.

Aus den Hashes lassen sich diese Zeilen nicht identifizieren. Ein bcrypt-Digest hat feste Breite und trägt keine Aufzeichnung darüber, wie lang seine Eingabe war. Falls Sie die Passwortlänge bei der Registrierung protokolliert haben, ist dieses Log Ihr einziges Inventar. Die meisten Teams haben es nicht, und im Nachhinein lässt es sich nicht rekonstruieren, planen Sie also mit dem Nichtwissen statt mit einer Liste.

Neu berechnen im Massenbetrieb geht nicht

Es gibt keinen Klartext zum erneuten Hashen, und genau darum geht es beim Speichern von Hashes. Die Migration muss also lazy erfolgen: Jedes Konto wird beim nächsten erfolgreichen Login seines Besitzers aktualisiert, während Sie den Klartext kurz im Speicher halten.

def login(user, password: str) -> bool:
    if not verify_legacy(password, user.password_hash):
        return False
    if needs_rehash(user.password_hash):
        user.password_hash = hash_new_scheme(password)
        save(user)
    return True

Verifizieren Sie zuerst mit dem alten Verfahren und hashen Sie erst danach neu. Wer diese beiden Schritte vertauscht, überschreibt den gespeicherten Hash, bevor die Richtigkeit des Passworts bestätigt ist. Speichern Sie neben jedem Hash eine Verfahrenskennung, damit needs_rehash ein Feldvergleich ist und keine Vermutung, und rechnen Sie mit einem langen Schwanz ruhender Konten, die sich nie anmelden. Die erledigen Sie beim Passwort-Reset, nicht mit Gewalt.

Wann sich eine vollständige Migration lohnt

Wenn Sie ohnehin gerade den Lazy-Rehash-Pfad schreiben, ist das der günstigste Moment, den Sie je bekommen, um den darunterliegenden Algorithmus zu wechseln. Die 72-Byte-Obergrenze existiert in Argon2id nicht, und der ausführliche Vergleich von Argon2id und bcrypt behandelt, wann sich der Wechsel rechnet und wann das Bleiben bei bcrypt die richtige Entscheidung ist. Das OWASP Password Storage Cheat Sheet ist die Referenz, an der Sie Ihre Parameter prüfen sollten.

Beginnen Sie keine Migration allein wegen dieses Fehlers. Wenn Ihre Passwörter bequem unter 72 Bytes bleiben, ist bcrypt weiterhin eine solide Wahl, und Abschnitt 6 hat Ihr Problem bereits gelöst.

FAQ

Warum sagt bcrypt, mein Passwort sei länger als 72 Bytes, obwohl es kurz ist?

Weil die Meldung von der internen Sonde in passlib handelt und nicht von Ihrem Passwort. Beim ersten Aufruf führt passlib detect_wrap_bug mit einer fest verdrahteten 255-Byte-Testzeichenkette aus. bcrypt 5.0.0 wirft ValueError für alles über 72 Bytes, also scheitert die Sonde und der Fehler taucht an Ihrer Aufrufstelle auf. Ein 14 Bytes langes Passwort löst das aus.

Ignoriert bcrypt wirklich alles nach 72 Bytes?

Ja, bcrypt ignoriert jedes Byte nach 72 vollständig. Zwei 82 Bytes lange Passwörter mit identischen ersten 72 Bytes erzeugen denselben Hash $2a$10$abcdefghijklmnopqrstuu.hioaszd4nGKdJlcuRzR1xqPIcN/X.S, und jedes verifiziert gegen den Hash des anderen. Die Grenze ist exakt: Ein Unterschied bei Byte 72 verändert den Hash, ein Unterschied bei Byte 73 nicht.

Ist das 72-Byte-Limit ein Sicherheitsproblem?

Bei langen Passphrasen ist das 72-Byte-Limit von bcrypt ein Sicherheitsproblem. Wer die ersten 72 Bytes kennt, kann beliebige Bytes anhängen und sich anmelden, jedes Byte jenseits des Limits bringt also nichts. Bei Passwörtern unter 72 Bytes ändert es gar nichts. Ein Pre-Hashing mit SHA-256 beseitigt die Angriffsfläche, falls lange Eingaben vollständig zählen müssen.

Wie viele Zeichen sind 72 Bytes?

Wie viele Zeichen 72 Bytes sind, hängt von der Kodierung ab. 72 ASCII-Buchstaben, 36 kyrillische Zeichen oder Umlaute, 24 chinesische Han-Zeichen, 24 japanische Kana oder 18 Emoji. bcrypt zählt UTF-8-Bytes statt Zeichen, messen Sie also mit len(pw.encode("utf-8")) in Python oder Buffer.byteLength(pw, "utf8") in Node.

Behebt ein Patch von __about__ den passlib-Fehler?

Nein, der __about__-Patch behebt den passlib-Fehler nicht. Wir haben den Patch in einem sauberen Prozess vor import passlib angewendet, und der ValueError trat trotzdem auf. bcrypt 4.3.0 fehlt __about__ ebenfalls und läuft problemlos mit passlib, was beweist, dass das fehlende Attribut nicht die Ursache ist. Der Patch schaltet nur die Warnung (trapped) error reading bcrypt version stumm.

Sollte ich bcrypt auf unter 5.0 herabstufen?

Ein Downgrade von bcrypt unter 5.0 ist als Notlösung vertretbar. bcrypt 4.3.0 mit passlib 1.7.4 funktioniert. Aber 4.x kürzt alles jenseits von 72 Bytes still, und das ist genau das Verhalten, dessen Beendigung der Anlass für 5.0 war, behandeln Sie den Pin also als vorübergehend und steigen Sie auf direkte bcrypt-Aufrufe um.

Kann ich das Passwort nicht einfach selbst auf 72 Bytes kürzen?

Kürzen Sie das Passwort nicht selbst auf 72 Bytes. pw[:72] erzeugt die oben beschriebene Kollision in Ihrem eigenen Code neu, still und ohne Bibliothekswarnung, die sie abfangen könnte. Hashen Sie entweder mit SHA-256 und base64 vor, damit lange Eingaben unterscheidbar bleiben, oder prüfen Sie die Bytelänge vorab und lehnen Sie mit einer klaren Fehlermeldung ab.

Was passiert mit Passwörtern, die vor der Behebung schon gehasht wurden?

Bestehende bcrypt-Hashes verifizieren weiterhin, weil Ihr Verifizierungspfad genauso kürzt wie der Hashing-Pfad zuvor. Geschwächt sind nur Konten, die mit über 72 Bytes langen Passwörtern registriert wurden, und ohne Klartext können Sie sie nicht neu berechnen. Hashen Sie lazy beim nächsten erfolgreichen Login neu und behandeln Sie ruhende Konten beim Passwort-Reset.

Tags: bcrypt password-hashing passlib python debugging security

Verwandte Artikel

Alle Artikel anzeigen