Passwörter sicher speichern

2 | 17 Kommentare | 34168 Aufrufe
Sie können diese Wikiseite nach der Anmeldung auf Webmasterpro bearbeiten. Helfen Sie mit und verbessern Sie "Passwörter sicher speichern" mit Ihrem Wissen!

Anzeige Hier werben

Passwörter sollten niemals im Klartext gespeichert werden. Fallen die Benutzerdaten in falsche Hände, können diese missbräuchlich genutzt werden - besondere Gefahrt entsteht durch den Umstand, dass viele Benutzer ein Passwort mehrfach einsetzen. Passwörter sollten in jedem Fall sicher gespeichert werden.

Um die gespeicherten Passwörter für Fremde nutzlos zu machen, verschlüsselt man diese oder generiert einen Hash-Wert.

Verschlüsseln

Das Passwort wird mittels eines geheimen Schlüssels (Zeichenkette) verschlüsselt. Nachteil: Zum Entschlüsseln benötigt man immer zwingend den Schlüssel. Bekommt der Angreifer diesen Schlüssel in die Hände, hat er Zugriff auf alle Passwörter. Gerade weil der Schlüssel auf dem Server selbst hinterlegt sein muss, kann es für Angreifer ein einfaches sein den Schlüssel zu erhalten und für seine Zwecke zu missbrauchen.

PHP bietet zum Ver- und Entschlüsseln unter anderem die Funktion mcrypt(). Diese Funktion unterstützt eine Vielzahl von Algorithmen.

Hashing

Kollisionen

Von einer Kollision spricht man, wenn zwei Daten denselben Hash-Wert erzeugen. Nur über den Hash lässt sich dann nicht mehr erkennen, dass die Eingaben unterschiedlich waren.

Bei allen Hash-Algorithmen treten möglicherweise Kollisionen auf. Ein Hash-Algorithmus gilt dann als unsicher, wenn sich Kollisionen einfach rechnerisch erzeugen lassen.

Ist das möglich kann man ein gültiges Passwort zu einem hinterlegten Hash erzeugen ohne das wirkliche Passwort zu kennen.

Für das Passwort (beliebig lange Zeichenkette) wird ein Hash-Wert mit einer festen Zeichenlänge generiert. Dieser Hash-Wert lässt sich nicht mehr in das ursprüngliche Passwort umwandeln. Um den Benutzer zu authentifizieren, vergleicht man nun den Hash-Wert des eingegeben Passworts mit dem in der Datenbank gespeicherten.

Zur Erstellung eines Hash-Wertes gibt es verschiedene Algorithmen. Hier eine kleine Auswahl:

  • md5 Weit verbreitet aber gilt als nicht mehr uneingeschränkt sicher da sich Kollisionen erzwingen lassen.
  • SHA-1 auch hier gibt es inzwischen Techniken um Kollisionen zu erzeugen, allerdings ist es aufwendiger als bei md5. Es ist daher besser eine der stärkere SHA-Varianten zu verwenden.
  • SHA-224/256/384/512 Die Zahl steht für die Länge des Hash-Wertes in Bit. Da der Hash somit umfangreicher wird, sinkt die Gefahr von Kollisionen. Diese Methode des Hashings ist daher für das Speichern sicherer Passwörter zu empfehlen.

PHP stellt einige Hashing-Funktionen zur Verfügung. Die vielseitigste ist hash(), welche ab PHP 5.1.2 verfügbar ist. In älteren PHP-Versionen kann man diese Funktion per PECL-Extension (PECL hash) nutzen. hash_algos() gibt ein Array mit den verfügbaren Hashing-Algorithmen zurück.

Beispiel  
PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php

// Erzeugung von Passwort-Hash
$password = "geheim";
$hash = hash('sha256', $password);
echo $password . ' : ' . $hash;

// Prüfung (beispielhaft)
$hash = get_user_hash($_POST['username']); // Fiktive Funktion um Hash aus der Datenbank zu laden
if ($hash == hash('sha256', $_POST['password'])) // Prüfung ob Passwort stimmt
{
     echo "Passwort stimmt überein";
}

?>

Salted Hash

Aber auch wenn man das Passwort als Hash-Wert in der Datenbank speichert ist dieses noch nicht ausreichend gegen Angreifer geschützt. Denn mittlerweile gibt es umfangreiche Rainbowtables. Diese enthalten tausende von Hash-Werten mit den dazugehörigen Zeichenketten, so dass man dort mit etwas Glück fündig wird. Gleichzeitig gibt es inzwischen sogar Suchmaschinen, die nach Hash-Werten suchen können. Für allgemein gängige Passwörter reicht also ein normaler Hash nicht aus.

Die Lösung für dieses Problem nennt sich "Salted Hash". Dem Passwort wird etwas "Salz" in Form einer Zeichenkette hinzugefügt. Passwort und "Salz" können beliebig kombiniert werden. In folgendem Beispiel wird die Benutzer-ID an das Passwort angehängt und daraus der Hash-Wert berechnet.

Beispiel  
PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

// Funktion die Passwort mit Hash kombiniert und den so erzeugten hash zurückgibt
function saltPassword($password, $salt)
{
     return hash('sha256', $password . $salt);
}

// Erzeugung von Passwort-Hash mit Salt
$password = "ganz_geheim";
$userID   = 5121; // Die UserID dient hier als einfache Möglichkeit für den Salt (hier als Beispiel 5121)
$salt = $userID;
$saltedHash    = saltPassword($password, $salt);
echo $password . ' : ' . $saltedHash . ' (Salt: ' . $salt . ')';

// Prüfung (beispielhaft)
$saltedHash = get_user_hash($_POST['username']); // Fiktive Funktion um salted Hash aus der Datenbank zu laden
$salt = get_user_id($_POST['username']); // Fiktive Funktion um UserID abzurufen
if ($saltedHash == saltPassword($_POST['password'], $salt)) // Prüfung mit Salt
{
     echo "Passwort stimmt überein";
}

?>

Wichtig ist natürlich, dass auch der Salt im Benutzerdatensatz gesichert wird. Ansonsten wäre es später nicht möglich das Passwort zu prüfen. Im Beispiel wird einfach die User-ID als Hash verwendet, zu empfehlen wäre aber das zufällige Erzeugen eines zufälligen Salts. Beispielsweise können zwei bis vier zufällige Zeichen verwendet werden.


Wikiseite bearbeiten

Diese Seite kann von jedem registrierten Benutzer bearbeitet werden. Bisher haben 7 Personen an der Seite "Passwörter sicher speichern" mitgewirkt.

Sie haben einen Fehler entdeckt oder möchten etwas ergänzen? Dann können Sie nach der Anmeldung "Passwörter sicher speichern" hier bearbeiten.


Kommentare: Passwörter sicher speichern

Neuen Kommentar schreiben
Besser: bcrypt
David Danier am 18.07.2012 um 11:52
Kollisionen
Beantworten

So, gleich noch ne Frage an die Mathematiker: Sind Kollisionen nicht vorprogrammiert? Jetzt mal rein rechnerisch für md5: ich habe eine 32-stellige Zeichenkette aus hexadezimalen Werten, d.h. kann ich 32^16 verschiedene Strings überhaupt nur bekommen, was so ungefähr 10^24 Stück sind. Wenn ich jetzt die Hashs von 0000000000000000 bis FFFFFFFFFFFFFFFF (hexadezimal) mir berechnen lassen würde, müsste doch danach eine Kollision auftreten oder nicht. Die Wahrscheinlichkeit ist wird dann auch mit zunehmenden Längen immer geringer, aber möglich sind die dann doch auch bei den Sha Algorithmen oder nicht?

Holger V am 29.07.2008 um 15:38
Re: Kollisionen
Beantworten

Vollkommen korrekt. Genau das hab ich eigentlich versucht in der Box oben klarzustellen, war vorher etwas schwammig. Um die Qualität eines Hash-Algorithmus zu bewerten wird geschaut, wie gut die Verteilung der Hash-Summen ist und wie groß der Aufwand ist künstlich eine Kollision zu erzeugen (sprich zu einem Hash Eingabedaten zu finden die passen, aber nicht unbedingt dem Orginal entsprechen).

David Danier am 29.07.2008 um 18:05
Re: Kollisionen
Beantworten

Kollisionen sind selbstverständlich: wenn man einen String beliebiger Länge auf eine feste Länge "zerhackt" (daher hash), dann müssen Kollisionen auftreten. Geschichte Algos vermeiden Kollisionen, bzw erkennen sie. Deswegen gibt es in jedem Hash Kollisionen!

Man spricht von kollisionsresistenten Algorithmen (CRHF), wenn (quasi) keine Kollisionen auftreten; die erzeugten Hashes gut verteilt sind. Bei großen SHAs ist die Wahrscheinlichkeit für Kollisionen niedriger, daher sicherer.

Benutzer gelöscht am 29.07.2008 um 16:04
Re: Kollisionen
Beantworten

Bin zwar kein Mathematiker, aber das ist korrekt. Ein Hash macht im Grunde nichts anderes als eine variable Datenmenge auf eine feste Datenmenge abzubilden, ohne dass eine Umkehroperation möglich ist (zumindest theoretisch). Es ist absolut unvermeidbar, dass es Kollisionen geben wird - schliesslich bilden wir eine unendlich grosse Menge auf eine begrenzte Menge ab. Die Frage ist eher, wie schwierig es ist, zwei Datensätze zu finden die den gleichen Hash haben. Oder noch schlimmer, wie schwierig ist es für einen gegebenen Datensatz einen anderen zu finden der den gleichen Hash hat. Zum Beispiel werden oft Transaktionen (z.B. eine Banküberweisung) nicht direkt mit einem Schlüssel signiert (da dies sehr aufwendig ist), sondern man berechnet einen Hash der Daten und signiert dann diesen. Zur Verifizierung vergleicht man nun den Hash, und dann die Signatur. Wenn es nun einem Angreifer möglich ist, die Transaktion zu verändern ohne dass sich dabei der Hash ändert, haben wir eine Lücke im System. Theoretisch gibt es zwar immer eine Kollision, die Frage ist aber ob man daraus auch eine gültige Transaktion bilden kann, und wie lange man braucht um eine solche Kollision zu finden.

Cedric Staub am 29.07.2008 um 16:00
Re: Kollisionen
Beantworten

Und als follow-up ein Link zu einem Paper von Dan Kaminsky über MD5-Kollisionen sowie die dazugehörige Präsentation. Siehe dazu auch seine Homepage, DoxPara Research.

Cedric Staub am 29.07.2008 um 16:09
Salts
Beantworten

Moin,

kann mir mal wer den Sinn von Salts nahe bringen oder erklären was es wirklich bringt? Jetzt mal auf das Beispiel hier bezogen, verlängert das doch maximal die Zeit, die bei einer BruteForce Methode zum Hacken der Hashs benötigt wird, da ein paar mehr Zeichen vorliegen. Den Hash macht es trotzdem nicht sicher, wenn derjenige, der die Hashs entschlüsseln will, schlau ist, sieht er nach vielleicht 10 Hashs die Regelmäßigkeit und hängt ab den BruteForce-String automatisch die Id an, die er ja vermutlich auch hat, wenn er die Passworthashs hat. Auch ein zufälliger Salt von 2 bis 4 Zeichen müsste irgendwo gespeichert werden und gelangt somit vermutlich in die Hände des Angreifers. Dieser muss dann wieder nur die Regelmäßigkeit entdecken und der Mechanismus verliert seine Wirkung.

Man könnte natürlich jetzt nen Salt von 90 Zeichen oder so nehmen, das würde das ganze dann etwas länglich gestalten (BruteForce), aber wirklich sicherer macht es das ganze trotz dessen nicht.

Holger V am 29.07.2008 um 15:25
Re: Salts
Beantworten

Salts helfen vorallem dabei den Nutzer im Falle eines erfolgreichen Hacks zu schützen. Gelangt ein Hacker an die Passwort-Hash-DB und crackt die Hashes, hat er z.B. E-Mail-Adresse und Passwort und kann versuchen sich damit auf anderen Portalen einzuloggen. Mehr dazu auf: http://code-bude.net/2015/03/30/grundlagen-sicheres-passwort-hashing-mit-salts/

pinguinmann am 12.04.2015 um 12:23
Re: Salts
Beantworten

Was ich noch vergessen hatte. Wenn ich in einer Rainbowtable mit dem "Hash von abcd" "abcd" finde, warum sollte ich dann nicht auch "abcdtz" fingen können?

Holger V am 29.07.2008 um 15:31
Re: Salts
Beantworten

Man muss beim Einsatz von Salts auch etwas "globaler" denken, denn gelingt es wirklich mal einem Angreifer an den Hash und an den Salt eines Users zu gelangen und schafft es dann auch noch eine Kollision zu erzeugen, so funktioniert diese Kollision nicht auf anderen Seiten, bei der der User das gleiche Passwort verwendet (vorrausgesetzt natürlich, dass dort der Salt anders ist).

Ich benutze gerne zufällig generierte Zeichenketten, die ich auch in der Datenbank abspeichere (ja, ist eigentlich unnötig, aber man beugt dem Brute-Force wieder etwas entgegen, da man nicht nur Zahlen benutzt) und zusätzlich noch einen "Mastersalt", der fest im PHP Code verankert ist. Nun kann man noch mehrfach Hash-Algorithmen verwenden und den Salt z.Bsp. 2x dabei verwenden. So ist es 99,99% sicher, dass man das Passwort nicht mehr rekonstruieren kann.

Zu deiner Frage bezüglich der Rainbowtables: In Rainbowtables sind schon die Hashwerte zu bestimmten Wörtern drin. Im Prinzip ähnelt es einer Wörterbuchattacke, die ebenfalls durch Salts zu nichte gemacht wird, nur dass nicht jedes Wort nach und nach probiert wird, sondern direkt der Hashwert. So Rainbowtables sind außerdem sehr umfangreich mit teilweisen mehreren Gigabytes und vor allem sehr schnell.

Ein Salt sichert also das Passwort des Users nur nochmals ab, um die Wahrscheinlichkeit, dass das Passwort wieder rekonstruiert werden kann, zu vermindern, nicht aber, um es unmöglich zu machen, eine Kollision zu finden.

Benutzer gelöscht am 30.07.2008 um 16:22
Re: Salts
Beantworten

Naja, also es gibt auch für md5 Rainbow Tables, die damit werben, dass sie [a-zA-Z0-9]{1,12} können. Das deckt schon einiges ab.

Holger V am 30.07.2008 um 16:31
Re: Salts
Beantworten

Das war ja auch Brute-Force bezogen. Und kleine Sonderzeichen kann man auch ohne Probleme einbauen.

Benutzer gelöscht am 30.07.2008 um 19:51
Re: Salts
Beantworten

Viele Leute benutzen solchen unsinn wie "password" als passwort, das steht sicher in einer Rainbowtable. "passwordxyz" aber nicht unbedingt. Gleichzeitig lässt sich mit einem Salt keinen Rückschluss darauf ziehen, welche User das gleiche Passwort gesetzt haben. Ansonsten würde ich, wenn ich versuchen würde eine Passwortdatenbank zu Klartext zu machen, mit genau den passwörtern anfangen, die mehrmals vorkommen, weil:
a) Die Wahrscheinlichkeit ist höher, dass es sich um einfache Passwörter handelt. (-> "password")
b) Ich bekomm mit einmal Arbeitsaufwand mehrere Accounts auf.

Würden Leute sichere, sich nicht wiederholende Passwörter verwenden (am Besten zufällig) erzeugt, dann würde der Salt keinen großen Vorteil bringen, ja. Die Realität sieht leider anders aus.

David Danier am 29.07.2008 um 18:02
Re: Salts
Beantworten

Nun das auch diese Methode nicht 100%ig sicher ist sollte klar allen klar sein. Jedoch kann man es dem Angreifer so erschwehren. Ein nicht erwähnter Vorteil von Salts ist auch das zwei gleiche Passwörter einen unterschiedlichen Hash ergeben und man so nicht nachvollziehen kann welche Benutzer dasselbe Passwort benutzen.

christian am 29.07.2008 um 15:43
Text verbessert + Verlinkung
Beantworten

Hab den Text mal massiv verbessert und teilweise richtiggestellt. Außerdem wurde der Artikel im PHP-Portal verlinkt (unter "PHP Sicherheit").

David Danier am 29.07.2008 um 14:01
Schöne Übersicht
Beantworten

Gelungener Einstiefsartikel in das Thema, welcher durch den allgemeinen Ansatz auch nicht Entwicklern wie mir einen Einblick in die Materie verschafft. Besten Dank.

Fabian Ziegler am 29.07.2008 um 09:42
Re: Schöne Übersicht
Beantworten

Jop genial.

JimBamir am 29.07.2008 um 11:58