Sicheres Hashing in PHP

PHP bringt prinzipiell alles mit, um anständiges Hashing zu betreiben. bcrypt ist der Way To Go, aber auch ohne bcrypt kann man mit vernünftigem Einsatz der vorhanden Hashing-Algorithmen (Iterationen + Salt) gut zurechtkommen – Symfony machts im MessageDigestPasswordEncoder.php richtig. Hauptproblem ist aber, dass vom Durchschnitts-Nutzer zuviel Wissen abverlangt wird, um wirklich sicheres Hashing zu betreiben. Deswegen schickt sich jetzt in PHP 5.5 eine Hashing-Library an, es besser zu machen. Bis es soweit ist und die Funktionalität im Core ankommt, gibt es für PHP >= 5.3.7 eine Compatiblity-Library, die das Verhalten der kommenden Hashing-Funktionen nachbildet.

Die Signaturen der Funktionen aus der Compat-Library sind wie folgt:

password_hash($password, $algo, $options = array())

Wobei im Options-Array der cost-Factor von bcrypt und das salt spezifiziert wird. Verwendung dann wie folgt:

$password = "foo";
$opts = array("cost" => 15, "salt" => "this is my salt, that I use for salting");
$hash = password_hash($password, PASSWORD_BCRYPT, $opts); //$2y$12$dGhpcyBpcyBteSBzYWx0L.QLYHdN06l.OhslYu9VilOYVwFApNezu

Weiter gehts mit password_get_info:

password_get_info($hash)

Da der Cost-Faktor und der Hashing-Algorithmus mit im Hash gespeichert wird (was KEIN Sicherheitsverlust ist, da es nur um das Erschweren von Rainbowtable-Angriffen geht), können wir die Infos natürlich auch wieder auslesen:

$hash = "$2y$12$dGhpcyBpcyBteSBzYWx0L.QLYHdN06l.OhslYu9VilOYVwFApNezu";
print_r(password_get_info($hash));
/*
Array
(
    [algo] => 1
    [algoName] => bcrypt
    [options] => Array
	(
		[cost] => 12
	)
)
*/

Darauf aufbauend lässt sich auch ermitteln, ob ein Passwort neu gehasht werden muss, etwa weil sich der Cost-Faktor geändert hat.

password_needs_rehash($hash, $algo, array $options = array())

Wichtig: Das salt wird hierbei nicht beachtet.

$opts = array("cost" => 13);
var_dump(password_needs_rehash($hash, PASSWORD_BCRYPT, $opts)); //bool(true)

Und natürlich die Verifikation, die einfacher kaum ausfallen könnte:

password_verify($password, $hash)

In der Praxis:

var_dump(password_verify("foo", '$2y$15$dGhpcyBpcyBteSBzYWx0L.TvUDgIgEuPSAJGRCDlJKS8ZI/HaKF4S')); //bool(true)

Das vollständige RFC, weitere Beispiele und eine umfassende Erkärung gibts im PHP-Wiki. Eine gute Entwicklung!

Weitere Posts:

Dieser Beitrag wurde unter php, Security, webdev veröffentlicht. Setze ein Lesezeichen auf den Permalink.

2 Antworten auf Sicheres Hashing in PHP

  1. Alex sagt:

    Und so einfach ist es wirklich, komisch dass dies oft einfach nicht gemacht wird…
    (kleine Korrektur?)
    $opts = array("cost" => 15, "salt" => "this is my salt, that I use for salting"); legt einen Cost-Factor von 15 fest, daraus sollte dann kein Hash wie
    $2y$12$dGhpcyBpcyBteSBzYWx0L.QLYHdN06l.OhslYu9VilOYVwFApNezu entstehen. Im letzten Code-Snippet ist dann die 15 wieder dabei.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert