Verschlüsselung von Passwörtern
Anonymus
- php
Hallo,
ich will das Passwort welches der User eingibt verschlüsselt abspeichern.
Nun ist meine Überlegung, wie ich das machen sollte.
Wenn ich bei Google danach suche kommen vorallem Beiträge von 2002-2004. Da sich empfohlene Verschlüsselungen aber relativ schnell ändern wollte ich nachfragen, was aktuell Stand der Dinge ist.
In den meisten älteren Beiträgen finde ich folgende Lösung:
$passwort = md5($password);
Dann habe ich gelesen, dass sha2 verwendet werden soll. Eine Funktion wie md5 habe ich dafür leider nicht gefunden als ich gegoogelt habe. Aber ein längeres Script, dass ich mir einbauen könnte.
Außerdem wurde empfohlen, dass Passwort mit "Salt" zu stärken.
Was heißt das genau? Dass man irgend wo im Quellcode eine Konstante im Klartext festgelegt hat, die dann vorm Verschlüsseln an das Passwort angehängt wird?
$passwort = md5($password . $SALT_KONSTANTE);
Würde mich freuen, wenn ihr mir die Verschlüsselungs-Technik erklärt, die man heut zu Tage verwenden soll.
Vielen Dank
Was bedeutet verschlüsseln für dich in diesem Zusammenhang?
Mit einem Hash kannst du nur feststellen ob ein gegebenes Passwort wieder den Hash erzeugt. Du kannst damit rausfinden ob ein eingegebenes Passwort richtig ist. Du kannst aber nicht das Passwort wieder herstellen.
Verschlüsseln bedeutet aber eher dass du was versteckst und dann wieder rekonstruieren kannst.
Außerdem wurde empfohlen, dass Passwort mit "Salt" zu stärken.
Was heißt das genau? Dass man irgend wo im Quellcode eine Konstante im Klartext festgelegt hat, die dann vorm Verschlüsseln an das Passwort angehängt wird?
$passwort = md5($password . $SALT_KONSTANTE);
Ja so ähnlich jedenfalls. Angehängt, vorangestellt... Die Konstante muss nicht unbedingt im Programm fest sein, die kann auch für jedes Passwort verschieden sein und muss dann natürlich zu jedem Passwort extra gespeichert werden.
Würde mich freuen, wenn ihr mir die Verschlüsselungs-Technik erklärt, die man heut zu Tage verwenden soll.
Die Technik an sich bleibt die gleiche. Du hast ja schon die richtige Richtung, zum Beispiel eben Passwörter als Hash speichern. Was sich ändert sind die Verfahren zum Berechnen des Hashs, z.B. md5 und sha2. Was da grad als sicher angenommen wird weiß ich nicht, aber das kriegst du in Google bestimmt schnell raus.
Hi,
ich will das Passwort welches der User eingibt verschlüsselt abspeichern.
Das halte ich für nicht richtig. Denn damit wäre es möglich, aus dem gespeicherten Wert wieder zum Originalpaßwort zu kommen.
Es sollte eher ein Hash verwendet werden.
$passwort = md5($password);
Das ist keine Verschlüsselung, sondern ein Hash.
Du solltest Dich erstmal entscheiden, ob Du wirklich eine Verschlüsselung oder einen Hash haben willst.
cu,
Andreas
Hallo,
ja ich meine hashen, nicht verschlüsseln. Tut mir leid.
Habe folgenden Funktionsaufruf gefunden:
hash('sha512',$salt . $message);
werde wohl diese Funktion auch nutzen.
Ich glaube, irgend wo habe ich gelsen, dass der Hashwert bei sha2 länger ist als das Wort was man verschlüsselt - natürlich das Wort mit dem salt schon drin.
Nun wollte ich wissen, wie groß die Wörter werden, damit ich dem Benutzer sagen kann, ab wann das Passwort zu lang ist (da eingestellte Speichergröße auf Datenbank zu klein).
Danke
Hallo,
Nun wollte ich wissen, wie groß die Wörter werden, damit ich dem Benutzer sagen kann, ab wann das Passwort zu lang ist (da eingestellte Speichergröße auf Datenbank zu klein).
Das Passwort kann so lang sein wie der Benutzer möchte - der Hash ist immer gleich lang, egal wie lang das Passwort ist.
Gruß,
Tobias
Hi!
Ich glaube, irgend wo habe ich gelsen, dass der Hashwert bei sha2 länger ist als das Wort was man verschlüsselt - natürlich das Wort mit dem salt schon drin.
Nein. Hashwerte, die mit dem selben Algorithmus erzeugt wurden, haben üblicherweise die gleiche Länge, unabhängig von ihrem Inhalt. Der kann natürlich kürzer oder auch länger als die x Bytes des Hash-Wertes sein.
Nun wollte ich wissen, wie groß die Wörter werden, damit ich dem Benutzer sagen kann, ab wann das Passwort zu lang ist (da eingestellte Speichergröße auf Datenbank zu klein).
Du must lediglich herausfinden, wie groß der Hash beziehungsweise seine Darstellung (üblicherweise stellt man ihn ja als Hexzeichenfolge dar) ist. Die Passwort-Länge mit oder ohne Salt spielt keine Rolle.
Lo!
Habe folgenden Funktionsaufruf gefunden:
hash('sha512',$salt . $message);
Unten schrieb Encoder dass du das Salz auch in die Datenbank schreiben kannst, eigentlich solltest du das sogar tun, weil der Sicherheitseffekt sonst nur marginal ist.
Diese Art des "salt" dient dazu Angriffe mit Regenbogentabellen zu erschweren. Regenbogentabellen sind Tabellen in denen bereits viele Hashes vorberechnet sind und die man entsprechend durchsuchen kann.
Nun das Szenario:
Der Angriff gegen den du dich mit Passwort-Hashing schützt ist ja, dass deine Datenbank verloren gehen könnte.
Also angenommen deine DB gerät in falsche Hände, die PWs hast du nicht verschlüsselt. Das ist schlecht der Angreifer hat sofort alle Passwörter.
Also hast du deine PWs vorher gehashed...
Der Angreife bekommt also alle PW-Hashes und dursucht seine Regenbogentabelle nach den Hashes, die du in deiner DB hast. Typischerweise haben manche User natürlich "god" oder "password" oder "123456" oder "dfghjkl" verwendet, die werden leicht gefunden, weil sie natürlich in jeder RT drin stehen.
Genau das wollen wir erschweren und fügen ein fest codiertes Salz dem Passwort hinzu. Sagen wir dein Salz ist "1".
Jetzt braucht der Angreifer eine umfangreiche Regenbogentabelle, denn die üblichen PWs (Wörterbuchangriff) funktionieren nicht mehr. Aber auf der umfangreichen Tabelle findet er "password1" und er errät, dein Salz, besorgt sich die passende Tabelle für PWs, die auf 1 enden (1234561 god1 etc...) und knackt wieder Unmengen von PWs.
Um dieses Szenario zu erschweren erstellst du für jedes einzelne PW eigenes, zufälliges Salz und speicherst es im Klartext direkt neben das gehashte Passwort.
Klingt ein bisschen absurd, denn der Angreifer hat ja die DatenBank und kann das Salz mit abgreifen. Aber der Angriff mit dünnen Regenbogentabellen funktioniert nicht mehr. Der Angreifer muss zunächst eine Tabelle verwenden, in denen "alle" (alle geht nicht) Hashes stehen, die irgendeines deiner Salze enthalten. Mal angenommen er knackt damit eines der Konten, dann hilft ihm das gar nichts, außer dass er dieses eine Salt aus seiner Tabelle rausschmeißen kann, er ist keinen Schritt weiter und muss weiter auf einer gigantischen Tabelle suchen, die eben hoffentlich nicht ausgerechnet die Kombinationen PW+Salt enthält.
Wie du das Salz erzeugst ist bei der ganzen Sache fast egal (es sollte sich nicht [oft] wiederholen), im Grunde sind sogar vorhersehbare Methoden relativ unkritisch also z.B.
hash('sha512',md5($benutzername) . $passwort);
Den Wert musst du nämlich nicht extra in die DB speichern :D (ist dafür öffentlich) Der Angreifer kann also theoretisch vor seinem Angriff schon Regenbogentabellen erstellen, aber ob er das vorher oder nachher macht... pffft Hauptsache sie wird unökonomisch groß.
Wie du das Salz erzeugst ist bei der ganzen Sache fast egal (es sollte sich nicht [oft] wiederholen), im Grunde sind sogar vorhersehbare Methoden relativ unkritisch also z.B.
hash('sha512',md5($benutzername) . $passwort);
Den Wert musst du nämlich nicht extra in die DB speichern :D (ist dafür öffentlich) Der Angreifer kann also theoretisch vor seinem Angriff schon Regenbogentabellen erstellen, aber ob er das vorher oder nachher macht... pffft Hauptsache sie wird unökonomisch groß.
Man darf nur einen Fehler nicht machen: einen kurzen Salt-Wert verwenden.
Annahme das Passwort ist "12345" und der Salt-Wert ist "foo" - dann ist die Kombination (bei einer einfachen Verkettung) 12345foo und so ein Wert wird ziemlich sicher in einer Rainbow-Table "aller" 8-stelligen Passwörter drin stehen.
Das Stichwort ist Entropie - der "Informationsgehalt" des Salt-Wertes muss so groß sein, das er ein verwenden einer Standard-Rainbow-Table unmöglich macht.
Das Paradoxe ist, dass selbst das Hashen eines einzelnen Buchstabens mit einem Hash-Algorithmus wie MD5 dessen Entropie erhöht obwohl die Information eigentliche dieselbe ist. Aber anstatt 8 Bit hat man nun 128 Bit mit denen man hantieren muss.
Eine weitere Möglichkeit ist es auch einfach einen Hash nochmal zu hashen - das macht ein einzelnes schlechtes Passwort aber auch nicht sicherer.
Man darf nur einen Fehler nicht machen: einen kurzen Salt-Wert verwenden.
richtig, das geht Hand in Hand mit "nicht wiederholen". Denn wenn man als Salt eine Zufallsziffer (0-9) nimmt hat man in seiner Userdatenbank eine Menge Wiederholungen ^^
Annahme das Passwort ist "12345" und der Salt-Wert ist "foo" - dann ist die Kombination (bei einer einfachen Verkettung) 12345foo und so ein Wert wird ziemlich sicher in einer Rainbow-Table "aller" 8-stelligen Passwörter drin stehen.
Oben habe ich behauptet "alle geht nicht", aber
ich habe gerade überlegt ob bei acht Zeichen wenn man Sonderzeichen mal weg lässt kommt man ohne Wörterbuch auf rund ((26+26+10)^8 =) 2,2*10^14 mögliche Zeichenfolgen. Ich denke dass das ein Index ist, der noch im Rahmen des verkraftbaren und durchsuchbaren liegt.
f12o34o5 wäre also wohl genauso schlecht
Das Paradoxe ist, dass selbst das Hashen eines einzelnen Buchstabens mit einem Hash-Algorithmus wie MD5 dessen Entropie erhöht obwohl die Information eigentliche dieselbe ist. Aber anstatt 8 Bit hat man nun 128 Bit mit denen man hantieren muss.
Ja... jain äääh naja. Also wenn der Algorithmus bekannt ist und er sollte ja bekannt sein (keine Security by Obscurity) dann ist die Menge der möglichen hashes für einzelne Buchstaben ja recht begrenzt und oben schrieb ich ja dass sie sich nicht wiederholen mögen.
Ein Angreifer könnte also "einfach" (naja *räusper*) eine Tabelle nehmen/erstellen, in der der bekannte Salzgehalt vorhanden ist.
theoretisch sind Hashes tatsächlich nicht sooo gut geeignet als Salz, weil die Menge ihrer unterschiedlichen Zeichen typischerweise bei 16 liegt.
Aber lieber 16 hoch (Länge eines Hashwertes als String) als 62 hoch 1 :D
Eine weitere Möglichkeit ist es auch einfach einen Hash nochmal zu hashen - das macht ein einzelnes schlechtes Passwort aber auch nicht sicherer.
Du meinst etwa so:
hash('sha512',md5($passwort).$passwort;
?
Ja, warum nicht? ^^ wobei... auch da ist die Tabelle relativ leicht zu erstellen (wenngleich dennoch groß), weil die Beziehung welches PW zu welchem Salz gehört bekannt ist. Bei dem was ich vorher vorschlug, nämlich den Usernamen zu nehmen ist diese Beziehung nicht bekannt, man kennt zwar den Usernamen und dessen Hashwert, muss aber alle Usernamen-Hashes mit allen Wörterbuch-PWs kombinieren. Andernfalls würde man alle Wörterbuch-PW-Hashes mit sich selbst (nicht mit allen!) kombinieren, was eine viel kleinere Tabelle ergibt.
Kurz: Wir denken binär und haben zwei PW-Stellen. Mein Hash XORt mit 1.
mögliche PWs:
00
01
10
11
4 Stück
mögliche PWs mit Hash des PW:
PW Hs
00 11
01 10
10 01
11 00
4 Stück
mögliche PWs mit Hash des einstelligen Usernamens:
PW Hs
00 0
00 1
01 0
01 1
10 0
10 1
11 0
11 1
8 Stück... weil ich eben nicht weiß welcher Username zu welchem PW gehört (bei einstelligen binären Benutzernamen ist die Anzahl der User allerdings auch so scheißklein, dass man das Projekt aufgeben sollte :D)
Die Beziehung zwischen Account und Salt darf bekannt sein, die Beziehung zwischen PW (unabhängig davon für welchen Account) und Salt möge unbekannt sein.
danke für die gute Erklärung
Vorallem über die Tatsache, dass der Angreifer auch die salt-Werte aus der Datenbank hat, wenn ihm das Eindringen gelungen ist, hab ich länger gegrübelt, warum es dann dennoch Sinn macht.
Aber nun ist es mir klar.
Danke
Vorallem über die Tatsache, dass der Angreifer auch die salt-Werte aus der Datenbank hat, wenn ihm das Eindringen gelungen ist, hab ich länger gegrübelt, warum es dann dennoch Sinn macht.
Um es nochmal zusammenzufassen, für andere die nicht lange nachgrübeln:
Ein Salt ist lediglich dazu da, das Attackieren von vielen Passwörtern unrentabel zu machen - ein einzelnes schlechtes Passwört schützt ein Salt-Algorithmus nicht effektiv genug.