Passwort vergessen?

Benutzername vergessen?

Alles rund um IT, Web und Entwicklung.
Von Nutzern für Nutzer.

(PHP) Passwörter sicher verschlüsseln



Bei der Planung von Webanwendungen sollte man stets auf die Sicherheit achten. Gerade beim abspeichern von Passwörtern in Datenbanken ist Vorsicht geboten.



In diesem Artikel wird eine sichere Implementierung zum Speichern von Passwörtern in Datenbanken vorgestellt.


Theorie


Zunächst sollte man bedenken, dass Passwörter keinesfalls im Klartext gespeichert werden dürfen. In der Vergangenheit wurden des öfteren Sicherheitslücken in Datenbanken genutzt, um Passwörter auszuspionieren.

Daher ist es ratsam Passwörter in verschlüsselter Form in der Datenbank abzulegen. Die einfachste Methode ist das bilden der MD5-Prüfsumme des Passwort-Strings.

Das Passwort "testpasswort" würde also wie folgend in Form eines 128-Bit Hashes abgespeichert werden:

e16b2ab8d12314bf4efbd6203906ea6c

In PHP würde dies wie folgt durchgeführt werden:

<?php 
    $password_hash 
md5("testpasswort");
?>


Verschlüsselung vs Hash


Bei MD5 oder SHA von einer Verschlüsselung zu reden ist genau betrachtet falsch. Eine Prüfsumme dient zur Verifizierung der Integrität eines Objektes (z.B. eine Zeichenkette) und ist nicht umkehrbar.

Eine echte Verschlüsselung ist immer umkehrbar. Besitzt man den passenden Schlüssel, kann also die ursprüngliche Information dargestellt werden.

Der Unterschied wird oft nicht beachtet, weshalb ich im folgenden der Einfachheit halber von Verschlüsselung rede.


Die MD5 Methode wurde des öfteren geknackt und gilt somit als weniger sicher. Daher wird meist der Secure Hash Algorithm verwendet.

Hier gibt es Unterschiede bei den Hash-Größen. Die zwei wichtigsten sind hier SHA256 und SHA512. Die Zahl hinter SHA steht hierbei für die Größe des Hashes (z.B. 512-Bit).

In der Regel genügt ein 256-Bit Hash. Wer auf Nummer sicher gehen will, kann auch den 512er Hash verwenden. Allerdings sollte man beachten, dass mit zunehmender Hash-Größe auch die nötige Rechenleistung zum verschlüsseln steigt. Bei einem großen Besucheraufkommen kann es hier zu Problemen kommen.

Nun zur Implementierung in PHP. Glücklicherweise bietet PHP wie auch für MD5 eine eigene Funktion an.

<?php 
    $password_hash 
hash('sha256''testpasswort');
?>


Die Variable $password_hash besitzt anschließend den folgenden Wert.

94ac5813105c9887c263df59d0145af2b4df7b49969a08fba624e55eec25d6b1


Zusätzliche Sicherheit mit einem Salt


Um es Angreifern noch schwieriger zu machen, kann man das Passwort mit einem Salt versehen. Man streut also zusätzlich Salz in die Suppe bzw. das Passwort.

<?php 
    $secret_salt 
"topsecretsalt";
    
$password "testpasswort";
    
$salted_password $secret_salt $password;
    
$password_hash hash('sha256'$salted_password);
?>


Dies würde folgendes Ergebnis liefern:

a77fb85ed091a4a2c677d558a253cbff1f11c84abf5076cd9a1bf0d623e04170

wobei das eigentliche Passwort des Benutzers als SHA256 Hash einen komplett anderen Wert besitzt.

Sollte ein Angreifer also den 256-Bit Hash knacken, was bisher noch nicht einmal der geheimsten Organisation mit 3 Buchstaben gelungen ist, dann hat er erst das "versalzene" Passwort. Dementsprechend sollte man gerade beim Salt keine eindeutigen Zeichenketten verwenden.

Platzbedarf in Datenbanken


Um den Passwort Hash nun in die Datenbank zu legen, sollte man sich zunächst einige Gedanken über die Größe und damit den Datentyp machen.

SHA256 liefert einen 256-Bit Hash zurück. Bei 4 Bit pro Zeichen entspricht das einem VARCHAR mit einer Länge von 64.
Bei der Verwendung von SHA512 beträgt die Länge des VARCHAR 128.

Praktischer Nebeneffekt bei gehashten Passwörtern: die Größe des Strings ist immer gleich. Man muss also in der Datenbank keine riesigen Felder reservieren bzw. die Passwortlänge der Benutzer nicht einschränken.


Passwort überprüfen


Um eine Passworteingabe des Benutzer zu überprüfen muss der eingegebene String wieder auf die gleiche Weise versalzen und verschlüsselt werden. Anschließend wird der neue Hash mit dem aus der Datenbank verglichen.

<?php 
    
function encrypt_password($password) {
        
$secret_salt "topsecretsalt";
        
$password "testpasswort";
        
$salted_password $secret_salt $password;
        
$password_hash hash('sha256'$salted_password);

        return 
$password_hash;
    }

     
// Benutzername
     
$username "foxplex";

     
// Vom Benutzer eingegebenes Passwort
     
$user_password "testpasswort";

     
// Passwort des Benutzers verschlüsseln
     
$user_password_hash encrypt_password($user_password);

     
// Benutzer und Hash prüfen
     
$sql "SELECT userid FROM users WHERE username = '$username' AND password_hash = '$user_password_hash'";

     
$result $db->query($sql);

     if (
$result->num_rows == 1) {
        
// Benutzername und Passwort sind korrekt
        
echo "User authenticated";
        exit(
0);
     } else {
        
// Benutzername oder Passwort sind falsch
        
echo "Wrong username or password";
        exit(
1);
     }
?>



Fazit


Im Umgang mit Passwörtern ist Vorsicht geboten. Dank bewährten Verschlüsselungsverfahren wie dem SHA und den bereits vorhandenen Funktionen in PHP ist es sehr einfach möglich, sichere Webanwendungen zu konstruieren.


Michael Kostka

Fachinformatiker / Systemintegration
Ich schreibe hier regelmäßig zu den Themen Android, Web, Linux und Hardware.

Raspberry Pi Starter Kit
DataCloud

Hinterlasse einen Kommentar

Ich habe die Datenschutzerklärung zur Kenntnis genommen und stimme einer elektronischen Speicherung und Verarbeitung meiner eingegebenen Daten zur Beantwortung der Anfrage zu.

Lukas

23.08.2017 14:50

Super Tutorial :)
Ich habe das ganze so gemacht, dass das beim Login der Salt neu gemacht wird und auch in der Datenbank gespeichert wird. Somit ist selbst der Salt komplett Random und bei jedem Login neu gemacht.

Hier mein Code:
//Starte die Session
session_start();

//Global Config einbinden
require('global_config.php');

//Datenbankverbindung prüfen
$con = mysqli_connect(host, user, pass, db);
$user_id = '1';
$get_user = mysqli_query($con, "SELECT `username`, `salt`, `password_hash` FROM `blox_user` WHERE `user_id` = '$user_id'");
$gu = mysqli_fetch_array($get_user);
$salt = $gu['salt'];
$passwort = "test123";

$salted = $salt.$passwort;

$password_hash = hash('sha256', $salted);
echo $password_hash."<br><br>= ";
echo $gu['password_hash'];

$new_salt = rand(111111111,999999999);
$new_salted = $new_salt.$passwort;
$new_hash = hash('sha256', $new_salted);
echo "<br><br>Nächster Hash = ";
echo $new_hash;

$update_salt = mysqli_query($con, "UPDATE `blox_user` SET `salt` = '$new_salt', `password_hash` = '$new_hash'");

Ayna

10.01.2017 17:01

Gute Informationen, ziemlich hilfreich. Danke.

Wenzel

06.06.2016 16:11

Danke für die Hinführung ... hatte erst mit pbkdf2 rumprobiert stieß aber da auf nicht reproduzierbare Ergebnisse!?

Jan Gregor Triebel

11.06.2012 13:28

Ein zusätzlicher Sicherungsmechanismus wäre eine zufällige Erstellung des Salts beim Anmelden des Users. Das Salt kann dann als Klartext mit in der DB gespeichert werden und wird beim Login erst einmal abgefragt um den Hash zu erzeugen.

Der Vorteil liegt darin, dass auch bei einem bekannten Salt keine Hash Tabelle berechnet werden könnte, bzw für jeden User neu berechnet werden müsste, was den Aufwand unrentabel macht.