Bin da gestern drüber gestolpert:
bcrypt
password_hash()
password_verify()
password_needs_rehash()
Zum Thema "Salt":
Falls sich jemand fragt,
"warum denn den Salt mit speichern. Und was, wenn die db gehackt wird? Dann hat der Angreifer ja alle zugehörigen Salts?!"
>>The only requirement for a salt is for it to be globally unique. It does not have to be kept secret. password_hash() takes care of it for you. Don't do anything fancy and stupid.
Einfache Übersetzung:
Das wichtigste ist, dass das Salt einzigartig ist. Es muss nicht geheim sein.
password_hash() kümmert sich um das Salt. Es macht also keinen Sinn sich eine "Beste-Salt-function-ever" zu basteln.
heißt: der Funktion password_hash() kein eigenen Salt mitgeben
siehe auch: php.net: "Caution It is strongly recommended that you do not generate your own salt for this function."
&
>>Sehr gute Erklärung - also lesen!
Hier mal eine kurze Zusammenfassung (ohne Übersetzung =)
- The reason we use salts is to stop precomputation attacks, such as rainbow tables.
- So, we use a salt. A salt is a random unique token stored with each password.
- nobody has rainbow tables that include that hash.
- The goal is to force the attacker to have to crack the hashes once he gets the database, instead of being able to just look them all up in a rainbow table.
- One other idea to consider is a pepper. A pepper is a second salt which is constant between individual passwords, but not stored in the database. (KDF(password + pepper, salt))
- So, how do we prevent brute-force attacks now?
- A more solid approach is to use a key derivation function with a work factor. These functions take a password, a salt and a work factor. The work factor is a way to scale the speed of the algorithm against your hardware and security requirements:
hash = KDF(password, salt, workFactor) (siehe password_hash() "cost"-Faktor)
Hier ein einfaches Bsp:
- /*(simuliert) formular daten bei registrierung:*/
- $_POST['uname'] = 'cottton';
- $_POST['pw'] = '12345678';
- /*fester "geheimer" wert ("pepper")*/
- // kann zB in einer config.php als constant definiert werden: define('PEPPER', 'bisschenPfeffer?') wobei schon etwas konstantes und schwer zu erratenes genutzt werden sollte
- $pepper = 'bisschenPfeffer?';
- /*hash:*/
- // wird erst erstellt, wenn alle benötigten benutzereingaben vorhanden sind
- $hash = password_hash($_POST['pw'] . $pepper, PASSWORD_BCRYPT, array('cost' => 12));
- # ^= $2y$12$sWGjyoZ9xDwuGLou6fvije3q3T5SV1cGbgS.wCKsWicdTXK9czeV6
- /*speichere nutzerdaten in db:*/
- // hier testweise nur ein var_dump !
- var_dump($hash);
- /*(simuliert) formular daten bei anmeldung:*/
- $_POST['uname'] = 'cottton';
- $_POST['pw'] = '12345678';
- /*(simuliert) daten aus db laden:*/
- $db_daten = array(
- 'uname' => 'cottton',
- 'pw' => '$2y$12$sWGjyoZ9xDwuGLou6fvije3q3T5SV1cGbgS.wCKsWicdTXK9czeV6',
- );
- /*prüfen ob hash aus db zu passwort aus anmeldung passt*/
- // dabei muss PEPPER an die gleiche stelle angehangen werden, wie es beim erstellen des hashes geschehen ist
- $valid = password_verify($_POST['pw'] . $pepper, $db_daten['pw']);
- var_dump(
- $valid
- ? 'Password is valid!'
- : 'Invalid password!'
- );
Zusammenfassung:
Wir haben also erreicht, dass der Angreifer:
- in die db eindringen muss (klar) um den Passwort-hash und Salt zu bekommen
- aber auch zugriff auf das Pfeffer ($pepper) haben muss - sich somit also auch Zugriff auf die Files verschaffen muss
- gezwungen ist den Passwort-hash zurück zu Rechnen, anstatt in "rainbow tables" danach zu suchen.
Das Ganze nun noch abgerundet, indem man Prepared Statements nutzt (siehe php.net "PDO"), um eine SQL-injection zu verhindern (wenn richtig angewandt!).
EDIT: 05.06.2016
Es ist wichtig die Funktion password_verify zur Prüfung des Passwortes zu nutzen
wenn sich User sich einloggt nicht if ($hash === $hashLogin), sondern wirklich password_verify() nutzen
Warum: um Timing_attacks zu unterbinden.
Siehe http://stackoverflow.com/a/29489833/3411766
http://stackoverflow.com/a/29489833/3411766 schrieb:
The answer is YES it uses length-constant time comparison.
This is an excerpt of php's password_verify function
You can have a look at the full source code at https://github.com/php/php-src…r/ext/standard/password.c
"Man kanns auch übertreiben ..." ? - Nein. Man kann es auch gleich richtig machen =)