Rolf B: Token bzw. Passwort generieren / php

Beitrag lesen

Hallo Bernd,

es ist eine alte Forderung vom BSI, dass ein Passwort aus 4 Kategorien zusammenzusetzen ist: Kleinbuchstaben, Großbuchstaben, Ziffern und Sonderzeichen. Hinzu kommt dann noch, dass es lang sein soll und überall ein anderes zu verwenden ist. Und nach 60 Tagen ein Neues vergeben werden muss.

Was zu den Zetteln unter der Tastatur führt. Und Schreikrämpfen in den Büros.

Mit der Forderung nach all diesen Zeichen gewinnt man gar nicht so viel. Es gibt ja auch noch die Anforderung, dass diese Zeichen auf einer "normalen" Tastatur eingebbar sein müssen, und dabei ist zu beachten, dass nicht jeder Anwender eine deutsche Tastatur hat. Oder nicht weiß, wie man ein { eingibt. Oder – wie auf meinem Samsung Tablet – das ` durch ein typographisches Anführungszeichen ersetzt wird.

Du hast 83 Zeichen vorgegeben. Das wären $$\log_2 83 \approx 6{,}4$$ Entropiebits pro Zeichen, oder 51 Bits Entropie bei 8 Passwortstellen. Dadurch, dass Du die Zeichenvorräte begrenzt, sind es aber nur

  • 2 Großbuchstaben: 9,34 Bits
  • 2 Ziffern: 6,49 Bits
  • 2 Sonderzeichen: 8,71 Bits
  • 2 Kleinbuchstaben: 9,34 Bits

In Summe 33,88 Bits Entropie, durch deine Einschränkungen verzichtest Du also auf 18 Bits der möglichen Passwortentropie. Das ist VIEL, jedes Bit verdoppelt den Passwortraum, d.h. Du hast ihn auf 1/262000 reduziert.

Wie kann man es besser machen? Ein Weg ist correct horse battery staple, das setzt aber eine geeignete Wörterliste voraus.

Ein anderer Weg ist dieser: Wenn man einfach beliebige Kleinbuchstaben verwendet, hat man 4,7 Bits Entropie pro Zeichen. Mal 11 ergibt 51,7. Du bist mit 11 zufälligen Kleinbuchstaben also genauso sicher wie mit einem 8-stelligen Kauderwelsch aus Kleinbuchstaben, Großbuchstaben, Ziffern und kryptischen Sonderzeichen. Mit 16 Kleinbuchtaben bist Du bei 75 - also deutlich besser. Mit einer Länge von 16 und einem Zeichenvorrat von Kleinbuchstaben und Ziffern bist Du bei 82,7 Bits Entropie. Das ist schon ziemlich gut.

Du könntest dein Passwort so erzeugen:

  • erzeuge per random_int() eine Zufallszahl $zuf von 0 bis 1679615 (das ist "0" bis "zzzz" im 36-er System). Verwende nicht rand() oder mt_rand(), die sind ausrechenbar!
  • wandle sie mit str_pad(base_convert($zuf, 10, 36), 4, '0', STR_PAD_LEFT); in eine Folge von 4 Zeichen um. str_pad muss man nehmen, weil base_convert keine führenden Nullen setzt.
  • Das wiederholst Du viermal und gibst diese 4 Werte als Passwort aus, mit einer Leerstelle zwischen den Gruppen. Deine Anwender werden Dich für Lesbarkeit und Merkbarkeit lieben. Je nach Font, heißt das…

Die Verbesserung der Lesbarkeit ist, diejenigem Zeichen wegzulassen oder zu ersetzen, die verwechselbar sind. Das ist vor allem 1 und l - aber auch 0 und o können ein Problem sein. Oder i und j.

Die folgende Funktion erzeugt einen Zufallsstring gegebener Länge aus einem Zeichenvorrat von 32 unverwechselbaren Zeichen. Die 32 macht die Entropieberechnung einfach: 5 Bits pro Zeichen. Bei 4 Gruppen zu 4 Zeichen also 80 Bits. Magische Zahlen im Code gibt's nicht, die Funktion rechnet ihre Parameter aus dem $charset String aus.

Was sie nicht tut, ist das Eliminieren doppelter Zeichen. Warum auch? "aaaa" ist genauso valider Zufall wie "d7qx". Du kannst, wenn Du magst, auch weitere Kleinbuchstaben durch Großbuchstaben ersetzen. Das erweckt die Illusion, dass Du zufällig Klein- und Großbuchstaben benutzt 😉. Achte aber immer auf mögliche Verwechslung von Zeichen.

$charset = "23456789abcdefghikLmnpqrstuvwxyz";
function getGroup($len) {
	global $charset;
	$result = "";
	$chars = strlen($charset);
	$r = random_int(0, $chars**$len - 1);
	for ($i=0; $i<$len; $i++) {
	   $result .= $charset[$r % $chars];
	   $r = intdiv($r, $chars);
	}
	return $result;
}

Einfach 4x getGroup(4) aufrufen und 80 Bits Entropie genießen 😉

Rolf

--
sumpsi - posui - obstruxi