Dieser Absatz erklärt, warum Hash Funktionen zur sicheren Passwortspeicherung benutzt werden, und wie dies am effektivsten bewerkstelligt werden kann.
Passworthashing ist eine der grundlegendsten Sicherheitsüberlegungen, die beim Design einer Anwendung bedacht werden müssen. Ohne Hashing können im Falle eines erfolgreichen Angriffs alle Userpasswörter in Ihrer Datenbank von einem Angreifer gestohlen und ohne Umwege in anderen Anwendungen (seien es Ihre oder die Anderer) benutzt werden. Dies ist oft der Fall, da viele User für verschiedene Dienste die gleichen Passwörter verwenden.
Wenn Sie Passwörter vor dem Abspeichern in der Datenbank hashen, machen Sie es einen Angreifer schwerer die ursprünglichen Passwörter herauszufinden. Sie haben jedoch weiterhin die Möglichkeit eingegebene Userpasswörter zu hashen und die Hashwerte zu vergleichen um herauszufinden, ob der User das richtige Passwort eingegeben hat.
Es ist jedoch wichtig zu wissen, dass Hashen nur das Auslesen der Passwörter aus dem Datenspeicher (z.B.: Datenbank oder Datei) erschwert. Sollte es einen Angreifer gelingen Code in Ihre Anwendung einzuschleusen, so kann er die Passwörter der User evtl. Auslesen bevor dieses gehasht werden.
Hashalgorithmen wie MD5, SHA1 und SHA256 sind auf Geschwindigkeit und Effizienz optimiert. Mit modernen Techniken und leistungsstarker Hardware ist es aber trivial geworden diese Hashalgorithmen mit "brute force" Attacken anzugreifen.
Weil moderne Computer diese Hashalgorithmen leicht brechen können, werden diese von Sicherheitsspezialisten nicht für die Speicherung von Passwörtern empfohlen.
Wenn es um das Hashen von Passwörtern geht müssen zwei wichtige Sachen bedacht werden: Der Berechnungsaufwand und das Salt. Wenn es länger dauert einen Hash zu berechnen wird ein Brute Force Angriff stark verzögert. Jedoch ist zu beachten, dass der Berechnungsaufwand sich im normalen Betrieb nicht negativ auf die Performance der Anwendung auswirkt. Das Salt hingegen dient dazu, die Erstellung von vorberechneten Rainbowtables zu verhindern, da durch das Salt auch gleiche Passwörter unterschiedliche Hashes erhalten.
PHP 5.5 bietet eine native Passworthashing API die sich auf eine sichere Art um das Hashen und Verifizieren von Passwörtern kümmert. Ebenso existiert eine » native PHP kompatible Bibliothek für PHP Versionen ab 5.3.7.
Eine andere Option ist die crypt() Funktion, die mehrere Hashalgorithmen unterstützt. Diese existiert ab Version 5.3.7. Wenn diese Funktion benutzt wird, ist es garantiert, dass der Hashalgorithmus unterstützt wird, da PHP native Implementierungen für die Algorithmen besitzt, die benutzt werden, wenn von dem Betriebsystem nicht angebotene Algorithmen benutzt werden.
Der empfohlene Algorithmus für das Hashen von Passwörtern ist Blowfish, welcher auf als Standardalgorithmus von der Passwort Hashing API benutzt wird, da dieser einen signifikant höheren Berechnungsaufwand als MD5 oder SHA1 voraussetzt und trotzdem weiterhin skalierbar ist.
Bitte beachten Sie: Wenn Sie crypt() benutzen um Passwörter zu verifizieren müssen sie dafür sorgen, Timing Attacken zu verhindern. Dies kann durch Stringvergleiche mit konstanter Laufzeit geschehen. Jedoch bieten die PHP Vergleichsoperatoren == und === keine konstante Laufzeit. Da jedoch password_verify() eine konstante Laufzeit besitzt ist es stark empfohlen die native Passwort Hashing API zu benutzen, wenn dies möglich ist.
Ein kryptografisches Salt sind Daten, die während des Hashens an das Passwort angefügt werden um die Möglichkeit des Angriffs über Rainbowtables zu erschweren. Rainbowtables sind bereits vorberechnete Paare (Schlüssel, Hash), die benutzt werden können, um für einen gegebenen Hash das vorberechnete Passwort nachzuschlagen.
In einfachen Worten: Ein Hash sind zusätzliche Daten, die es erschweren das Passwort zu knacken. Es gibt Onlinedienste bei denen man für einen gegebenen Hash das dazugehörige Passwort herrausfinden kann. Die Benutzung eines Salts macht es unpraktisch bis unmöglich das Passwort durch die Benutzung dieser Dienste zu finden.
Die Funktion password_hash() generiert ein zufälliges Salt, sollte beim Aufruf der Funktion keines übergeben werden. Dies ist generell der einfachste und sicherste Ansatz.
Die Funktionen password_hash() oder crypt() geben den Salt als einen Teil des generierten Hashs zurück. Dieser Wert sollte unverändert abgespeichert werden, da er Informationen über den Hashalgorithmus enthält und direkt an die Funktion password_verify() oder crypt() übergeben werden kann um ein Passwort zu verifzieren.
Das folgende Diagramm zeigt das Format eines Rückgabewertes der Funktionen crypt() oder password_hash(). Wie sie sehen können, enthalten die Hashes alle Informationen über Hashalgorithmus und Salt, wie sie für die spätere Verifikation von Passwörtern benötigt werden.