| Passwort Hash mit der Bcrypt Klasse |
|
Zunächst etwas Hintergrundinfo zu md5, Bcrypt und Co. Stellt sich die Frage, wieso md5() eine Schwachstelle ist?! Was kann man also tun? Die Bcrypt KlasseHier zunächst die Klasse, im Anschluss dann ein kurzes Anwendungsbeispiel. <?php /** * phpBuddy.eu Bcrypt Klasse * * Erzeugt einen Passwort-Hash mittels Blowfish Algorithmus. * * @author Andreas Skodzek <webmaster@phpbuddy.eu> * @link http://www.phpbuddy.eu/ * @copyright 2011 Andreas Skodzek * @license GNU Public License <http://www.gnu.org/licenses/gpl.html> * @package phpBuddy Bcrypt * @version 1.0 released 10.02.2011 */ class Bcrypt { /** * Konstante mit erlaubten Zeichen für den Passwortzusatz */ const SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; /** * @param int Anzahl der Wiederholungen (Cost). minimal 4, maximal 31 */ public static $cost = 12; /** * * @param array Nimmt die Informationen Passwort, Salt, Wiederholungen und Hash auf */ public static $info = array(); /** * Erzeugt einen Hash aus einem Passwort * * @param string $passwort Passwort * @param int $cost Anzahl der Wiederholungen * @return array */ public static function hash($passwort, $cost = NULL) { // Prüfen ob Blowfish vom Server unterstützt wird self::check_blowfish(); // Blowfish Algorithmus self::$info['algo'] = '$2a$'; // 22-stelligen Salt erzeugen der für Blowfish erforderlich ist $tmp_salt = ''; for ($i = 0; $i <= 21; $i++) { $tmp_str = str_shuffle(self::SALTCHARS); $tmp_salt .= $tmp_str[0]; } // Salt im Info-Array ablegen self::$info['salt_string'] = $tmp_salt; // Anzahl der Wiederholungen ermitteln if ($cost) { // Führende Null voranstellen bei einstelliger Wiederholung self::$info['cost'] = sprintf('%02d', min(31, max(intval($cost), 4))); } else { // Standard verwenden self::$info['cost'] = self::$cost; } // Komplettes Salt mit Algorithmus und Wiederholungen self::$info['salt_komplett'] = self::$info['algo'] . self::$info['cost'] . '$' . self::$info['salt_string'] . '$'; // Passwort Hash erzeugen self::$info['hash'] = crypt($passwort, self::$info['salt_komplett']); // Info-Array zurückgeben return self::$info; } /** * Prüft ein Passwort gegen einen Hash * * @param string $passwort Passwort aus dem der zu vergleichende Hash erzeugt werden soll * @param string $hash Der zu vergleichende Hash mit komplettem Salt * @return bool */ public static function check_hash($passwort, $hash) { // Prüfen ob Blowfish vom Server unterstützt wird self::check_blowfish(); // Komplettes Salt mit Algorithmus und Wiederholungen aus dem Hash extrahieren $tmp_salt = substr($hash, 0, 29); // Vergleichshash erzeugen $tmp_hash = crypt($passwort, $tmp_salt . '$'); // Stimmt das Passwort mit dem Hash überein ist der Rückgabewert TRUE, ansonsten FALSE return ($tmp_hash == $hash) ? TRUE : FALSE; } /** * Prüft ob der Blowfish Algorithmus unterstützt wird */ private static function check_blowfish() { if ( ! defined('CRYPT_BLOWFISH')) { throw new Exception('Bcrypt wird von diesem Server leider nicht unterstützt!'); } } } Wie man im Kommentar von $cost sehen kann, ist ein Wert zwischen 4 und 31 möglich. Anwendungsbeispiel <?php header( 'Content-Type: text/html; charset=utf-8' ); error_reporting( 0 ); // Klasse einbinden include 'bcrypt.php'; // Anwendungsbeispiel try { // Hash von Passwort erzeugen // Bcrypt::hash($passwort, $wiederholungen) // Liefert ein Array mit Algorithmus, Wiederholungen (Cost), Salt String, Salt komplett und Hash zurück // Hash ist der Wert der gespeichert wird und den man mit check_hash() gegen ein Passwort vergleicht $info = Bcrypt::hash('strenggeheim', 12); var_dump($info); // Passwort mit einem Hash (z.B. aus einer Datenbank) vergleichen // Bcrypt::hash($passwort, $hash) // Stimmt das Passwort mit dem Hash überein liefert die Funktion TRUE, ansonsten FALSE zurück var_dump(Bcrypt::check_hash('strenggeheim', $info['hash'])); } catch (Exception $error) { echo $error->getMessage(); } Da der Code ausführlich kommentiert ist, sollten keine Fragen mehr offen bleiben. Neben der Klasse und dem Anwendungsbeispiel befindet sich in der Zip Datei auch eine Mini-Anwendung in Form eines sehr schlicht gehaltenen Login Scripts. Dieses Login Script dient ausschließlich der Demonstration und ist nicht dazu gedacht einfach in ein produktives System übernommen zu werden, denn dafür ist es ganz und gar nicht ausgelegt! Nochmal der eindringliche Hinweis, dass dieses Login Script nur zur Anschauung gedacht ist und nicht im produktiven Einsatz eingesetzt werden soll! Ich weiss, einige sind von diesen Hinweisen genervt, aber immer wieder missachten User diese Hinweise, kopieren ohne nötigen Sachverstand 1:1 die Scripts und rennen dann mit dem Kopf gegen eine Wand, weil sie nicht mehr weiter wissen. Anschließend treffen bei mir dann verzweifelte Hilfemails ein, in denen um Anpassungen und Erklärungen gebeten wird. Viel Spaß mit der Bcrypt Klasse und happy encrypting! :-) Bcrypt Klasse (8 KB) |