PHP
Passwort-Hashing-Funktionen
Suche…
Einführung
Da sicherere Web-Services das Speichern von Passwörtern im Klartextformat vermeiden, bieten Sprachen wie PHP verschiedene (nicht dekodierbare) Hash-Funktionen zur Unterstützung des sichereren Industriestandards. Dieses Thema enthält Dokumentation für das korrekte Hashing mit PHP.
Syntax
-
string password_hash ( string $password , integer $algo [, array $options ] )
-
boolean password_verify ( string $password , string $hash )
-
boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )
-
array password_get_info ( string $hash )
Bemerkungen
Vor PHP 5.5 können Sie das Kompatibilitätspaket verwenden , um die Funktionen password_*
bereitzustellen. Es wird dringend empfohlen, das Kompatibilitätspaket zu verwenden, wenn Sie dazu in der Lage sind.
Mit oder ohne Kompatibilitätspaket hängt die korrekte Bcrypt-Funktionalität von crypt()
von PHP 5.3.7 und höher ab. Andernfalls müssen Sie Kennwörter auf Nur-ASCII-Zeichensätze beschränken.
Hinweis: Wenn Sie PHP 5.5 oder niedriger verwenden, verwenden Sie eine nicht unterstützte Version von PHP, die keine Sicherheitsupdates mehr erhält. Aktualisieren Sie so schnell wie möglich. Sie können anschließend Ihre Passwort-Hashes aktualisieren.
Algorithmusauswahl
Sichere Algorithmen
- bcrypt ist die beste Option, wenn Sie die Hashberechnungszeit mit Key Stretching erhöhen, da Brute-Force-Angriffe extrem langsam werden .
- argon2 ist eine weitere Option, die in PHP 7.2 verfügbar sein wird .
Unsichere Algorithmen
Die folgenden Hash-Algorithmen sind für den Zweck unsicher oder nicht geeignet und sollten daher nicht verwendet werden . Sie waren nie für Passwort-Hashing geeignet, da sie für schnelle Digests statt langsamer und schwer zu erzwingender Passwort-Hashes ausgelegt sind.
Wenn Sie einen von ihnen verwenden , auch Salze, sollten Sie so schnell wie möglich zu einem der empfohlenen sicheren Algorithmen wechseln .
Algorithmen als unsicher betrachtet:
- MD4 - Kollisionsangriff 1995 gefunden
- MD5 - Kollisionsangriff im Jahr 2005 gefunden
- SHA-1 - Kollisionsangriff im Jahr 2015 demonstriert
Einige Algorithmen können sicher als Message Digest-Algorithmus zum Nachweis der Authentizität verwendet werden, niemals jedoch als Passwort-Hashing-Algorithmus :
- SHA-2
- SHA-3
Beachten Sie , starke Hashes wie SHA256 und SHA512 sind ungebrochen und robust, jedoch ist es in der Regel sicherer bcrypt oder argon2 Hash - Funktionen zu verwenden , wie Brute - Force - Angriffe gegen diese Algorithmen viel schwieriger für klassische Computer sind.
Stellen Sie fest, ob ein vorhandener Kennwort-Hash auf einen stärkeren Algorithmus aktualisiert werden kann
Wenn Sie die PASSWORD_DEFAULT
Methode verwenden, damit das System den besten Algorithmus für das PASSWORD_DEFAULT
Ihrer Kennwörter auswählen kann, da der Standardwert zunimmt, können Sie alte Kennwörter bei der Anmeldung erneut verwenden
<?php
// first determine if a supplied password is valid
if (password_verify($plaintextPassword, $hashedPassword)) {
// now determine if the existing hash was created with an algorithm that is
// no longer the default
if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) {
// create a new hash with the new default
$newHashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT);
// and then save it to your data store
//$db->update(...);
}
}
?>
Wenn die Funktionen password_ * auf Ihrem System nicht verfügbar sind (und Sie das in den folgenden Anmerkungen verknüpfte Kompatibilitätspaket nicht verwenden können), können Sie den Algorithmus bestimmen und den ursprünglichen Hash mit einer der folgenden Methode ähnlichen Methode erstellen:
<?php
if (substr($hashedPassword, 0, 4) == '$2y$' && strlen($hashedPassword) == 60) {
echo 'Algorithm is Bcrypt';
// the "cost" determines how strong this version of Bcrypt is
preg_match('/\$2y\$(\d+)\$/', $hashedPassword, $matches);
$cost = $matches[1];
echo 'Bcrypt cost is '.$cost;
}
?>
Passwort-Hash erstellen
Erstellen Sie Kennwort-Hashes mit password_hash()
, um den aktuellen Standard-Hash oder die Ableitung von Schlüsseln der Branche zu verwenden. Zum Zeitpunkt des Schreibens ist der Standard bcrypt , was bedeutet, dass PASSWORD_DEFAULT
den gleichen Wert wie PASSWORD_BCRYPT
.
$options = [
'cost' => 12,
];
$hashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT, $options);
Der dritte Parameter ist nicht obligatorisch .
Der 'cost'
sollte auf der Grundlage der Hardware Ihres Produktionsservers ausgewählt werden. Wenn Sie es erhöhen, wird die Generierung des Passworts teurer. Je teurer es ist zu generieren, desto länger dauert es, wenn jemand versucht, es zu knacken, um es auch zu erzeugen. Die Kosten sollten im Idealfall so hoch wie möglich sein, aber in der Praxis sollten sie so festgelegt werden, dass sie nicht alles zu sehr verlangsamen. Irgendwo zwischen 0,1 und 0,4 Sekunden wäre das okay. Verwenden Sie den Standardwert, wenn Sie sich nicht sicher sind.
Bei PHP unter 5.5.0 sind die Funktionen password_*
nicht verfügbar. Sie sollten das Kompatibilitätspaket verwenden, um diese Funktionen zu ersetzen. Beachten Sie, dass für das Kompatibilitätspaket PHP 5.3.7 oder höher oder eine Version erforderlich ist, für die der $2y
Fix zurückportiert wurde (z. B. RedHat).
Wenn Sie diese nicht verwenden können, können Sie Kennwort-Hashing mit crypt()
implementieren. Da password_hash()
als Wrapper für die Funktion crypt()
implementiert ist, müssen Sie keine Funktionalität verlieren.
// this is a simple implementation of a bcrypt hash otherwise compatible
// with `password_hash()`
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
// if `CRYPT_BLOWFISH` is 1, that means bcrypt (which uses blowfish) is available
// on your system
if (CRYPT_BLOWFISH == 1) {
$salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$salt = base64_encode($salt);
// crypt uses a modified base64 variant
$source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$dest = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$salt = strtr(rtrim($salt, '='), $source, $dest);
$salt = substr($salt, 0, 22);
// `crypt()` determines which hashing algorithm to use by the form of the salt string
// that is passed in
$hashedPassword = crypt($plaintextPassword, '$2y$10$'.$salt.'$');
}
Salz für Passwort-Hash
Trotz der Zuverlässigkeit des Krypto-Algorithmus besteht immer noch eine Sicherheitsanfälligkeit gegen Regenbogen-Tabellen . Aus diesem Grund wird empfohlen, Salz zu verwenden.
Ein Salt wird vor dem Hashing an das Kennwort angehängt, um die Quellzeichenfolge eindeutig zu machen. Bei zwei identischen Passwörtern sind die resultierenden Hashes ebenfalls eindeutig, da ihre Salze eindeutig sind.
Ein zufälliges Salt ist eines der wichtigsten Elemente Ihrer Passwortsicherheit. Dies bedeutet, dass ein Angreifer selbst bei einer Nachschlagetabelle mit bekannten Kennworthashes den Kennworthash des Benutzers nicht mit den Datenbankkennworthashes abgleichen kann, da ein zufälliger Salt-Salt verwendet wurde. Sie sollten immer zufällige und kryptographisch sichere Salze verwenden. Weiterlesen
Mit dem bcrypt
Algorithmus password_hash()
wird Klartext-Salt zusammen mit dem resultierenden Hash gespeichert. Das bedeutet, dass der Hash zwischen verschiedenen Systemen und Plattformen übertragen werden kann und dennoch mit dem ursprünglichen Passwort abgeglichen werden kann.
Selbst wenn dies nicht empfohlen wird, können Sie die salt
Option verwenden, um Ihr eigenes zufälliges Salt zu definieren.
$options = [
'salt' => $salt, //see example below
];
Wichtig Wenn Sie diese Option nicht angeben, wird von password_hash () für jedes Passwort-Hash ein zufälliger Salt generiert. Dies ist die vorgesehene Betriebsart.
Die Salt-Option wurde ab PHP 7.0.0 nicht mehr unterstützt. Es wird jetzt bevorzugt, einfach das standardmäßig erzeugte Salz zu verwenden.
Überprüfen eines Passworts gegen einen Hash
password_verify()
ist die eingebaute Funktion (ab PHP 5.5), um die Gültigkeit eines Passworts gegen einen bekannten Hash zu überprüfen.
<?php
if (password_verify($plaintextPassword, $hashedPassword)) {
echo 'Valid Password';
}
else {
echo 'Invalid Password.';
}
?>
Alle unterstützten Hash-Algorithmen speichern Informationen, die angeben, welcher Hash im Hash selbst verwendet wurde. Daher müssen Sie nicht angeben, mit welchem Algorithmus Sie das Klartext-Kennwort verschlüsseln.
Wenn die Funktionen password_ * auf Ihrem System nicht verfügbar sind (und Sie das in den nachstehenden Anmerkungen verknüpfte Kompatibilitätspaket nicht verwenden können), können Sie die Kennwortüberprüfung mit der Funktion crypt()
. Bitte beachten Sie, dass besondere Vorsichtsmaßnahmen getroffen werden müssen, um Timing-Angriffe zu vermeiden.
<?php
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
if (CRYPT_BLOWFISH == 1) {
// `crypt()` discards all characters beyond the salt length, so we can pass in
// the full hashed password
$hashedCheck = crypt($plaintextPassword, $hashedPassword);
// this a basic constant-time comparison based on the full implementation used
// in `password_hash()`
$status = 0;
for ($i=0; $i<strlen($hashedCheck); $i++) {
$status |= (ord($hashedCheck[$i]) ^ ord($hashedPassword[$i]));
}
if ($status === 0) {
echo 'Valid Password';
}
else {
echo 'Invalid Password';
}
}
?>