Da ich derzeit an einer kompletten Neuentwicklung für eine Community-Software sitze, stehe ich unter anderem vor dem Problem, dem Benutzer neue Passwörter vorzuschlagen bzw. auch automatisch neue Passwörter generieren zu lassen. Diese Passwörter sollten natürlich sicher sein. Doch was ist dazu zu beachten?
Generell sollte man natürlich darauf achten, dass das Passwort nicht mit Hilfe eines Wörterbuchs herausfindbar ist. Durch solche Passwörter ist es Hackern ein Leichtes, schnell an das nötige Passwort zu kommen. Beispiele für solche sehr schlechten Passwörter sind “MeinNameIstHans” oder “SicheresPasswort1”.
Sollte ein Wörterbuch nicht mehr beim Hacken ausreichen, wird ein BruteForce-Algorithmus angewendet, der praktisch mit roher Gewalt alle möglichen Buchstaben und Wortkombinationen ausprobiert, um ans Ziel zu kommen. Dass diese Methode nicht abwegig ist, zeigt der Artikel Password Recovery Speed: so kann ein 9-stelliges Passwort, das nur aus Zahlen besteht, auf einem Pentium-100 in 28 Stunden geknackt werden. Auf heutigen Rechnern dürfte sich dann nicht mal das Anschalten der Kaffeemaschine lohnen. Erst bei der Verwendung des vollen Alphabets (groß und klein) sowie von Zahlen und Sonderzeichen ergibt sich ein Passwort, das ab einer gewissen Mindestlänge auch auf leistungsstarken Rechnern aufwendig zu knacken ist und damit relativ sicher sein sollte.
Das Problem an diesen Passwörtern ist aber: wer kann sie sich merken? Es gibt sicherlich Software, welche die Passwörter für mich speichert (darunter zähle ich jetzt auch einfach mal die bekannten Haftnotizen, die viele Bildschirme veredeln). Dies macht die Sache aber nicht sicherer.
Eine Lösung stellen mnemonische Verfahren dar (siehe Mnemonik), die versuchen, Passwörter derart zu generieren, dass sie aussprechbar sind. Und ein solches versuchte ich nun zu implementieren. Da ich den Code für recht hilfreich finde, veröffentliche ich ihn hier:
function createRandomPassword() { $vokale = "aeiouy"; $konsonanten = "bcdfghjklmnprstvwxz"; $special = '!#$%&*+-/< =>?@^_~'; $password = ""; //zufällige Länge zwischen 4 und 10 Zeichen festlegen $sizeCharacter = mt_rand(3,7); for($i = 1; $i <= $sizeCharacter; $i++) { $passwort .= substr($konsonanten, mt_rand(0, strlen($konsonanten)-1), 1); $passwort .= substr($vokale, mt_rand(0, strlen($vokale)-1), 1); } //zufälliges Sonderzeichen einfügen $passwort .= substr($special, mt_rand(0, strlen($special)-1), 1); //Zufällige Anzahl an Zahlen einfügen $sizeNumbers = mt_rand(1,3); for($i = 1; $i <= $sizeNumbers; $i++) { $passwort .= mt_rand(0,9); } return $passwort; }
Diese Funktion erzeugt Passwörter mit mindestens 6 Zeichen, maximal 14 Zeichen. Zur einfachen Aussprache wechselt sie zufällig Vokale (inkl. y!) und Konsonanten aus. Erzeugte Passwörter sehen z.B. so aus:
- givubyru@956
- wasurityzujasy!39
- jumexa@13
- hutydorufanuwy#44
- zidacy%4
- hafiby!35
- fadujudimy%52
- wykigy%263
- feweda@202
Sicher nicht jedes perfekt, aber meiner Meinung nach schon recht gut. Anderer Meinung? Verbesserungsvorschläge?
[Update]
Mit den Vorschlägen von Martin (siehe Kommentare) hab ich die Funktion jetzt etwas angepasst. Sie kann jetzt auch Großbuchstaben (hatte ich in der ersten Funktion komplett vergessen). Dabei wird berücksichtigt, dass zuviele Großbuchstaben schwer zu merken sind und dass dies noch einfacher fällt, wenn die Großbuchstaben nur Konsonanten sind.
function st_createRandomPassword($minpairs = 2, $maxpairs = 5, $minnumbers = 1, $maxnumbers = 3){ $vowels = "aeiou"; $consonants = "bcdfghjklmnprstvwxz"; $specialchars = '!#$%&*+-/< =>?@^_~'; $password = ""; $pairs = mt_rand($minpairs, $maxpairs); $lenv = strlen($vowels)-1; $lenc = strlen($consonants)-1; $usedBig = false; //Großbuchstabe bereits eingefügt wurde for($i = 1; $i < = $pairs; $i++) { $password .= $vowels[mt_rand(0, $lenv)]; if (mt_rand(0,1)==0 && !$usedBig) { $password .= strtoupper($consonants[mt_rand(0, $lenc)]); if (mt_rand(0,1)==0) $usedBig=true; } else { $password .= $consonants[mt_rand(0, $lenc)]; } } //zufälliges Sonderzeichen einfügen $password .= $specialchars[mt_rand(0, strlen($specialchars)-1)]; //Zufällige Anzahl an Zahlen einfügen $sizeNumbers = mt_rand($minnumbers, $maxnumbers); for($i = 1; $i <= $sizeNumbers; $i++) { $password .= mt_rand(0,9); } return $password; }
[Update 2]
In aktuellen PHP-Versionen scheint die eckige-Klammmer-Variante nicht mehr zu gehen. Deshalb hier die korrigierte Version:
function st_createRandomPassword($minpairs = 2, $maxpairs = 5, $minnumbers = 1, $maxnumbers = 3){ $vowels = "aeiou"; $consonants = "bcdfghjklmnprstvwxz"; $specialchars = '!#$%&*+-/< =>?@^_~'; $password = ""; $pairs = mt_rand($minpairs, $maxpairs); $lenv = strlen($vowels)-1; $lenc = strlen($consonants)-1; $usedBig = false; //Großbuchstabe bereits eingefügt wurde for($i = 1; $i < = $pairs; $i++) { $password .= $vowels{mt_rand(0, $lenv)}; if (mt_rand(0,1)==0 && !$usedBig) { $password .= strtoupper($consonants{mt_rand(0, $lenc)}); if (mt_rand(0,1)==0) $usedBig=true; } else { $password .= $consonants{mt_rand(0, $lenc)}; } } //zufälliges Sonderzeichen einfügen $password .= $specialchars{mt_rand(0, strlen($specialchars)-1)}; //Zufällige Anzahl an Zahlen einfügen $sizeNumbers = mt_rand($minnumbers, $maxnumbers); for($i = 1; $i <= $sizeNumbers; $i++) { $password .= mt_rand(0,9); } return $password; }
Erzeugte Passwörter:
- oWatus^885
- aToDosop@03
- iWiwatur+48
- eNiguTad!7
- adalowiLuv-350
- ajoW=3
- uSapen%61
- ozaDokaLes=417
- iNesebav%456
- oKaPogoz>5
Hier meine Abwandlung mit leichten Verbesserungen (Anzahlen als Parameter, einheitliche Sprache, nur einmalige Aufrufe von strlen(), Vereinfachung von substr(), ‘ statt “):
Mist, das hat’s zerhauen. Den Rest gibt’s bei nopaste.
Ich hab deinen Eintrag mal korrigiert. Ich glaube in der Schleife meinst du statt $length $pairs? Aber sonst ist die Idee wirklich nicht schlecht, dürfte das Script auf jeden Fall beschleunigen.
Ja genau,
$pairs
wäre richtig. Hab’s nicht getestet 😉Und von strlen() muss auch noch eins abgezogen werden, die erste Schleife müsste also etwa so aussehen:
for($i = 1, $maxv = strlen($vowels) - 1, $maxc = strlen($consonants) - 1; $i <= $length; $i++) {
$password .= vowels[mt_rand(0, $maxv)]; // in älteren PHP-Versionen geschweifte statt eckige Klammern benutzen
$password .= consonants[mt_rand(0, $maxc)];
}
Eine Kommentarvorschau wäre nicht verkehrt.
Ach Mist, jetzt hab ich schon wieder $length drin 😮
$lenv und $lenc hatte ich übrigens extra umbenannt, weil die nicht mehr die tatsächliche Länge enthalten 😉
Ach noch was, bei mt_rand(0,1) kann man das == 0 weglassen, da die 1 ja ebenso oft auftritt.
Ja, dann wird natürlich ein Typecast auf Boolean gemacht. Aber der Stil
if ($blubb)...
gefällt mir einfach nicht, weshalb ich lieber auf
if ($blubb===true)...
prüfe. So stell ich sicher, dass die Werte auch wirklich das enthalten, was ich mir vorstelle, das sie enhalten.
Ja, das Typecasting kann oft zu unerwarteten Ergebnissen führen. Halte ich hier aber für unproblematisch, da mt_rand() ganz sicher eine Zahl zurückgibt. Wenn ich auf Gleichheit prüfe, dann mach ich das eigentlich auch immer mit ===, das geht auch schneller. Also würde ich das zumindest in ===0 ändern.
Und hier mal ein paar üble Beispiele für das Typecasting 😉 (Man beachte, es werden Strings mit Strings verglichen, ich käme nie auf die Idee, da ein Typecasting zu machen, ist aber offenbar so gewollt, wie man nach einer Recherche auf bugs.php.net feststellen muss.)
var_dump('01'=='1',
'01' == '1.0',
'11111111111111111' == '11111111111111112',
'1E1' == '010');
Schade,
keine der Versionen will bei mir funktionieren. Bei Martins Version erhalte ich ein “Parse error: parse error, unexpected ‘[‘ in C:\Tools\xampp\htdocs\pass3.php on line 14”
Ich habe PHP Version 5.2.0, auch unter 4.x will es nicht klappen. Was mach ich falsch?
Stefan
Was sagt denn dein PHP-Script? Aktivier dazu error_reporting(E_ALL).
Servus,
wie ich schon geschrieben habe, die Fehlermeldung lautet:
Parse error: parse error, unexpected ‘[‘ in C:\Tools\xampp\htdocs\pass3.php on line 15
Ich denke das das an der eckigen Klammer liegt. Denn in dieser Zeile ist die Schleife:
for($i = 1, $lenv = strlen($vowels), $lenc = strlen($consonants); $i
Dann nimm statt der eckigen Klammer eine geschweifte (String-Typ)
Hat bisher in den PHP-Versionen getan. Interessant, dass da jetzt ein Fehler kommt.
Habe ich auch schon probiert.
Parse error: parse error, unexpected ‘{‘ in C:\Tools\xampp\htdocs\pass3.php on line 15
Löst das Problem leider auch nicht.
@Stefan:
kopier dir nochmal die letzte Version: WordPress hatte hier ein paar Anführungszeichen geändert. Bei mir funktioniert die Version einwanfrei.
Und das Ganze dann nochmal auf das wesentliche reduziert, dann wird es auch ein schöner kleiner Schnipsel (ausschneiden und sammeln!) 😉 :