Was an password.es falsch war — und jetzt nicht mehr

Veröffentlicht am von David Carrero

Dieses Blog hat zwölf Artikel darüber, wie man Dinge richtig macht: dass Länge mehr zählt als Sonderzeichen, dass ein Manager keine Bequemlichkeit ist, sondern die einzige Art, die Regel einzuhalten, dass eine Prozentzahl nichts sagt.

Das zu schreiben ist leicht. Unangenehm wird es, wenn man die eigene Seite am selben Maßstab misst. Wir haben es getan, und drei Dinge waren falsch. Sie stehen hier vollständig, mit den Zahlen, die sie verraten haben — denn eine Sicherheitsseite, die nur ihre Erfolge veröffentlicht, ist deutlich weniger wert.

Der Checker fror ein, während du tipptest

Der Checker analysiert dein Passwort mit zxcvbn, einer Bibliothek, die nach Mustern sucht, statt Großbuchstaben zu zählen. Sie funktioniert sehr gut und hat einen Preis: sie läuft am Stück, auf demselben Thread, der die Seite zeichnet. Solange sie läuft, kann der Browser nichts anderes tun.

Dieser Preis wächst schnell mit der Länge. Gemessen mit genau dem Paket, das die Seite ausliefert, und mit Passwörtern, wie Menschen sie wirklich tippen — Wörter, Jahreszahlen, @ statt a:

Länge ein Durchlauf
16 Zeichen 45 ms
20 Zeichen 121 ms
32 Zeichen 273 ms
64 Zeichen 843 ms
128 Zeichen 3.621 ms

So weit normal. Das Problem war, wie oft wir sie starteten.

Am Feld hingen zwei getrennte Listener, input und keyup. Eine normale Taste löst beide aus. Bei jedem Buchstaben lief die vollständige Analyse also zweimal: 90 ms bei einem 16-Zeichen-Passwort, eine halbe Sekunde bei 32.

Und nichts bremste sie: kein Timer, keine Längengrenze, kein eigener Thread. Ab etwa zwanzig Zeichen brauchte der Browser länger zum Analysieren, als du zum Drücken der nächsten Taste. Die Anschläge stapelten sich in einer Warteschlange, die sich nie leerte, und die Seite reagierte beim Tippen nicht mehr. Ein langes Passwort einzufügen fror sie für Sekunden ein.

Die Behebung sind zwei kleine Änderungen. Wir haben den keyup-Listener entfernt, denn input deckt Tippen, Einfügen, Löschen und das Ausfüllen durch den Manager bereits ab: die Hälfte der Arbeit verschwindet, ohne dass sich an dem, was du siehst, irgendetwas ändert. Und wir haben 150 Millisekunden Wartezeit eingebaut: während du tippst, wird nichts analysiert, und analysiert wird, sobald du aufhörst. Niemand tippt langsam genug, um das zu merken.

Das Ergebnis ist identisch. Barcelona1992$ sagt weiterhin dasselbe: dass «barcelona» im Wörterbuch steht, dass 1992 nach einer Jahreszahl aussieht, und dass es in unter einer Sekunde fällt.

Die Beschreibung brach in fünfzehn Sprachen mitten im Satz ab

Diese ist dümmer und peinlicher.

Der Satz, der in der Suche unter dem Titel erscheint — die Meta-Description — war in fünfzehn der achtzehn Sprachen des Checkers abgeschnitten. Nur Spanisch, Koreanisch und Japanisch blieben heil. Irgendwann hat jemand nach Länge gekürzt, mitten im Wort geschnitten, und danach hat niemand nachgesehen.

In drei Sprachen fiel der Schnitt mitten in ein Sonderzeichen. Das hier haben wir also an Google ausgeliefert:

Sprache was wir auslieferten was da stehen sollte
Portugiesisch …datas e padr&o padrões
Türkisch …arıyor ve ger&cced gerçekten
Vietnamesisch …chúng tôi tra mật kh&# mật khẩu

Das Auffällige ist, wo: auf der Seite, die von allen am besten läuft. Der Checker konvertiert deutlich besser als der Generator — und tat es mit kaputter Beschreibung. Alle fünfzehn sind jetzt vollständig.

Bei der Gelegenheit ist im Koreanischen, Japanischen und Vietnamesischen die Marke vom Anfang ans Ende des Titels gewandert. In der Suche steht die Domain ohnehin separat, mit «password.es ·» zu beginnen verbrauchte nur den Platz, der am meisten zählt.

Eine Schieflage von eins zu hundert Millionen

Der Generator wählt jedes Zeichen mit crypto.getRandomValues(), der guten Zufallsquelle des Browsers. Aber um diese riesige Zahl in «eine Position im Alphabet» zu verwandeln, benutzten wir einen Rest — und da lauert eine klassische Falle: 2³² ist kein Vielfaches von 83, also kamen die ersten Positionen des Alphabets eine Spur häufiger vor als die letzten.

Wie viel Spur: bei einem Alphabet von bis zu 89 Zeichen in der Größenordnung von eins zu hundert Millionen. Das ändert nichts. Es macht dein Passwort nicht messbar schwächer, nicht annähernd.

Wir haben es trotzdem behoben, und es sind drei Zeilen: Die 45 überzähligen Werte von 4.294.967.296 möglichen werden verworfen und neu gezogen. Auf einer Seite über Passwörter ist «vernachlässigbar» kein guter Grund, eine Schieflage stehen zu lassen, wenn das Entfernen so wenig kostet.

Was fehlte: den Browser das Versprechen durchsetzen lassen

Wir haben einen ganzen Artikel darüber, dass dein Passwort hier nicht rausgeht. Das stimmte, und trotzdem war es nur ein Satz von uns: technisch hinderte nichts ein eingeschleustes Skript daran, etwas anderes zu tun.

Jetzt trägt jede Seite eine Content-Security-Policy. Die zwei entscheidenden Teile:

  • Es läuft kein Skript, das beim Bauen nicht in der Seite war. Jedes legitime Skript ist mit seinem Fingerabdruck unterschrieben; ein eingeschleustes passt nicht, und der Browser weigert sich, es auszuführen.
  • connect-src 'none'. Die Seite stellt aus JavaScript keine einzige Netzwerkanfrage, und das setzt jetzt der Browser durch. Sollte je etwas versuchen, das Getippte irgendwohin zu schicken, käme es nicht hinaus.

Aus dem Versprechen wurde eine Regel.

Was weiterhin falsch ist

Nachtrag vom 31. August. Alle drei Punkte dieses Abschnitts wurden am selben Tag behoben, an dem dieser Artikel erschien: Die fünfzehn Sprachen beschreiben jetzt die echte Engine, aus den zwei Skalen ist eine geworden, und die FAQ des Checkers erklärt die Sache mit den Sonderzeichen. Sie bleiben trotzdem stehen: Das Protokoll dessen, was schiefging, ist mehr wert als das Bild einer makellosen Seite.

Hier verdient sich dieser Artikel seinen Platz.

Fünfzehn Sprachen beschreiben den Checker noch als die alte Engine. Ihr Text sagt, er bilde die klassische PasswordMeter-Logik nach. Nicht mehr: Diese Engine wurde ersetzt, weil sie Passwort1! für sehr stark hielt und eine Passphrase aus fünf Wörtern durchfallen ließ — also genau andersherum. Spanisch, Koreanisch und Japanisch sind aktualisiert; die anderen fünfzehn nicht.

Es gibt zwei verschiedene Skalen im selben Haus. Die Startseite entscheidet über die Stärke nach Bits, der Checker nach der Zeit, die das Knacken kosten würde. Zwei Kriterien — und nirgends sagen wir es.

Generator und Checker zählen nicht dieselben Sonderzeichen: einer nutzt 27, der andere nimmt 33 an. Der Unterschied ist klein, aber er ist da.

Keines der drei ist gravierend. Alle drei sind Schulden, und sie stehen lieber hier, als darauf zu warten, dass sie jemand anders findet.

Das Änderungsprotokoll dieser Version

Da das Repository nicht öffentlich ist, steht das Änderungsprotokoll hier vollständig. Version 0.2.0, 31. August 2026:

Hinzugefügt. Eine Content-Security-Policy pro Seite, mit dem Fingerabdruck jedes Skripts. Der Artikel darüber, wo deine gespeicherten Passwörter liegen, in allen achtzehn Sprachen. Eine redaktionelle Warteschlange, die entscheidet, was geschrieben wird — und die anordnet, nichts zu veröffentlichen, wenn sie leer läuft.

Behoben. Die Beschreibung des Checkers, in fünfzehn Sprachen mitten im Satz abgeschnitten, in dreien davon mit einem halbierten Zeichen. Das Einfrieren des Tabs beim Tippen. Die Schieflage der Ziehung. Und das fehlende Foto im vorigen Artikel.

Geändert. Der Titel des Checkers auf Koreanisch, Japanisch und Vietnamesisch. Das Deployment, das jetzt auslöst, wenn die gebaute Seite bereits existiert, und nicht eine Minute früher. Und die Übersetzungen ins Vietnamesische, Hindi und Arabische, die eine Veröffentlichung nicht mehr blockieren, auch wenn sie die schwächsten bleiben.


Die Zahlen in diesem Artikel sind gemessen, nicht geschätzt: die zxcvbn-Zeiten mit genau dem Paket, das die Seite ausliefert, und Passwörtern mit Wörtern und Ersetzungen; die Schieflage der Ziehung, gerechnet über die 4.294.967.296 Werte einer 32-Bit-Ganzzahl. Die Engine des Checkers ist zxcvbn, quelloffen.

Foto von Ernandes Alves · Pexels

← Zurück zum Blog