Das Hashing-Verfahren (im Gegensatz zur Verschlüsselung) erzeugt aus der Eingabe eine Ausgabe, aus der die ursprüngliche Zeichenfolge nicht mehr abgeleitet werden kann.
Es eignet sich daher gut für den Schutz sensibler Zeichenfolgen, Passwörter und Prüfsummen.
Eine weitere nette Eigenschaft von Hash-Funktionen ist, dass sie immer gleich lange Ausgaben erzeugen und dass eine kleine Änderung der Eingabe immer die gesamte Ausgabe verändert.
Es gibt viele Hash-Funktionen in PHP, die wichtigsten sind:
$password = 'Geheim-Passwort';echo password_hash($password); // Bcryptecho md5($password);echo sha1($password);
Warnung: Weder
md5()
nochsha1()
sind für das Hashing von Passwörtern geeignet, da es rechnerisch einfach ist, das ursprüngliche Passwort zu ermitteln oder zumindest die Passwörter vorzuberechnen. Es ist viel besser,bcrypt
zu verwenden, das für das Hashing von Passwörtern entwickelt wurde.Die Website md5cracker.com verfügt über eine Datenbank mit Prüfsummen (Hashes). Versuchen Sie, nach dem Hash "79c2b46ce2594ecbcb5b73e928345492" zu suchen, wie Sie sehen können.
In dem Vortrag Wie man es in der Zielebene nicht vermasselt sprach David Grudl über Möglichkeiten, Passwörter korrekt zu hacken und zu speichern.
Die einzig richtige Lösung ist: "Bcrypt + Salt".
Konkret:
$password = 'Hash';// Erzeugt einen sicheren Hashwertecho password_hash($password, PASSWORD_BCRYPT);// Alternativ mit höherer Komplexität (Standard ist 10):echo password_hash($password, PASSWORD_BCRYPT, ['Kosten' => 12]);
Der Vorteil von Bcryp liegt vor allem in seiner Schnelligkeit und der automatischen Besalzung.
Die Tatsache, dass die Generierung lang dauert, sagen wir 100 ms, macht es für einen Angreifer sehr teuer, viele Passwörter zu testen.
Außerdem wird der ausgegebene Hash-Wert automatisch mit einem Zufallssalz behandelt, d. h., wenn dasselbe Kennwort wiederholt gehasht wird, wird immer ein anderer Hash-Wert ausgegeben. Daher ist ein Angreifer nicht in der Lage, eine vorberechnete Hash-Tabelle zu verwenden.
Daher können wir die Korrektheit des Kennworts nicht durch wiederholtes Hashing überprüfen, sondern müssen eine spezielle Funktion aufrufen:
if (password_verify($password, $hash)) {// Passwort ist korrekt} else {// Passwort ist falsch}
Um das Knacken von Hashes zu erschweren, ist es eine gute Idee, eine zusätzliche Zeichenfolge in die ursprüngliche Eingabe einzufügen. Idealerweise eine zufällige. Dieser Vorgang wird Passwortsalzen genannt.
Die Sicherheit basiert auf der Idee, dass ein Angreifer nicht in der Lage sein wird, eine vorberechnete Tabelle von Passwörtern und Hashes zu verwenden, da er den Salt nicht kennt und die Passwörter einzeln knacken muss.
Zum Beispiel:
$password = 'geheimer_Reisepass';$salt = 'fghjgtzjhg';$hash = md5($password . $salt);echo $password; // druckt das ursprüngliche Passwortecho $hash; // druckt Passwort-Hash inklusive Salt
Sie denken vielleicht, dass es eine gute Idee wäre, die Hash-Funktion wiederholt auszuführen und damit die Komplexität des Knackens zu erhöhen, da das ursprüngliche Kennwort wiederholt gehasht werden muss.
Zum Beispiel:
$password = 'Passwort';for ($i = 0; $i <= 1000; $i++) {$password = md5($password);}echo $password; // 1000x gehasht mit md5()
Paradoxerweise ist die Schwierigkeit des Durchbruchs geringer oder bleibt fast gleich.
Der Grund dafür ist, dass die Funktion md5()
extrem schnell ist und auf einem normalen Computer mehr als eine Million Hashes pro Sekunde berechnen kann, so dass das Ausprobieren eines Kennworts nach dem anderen nicht viel langsamer ist.
Der zweite Grund ist eher eine Theorie, nämlich die Möglichkeit einer so genannten Kollision. Wenn wir ein Kennwort wiederholt hashen, kann es passieren, dass wir auf einen Hash stoßen, den der Angreifer bereits kennt und der es ihm ermöglicht, das Kennwort mithilfe der Datenbank zu hashen.
Daher ist es besser, eine langsame, sichere Hashing-Funktion zu verwenden und das Hashing nur einmal durchzuführen, während die endgültige Ausgabe weiterhin mit Salting behandelt wird.
Wussten Sie, dass der Operator === nicht die sicherste Wahl für den Hash-Vergleich bei der Kennwortüberprüfung ist?
Beim Vergleich von Zeichenketten werden die beiden Zeichenketten Zeichen für Zeichen durchlaufen, bis das Ende erreicht ist (Erfolg, sie sind gleich) oder es keinen Unterschied gibt (die Zeichenketten sind unterschiedlich).
Und das kann bei einem Angriff ausgenutzt werden. Wenn Sie die Zeit genau genug messen, können Sie abschätzen, wie viele Zeichen noch hinzugefügt werden müssen, um eine exakte Übereinstimmung zu erzielen und das Ende zu erreichen, oder Sie können abschätzen, wie weit die Zeichenfolgen beim Vergleich der Zeichenfolgen gekommen sind.
Die Lösung besteht darin, die Funktion hash_equals() überall dort zu verwenden, wo Zeichenketten verglichen werden, und es wäre von Bedeutung, wenn ein Angreifer die Position herausfinden könnte, an der der Vergleich fehlgeschlagen ist.
Und wie macht die Funktion das? Es stellt sicher, dass der Vergleich von 2 beliebigen Zeichenketten immer die gleiche Zeit in Anspruch nimmt, so dass man durch Messung der Zeit nicht feststellen kann, wo der Unterschied aufgetreten ist. Ich finde einige Arten von Angriffen wirklich sehr unwahrscheinlich und schwer umzusetzen. Dies ist einer von ihnen.
Jan Barášek Více o autorovi
Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.
Rád vám pomůžu:
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | de