kostenloser Webspace werbefrei: lima-city


MD5 und Salt

lima-cityForumProgrammiersprachenPHP, MySQL & .htaccess

  1. Autor dieses Themas

    misc

    misc hat kostenlosen Webspace.

    Hallo Lima-citizens

    Immer wieder liest man, dass der MD5-Hash nicht mehr sicher ist. Da MD5 aber immer noch relativ weit verbreitet ist, vor allem in PHP, bleibt fast nichts anderes übrig als diesen trotzdem zu verwenden oder auf einen fast gleich unsicheren SHA-Algorythmus zurückzugreifen.

    Im Internet habe ich gelesen, dass man ein sogenanntes "Salt" beim MD5-Hashen hinzufügen kann, um die Entschlüsselung zu erschweren (http://en.wikipedia.org/wiki/Key_strengthening).
    Nun, wie soll man jetzt so ein Salt wählen? Wäre es intelligent, als Salt den MD5-Hash des Passwortes zu verwenden?

    Also:
    $pass = $_POST["password"];
    $salt = md5($pass);
    $result = md5($salt.$pass);

    Wäre das sicher? Oder noch ein anderes Salt anhängen? Ich will es nur aus reinem Interesse wissen, mir ist klar dass niemand so viel Zeit verschwendet um an ein belangloses Passwort meiner (zukünftigen) Internetseite zu gelangen. Trotzdem ist es doch auch schön für die Users zu wissen, dass sich der Administrator um geeignete Sicherheitsmassnahmen kümmert.

    Vielen Dank für die Auskunft.
    misc
  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. Da mittlerweile Kollisionen mit MD5 möglich sind, ist die Verwendung von MD5 nicht mehr so sicher. Dann eher SHA-1.

    Einen Salt zu nutzen, macht schon Sinn. Aber wenn, dann gleich definitiv in keiner Hashtable zu finden:

    $hash = md5(md5($salt).md5($pass).md5($salt));


    Beitrag zuletzt geändert: 5.2.2011 0:22:14 von fabo
  4. Autor dieses Themas

    misc

    misc hat kostenlosen Webspace.

    Wow! Das ging ja super schnell. Aber kannst du mir erklären, warum zwei Salts die Sicherheit nochmal signifikant erhöhen sollten?
  5. Macht der Gewohnheit. Was ich damit sagen wollte ist, dass es sicherer ist, auch den Salt zu hashen, wobei du das ja prinzipiell schon tust. Aber wie gesagt... MD5 ist nicht mehr unbedingt sicher. Siehe http://eprint.iacr.org/2004/199.pdf
  6. Autor dieses Themas

    misc

    misc hat kostenlosen Webspace.

    Also das ist mir, glaube ich, etwas zu mathematisch. Da verstehe ich nur Bahnhof, ich könnte jetzt nicht einfach eine MD5-Kollision finden...
    Heisst das jetzt die können eine zweite Zeichenfolge errechnen die den selben Hash gibt? Und brauchen sie dazu das Ursprungspasswort?
    Irgendwie habe ich auch das Gefühl, nach dem Lesen des Dokuments, dass es dann schlussendlich nicht mehr draufankommt wie und wo man das Salt in den MD5 einberechnet. Hauptsache man hat mindestens eins.

    Beitrag zuletzt geändert: 5.2.2011 0:43:42 von misc
  7. Heisst das jetzt die können eine zweite Zeichenfolge errechnen die den selben Hash gibt?


    Richtig.

    Und brauchen sie dazu das Ursprungspasswort?


    Nein. Das ist ja das Problem.
  8. Gut, ich habe schon oft genug immer das selbe zu diesem Thema geschrieben, daher jetzt nur in Stichpunkten, ohne große Begründung:

    * Benutze md5 nicht, stattdessen nutze sha1 oder noch besser sha512
    * Der Salt muss für jeden User verschieden sein. Wenn du willst, kannst du einfach den Usernamen nutzen. Ein zufallsgenerierter Salt ist natürlich besser, da er bei Cross-Domain-Attacken deutlich mehr im Weg steht, aber wenn du dir die Mühe nicht machen willst, ist der Username genügend.
    * Du solltest deinen Key stretchen, d.h. mehrere Iterationen durchführen, um den Prozess zu verlangsamen.

    function pwHash($string, $salt, $runs = 100, $algorithm = 'sha512) {
        // some nice big salt
        $salt = hash($algorithm, $salt);
    
        // apply $algorithm $runs times for slowdown
        while ($runs--) {
            $string = hash($algorithm, $string . $salt, $raw);
        }
    
        return $string;
    }


    Beitrag zuletzt geändert: 5.2.2011 1:42:50 von nikic
  9. Autor dieses Themas

    misc

    misc hat kostenlosen Webspace.

    Ich hab mich schlau gemacht:

    fabo schrieb:
    Und brauchen sie dazu das Ursprungspasswort?


    Nein. Das ist ja das Problem.


    Falsch.
    Zitat: Wikipedia
    Kollisionen finden heißt, man sucht ein M (Text) und ein M' (Kollision), so dass hash(M) = hash(M'). Preimage-Angriff heißt, man sucht zu vorgegebenen M bzw. hash(M) ein M', so dass hash(M) = hash(M'). Da man beim Preimage-Angriff nur M' kontrolliert, nicht auch M, ist dieser viel schwieriger.

    Derzeit ist MD5 nur bezüglich der Kollisions-Angriffe geknackt. Deswegen besteht noch keine akute Gefahr für Passwörter, die als MD5-Hash gespeichert wurden, diese Kollisionen sind eher eine Gefahr für digitale Signaturen.


    -> Bisher sind nur Kollisionen geknackt, d.h. z.B. eine Datenbank voller Hashes ist noch nicht in Gefahr.
    Vielleicht erst den Link durchlesen bevor man den anderen mit mathematischen Formeln zubombt in der Annahme er werde dann schweigen.

    @nikic:
    Ich habe mich genügend darüber informiert, eigentlich wollte ich nur wissen ob ein Hash des Passwortes selber als Salt geeignet ist...

    Beitrag zuletzt geändert: 5.2.2011 1:57:11 von misc
  10. Vielleicht erst den Link durchlesen bevor man den anderen mit mathematischen Formeln zubombt in der Annahme er werde dann schweigen.


    Ich bin sogar zertifiziert dafür, Leute mit gewissen Dingen zuzubomben in der Hoffnung, sie würden dann schweigen.

    Bisher sind nur Kollisionen geknackt, d.h. z.B. eine Datenbank voller Hashes ist noch nicht in Gefahr


    Habe ich das in nur einem einzigen Buchstaben erwähnt? Ich glaube nicht.
  11. Autor dieses Themas

    misc

    misc hat kostenlosen Webspace.

    Jetzt wollen wir ja nicht in einen Flamewar kommen aber du hast gesagt man könne nur mit einem Hash ohne Ursprungspasswort eine Zeichenfolge herausfinden, die den gleichen Hash hat, was bis heute einfach und simpel unmöglich ist.

    Daraus lässt sich dann folgern dass MD5 dekodiert werden kann und so Passwörter herausgefunden werden. Eine Datenbank voller MD5 Passwörter wäre demnach in Gefahr.

    Aber eben, on Topic nochmal: macht es Sinn als Salt ein MD5 des Passwortes selber zu nehmen?

    Beitrag zuletzt geändert: 5.2.2011 2:51:43 von misc
  12. misc schrieb:
    Jetzt wollen wir ja nicht in einen Flamewar kommen aber du hast gesagt man könne nur mit einem Hash ohne Ursprungspasswort eine Zeichenfolge herausfinden, die den gleichen Hash hat, was bis heute einfach und simpel unmöglich ist.

    Du hast Wikipedia falsch verstanden. Man kann für einen Hash in vernachlässigbarer Zeit einen Ausgangstext finden, der diesen Hash besitzt, aber nicht zwangsweise dem Ursprungstext entspricht. Für Passwörter ist das aber uninteressant, da man ja nicht Zugriff zu deiner vollkommen unwichtigen, niemanden interessierenden Seite erlangen will, sondern versucht mit dem selben Passwort Zugriff zum Email-Konto, usw. zu erlangen.

    Und nein, der Hash des Passworts eignet sich nicht als Salt. Du hast scheinbar noch nicht wirklich verstanden wofür der Salt da ist: Er dient dazu, damit nicht eine Rainbow Table genutzt werden kann, um eine ganze Passwortdatenbank auszuhebeln. Wenn man nun aber den Hash des Passworts als Salt nimmt, dann gilt MD5(MD5(PW).PW) == MD5(MD5(PW).PW). So offensichtlich das jetzt auch klingen mag (was klar zeigt, das du absolut keine Ahnung von der Sache hast und daher fabo nicht selbiges unterstellen solltest!), sagt uns das, dass der Hash für das selbe Passwort immernoch gleich bleibt und somit eine Rainbow Table für die ganze Datenbank genutzt werden kann.

    Also, wie ihc oben bereits erwähnt habe, muss der Salt für jeden User verschieden sein und möglichst zufällig.
  13. Autor dieses Themas

    misc

    misc hat kostenlosen Webspace.

    Ich habe Wikipedia sehr wohl richtig verstanden. Eine Kollision zu finden bedeutet man sucht sowohl ein A wie ein B (beide frei wählbar) so dass md5(A) == md5(A). Das kann man heute.
    Ein Preimage-Angriff geht folgendermassen: Man hat A, bzw. md5(A) fix definiert und sucht dafür ein B so dass md5(A) == md5(B).

    Das geht nicht ohne Bruteforce, wie z.B. mit Rainbow Tables. Ein zufälliges Passwort das in keinem Duden vorkommt und in MD5 gehasht ist kann bis heute auf keine Art wieder herausgefunden werden, ausser mit purer Bruteforce.
    Das wird auch so bestätigt im ganzen Internet. Übrigens hat die Kollisionsfindung nichts mit Rainbowtables zu tun.

    Okay, ich sehe ein dass ein MD5 Hash im Salt rein gar nichts ändert. Danke für die Antwort.

    Ich hab mich jetzt noch weiter schlau darüber gemacht und werde jetzt den Usernamen als Salt verwenden, diesen dann aber in der Datenbank auch als MD5 speichern. So kommt ein potenzieller Hacker an zwei MD5 Hashes, mit denen er nichts anfangen kan.

    Beitrag zuletzt geändert: 5.2.2011 12:46:25 von misc
  14. Du bringst da ein paar Sachen durcheinander.

    Ziel einer Kollision ist ja, dass MD5(A) am Ende MD5(B) ergibt - Dies wiederrum ohne Bruteforce, sondern eben durch mathematische Berechnung.

    Das Ganze ist noch nicht so weit ausgearbeitet, dass es zu jedem Hash auch eine Kollision gibt, defakto ist ein mit MD5 gehashtes Passwort auch noch als sicher zu betrachten.

    Was ich dir sagte bzw. versucht habe zu vermitteln ist, dass es theoretisch keine Rolle spielt, ob dein gehashtes Passwort mit einem Salt in doppelter und dreifacher Ausführung versehen ist. Klar, man kommt nicht an den Klartext d.h. ein mit MD5 Passwort ist dahingehend so sicher, dass man nicht befürchten muss, dass irgendjemand mein Passwort rausfinden könnte, außer eben mit Bruteforce und/oder Hashtables. Aber das ist eben durch die Kollisionsgefahr nicht nötig, da MD5(A) eben auch MD5(B) ergeben KANN d.h. auch ohne das eigentliche Passwort zu kennen, könnte ich mir Zugriff auf den dazugehörigen Useraccount verschaffen, insofern es die Technik in absehbarer Zeit erlaubt.

    Beitrag zuletzt geändert: 5.2.2011 15:50:30 von fabo
  15. Ich verstehe die Aufregung gerade nicht. Oo

    Ich halte bisher folgendes Verfahren ausreichend sicher:
    - ein festdefinierten Salt S wird im PHP Script festgelegt
    - alle Passwörter werden in der Datenbank, wie folgt abgelegt: md5 (Passwort . Salt)

    - beim Login des Benutzers
    - PasswortLoginMD5 := md5 (PasswortDesLogin . Salt)
    - PasswortLoginMD5 == PasswortDatenbank => Passwort korrekt

    Wenn nun der Angreifer Lesezugriff auf die Datenbank hat, muss er den Salt herausfinden, um sich einloggen zu können.
    Der Angreifer kann zwar eine Kollision finden (md5(Kollision) == PasswortDatenbank), wenn er sich nun aber mit Kollision anmeldet, dann wird md5(Kollision.Salt) im Skript erzeugt und das ist wieder nicht gleich PasswortDatenbank

    Sollte der Angreifer nur Lesezugriff auf den PHP Code haben, hilft ihm das nichts.
    Sollte der Angreifer nur Lesezugriff auf die Datebnbank haben, hilft ihm das auch nicht.

    Der Salt sollte möglichst nicht im Duden stehen und einfach eine willkürliche Zeichenkette sein.
    Ich denke den Benutzernamen als Salt zu nehmen, ist eine gute Idee.
    Ob der Salt nochmals mit md5() verschlüsselt wird ist letztendlich aber relativ egal.

    So, jetzt bin ich auf euch gespannt. :)

    Gruß Lucas

    @fabo: Du bist nicht unfehlbar, vllt hat er sich nur falsch ausgedrückt oder du hast ihn falsch verstanden. Es würde der Diskussion mehr bringen, wenn du am Anfang deines Posts den Post von misc noch einmal mit eigenen Worten kurz zusammenfasst.
    Dann kann er wiederrum sehen, ob du verstanden hast, was er meinte.

    edit:

    Der Salt sollte möglichst nicht im Duden stehen und einfach eine willkürliche Zeichenkette sein.

    Angenommen der Benutzer hat als Passwort 1234 und dein Salt wäre 5678.
    Dann würde der Angreifer für md5 (1234.5678) sicherlich in einer Rainbowtabelle eine Kollision finden.

    Beitrag zuletzt geändert: 7.2.2011 17:04:18 von lucas9991
  16. Ich halte bisher folgendes Verfahren ausreichend sicher:
    - ein festdefinierten Salt S wird im PHP Script festgelegt
    - alle Passwörter werden in der Datenbank, wie folgt abgelegt: md5 (Passwort . Salt)

    - beim Login des Benutzers
    - PasswortLoginMD5 := md5 (PasswortDesLogin . Salt)
    - PasswortLoginMD5 == PasswortDatenbank => Passwort korrekt

    Wenn nun der Angreifer Lesezugriff auf die Datenbank hat, muss er den Salt herausfinden, um sich einloggen zu können.
    Der Angreifer kann zwar eine Kollision finden (md5(Kollision) == PasswortDatenbank), wenn er sich nun aber mit Kollision anmeldet, dann wird md5(Kollision.Salt) im Skript erzeugt und das ist wieder nicht gleich PasswortDatenbank

    So, ich versuche dann mal zu zeigen, warum dein aktuelles System nicht ausreichend ist.

    Fangen wir da an, wo wir ankommen wollen, bei den Zielen. Wofür ist dieses ganze rumgesalte überhaupt gut, was wollen wir damit erreichen?
    1. Wir wollen verhindern, dass eine Rainbow-Tabelle (eine Tabelle mit Hash => Ursprungstext Zuordnungen) genügt, um an alle Passwörter in allen Passwort-Datenbanken der Welt heranzukommen. Ein applikationsspezifischer Salt (diesen nutzt du) verhindert dies effektiv. Man kann nicht mehr eine Rainbow-Tabelle nutzen, um alle Passwörter der Welt herauszubekommen. Huh. super!
    2. Wir wollen verhindern, dass eine Rainbow-Tabelle genügt, um alle Passwörter in unserer Datenbank wiederherzustellen. Der Applikationsspezifische Hash wird hier kläglich versagen, denn er ist für alle User und Passwörter gleich. Eine Rainbow-Table für die ganze Datenbank ist bei der Geschwindigkeit moderner Computer wirklich kein Problem. Daher müssen wir nun einen userspezifischen Salt verwenden. Durch diesen muss für jeden Hash in der Datenbank eine Dictionary-Attacke durchgeführt werden. Okay, also, lasst uns etwas ganz userspezifisches nehmen, sagen wir mal den Username?
    3. Wir wollen verhindern, dass mehrere Rainbow-Tabellen genügen, um viele Passwörter reversieren zu können. Das Problem an der vorherigen Technik ist, dass viele Usernamen nunmal häufig vorkommen. Darunter fallen "admin", "root" genauso wie "peter" oder "peter1". Wenn man also mehrere Passwort-Datenbanken vorliegen hat, die den Username als Salt benutzen, dann kann man jeweils alle User mit dem Namen "peter" gleichzeitig angreifen und somit die Attacke ungemein optimieren. Was tut man dagegen? Man benutzt einen zufälligen Salt, der nichts mit dem Usernamen, seiner Id, Email oder sonstige zu tun hat.

    Ja, das ist ja alles schön und gut, aber es hat doch sowieso niemand Zugriff auf meinen PHP-Code. Es reicht doch, wenn der geheime Salt im PHP-Code steht und für alle gleich ist. Kennt doch niemand, ist sicher. Naja. Auf die Datenbank hast eigentlich auch nur du Zugriff ;) Wenn man die Datenbank übernehmen kann, dann ist PHP oder gar der ganze Server nicht weit ;) Was du betreibst ist Security By Obfuscation und wird nicht als Sicherheit anerkannt ;)

    So, gehen wir aber noch ein wenig weiter: Mit guten Salts zwingen wir den Angreifer dazu eine Dictionary-Attacke für jedes einzelne Passwort in der Datenbank durchzuführen. Das dauert doch ewig! Nein. Computer sind verdammt schnell. MD5 ist verdammt schnell. SHA1 ist verdammt schnell. Man kann Millionen von md5-Hashes pro Sekunde generieren [für diese Zahl habe ich keine Belege :P]. Daher setzt man mittlerweile gehäuft eine Technologie Namens Key Stretching ein. Dabei wird der Hash-Algorithmus nicht einmal angewandt, sonder hundert oder tausendfach. Dies erzeugt eine minimale und vernachlässigbare Verzögerung beim Login, aber verlangsamt die Attacke um hundert beziehungsweise tausend Mal! Wenn der Angreifer vorher eine Millionen Hashes pro Sekunde generiert hat, so sind es nun nurnoch Tausend.

    Noch Fragen?
  17. Juhu, endlich mal ein Thema mit etwas mehr Brisanz und nebenbei auch eines, welches diesem Forum enorm gut tut, bei so viel unsicherem Code, den ich mittlerweile schon gesehen habe.

    Aber kommen wir zum eigentlichen Thema, wie nikic schon sehr ausführlich aufgezeigt hat, gibt es vor allem 3 Punkte an denen unsere Passwort-Hashes angreifbar sind, das wäre kurz zusammengefasst:
    • wir wollen die Passwörter Anwendungsabhängig speichern
    • wir wollen die Passwörter nicht mit den selben Kriterien (salt) generieren, um unsere eigene DB zu schützen
    • wir wollen die Passwörter unabhängig von denen der anderen User speichern

    Desweiteren gibt es aber auch noch den Weg bis das Passwort auf dem Server landet, welcher viel leichter auszuspähen wäre und genau da greift meine Methode ein, da sie das Passwort schon vor der Übertragung individualisiert, auch wenn dazu Javascript nötig ist, aber auf diese Weise erhält man eine relativ sichere Übertragung.
    Um das ganze mal an einem Beispiel fest zu machen will ich hier kurz einen kleinen JS-Broken einwerfen, an dem man sieht, wie ich das Passwort verschlüssele.
    // der salt wir bei jedem Seitenzugriff individuell erzeugt,
    // hier ist es entsprechend nur ein Beispiel
    var salt = '0@=xj_KFh"!An\'Z';
    
    // dieser salt wurde ebenfalls dynamisch erzeugt,
    // allerdings nur einmalig beim ersten aufruff des systems
    var pw_salt = 'xd.r^mNRZw?WCiA';
    
    $('login').onsubmit = function() {
        $('password').value = md5(
            sha1( $('password').value + $('username').value + pw_salt ) + salt
        );
    };


    Wie man sehen kann setzte ich lediglich den 3. Punkt aus nikic`s Auflistung nicht konsequent um, das liegt allerdings daran, das es nur wenige Merkmale gibt, die man sinnvoll dazu einsetzen kann.

    Mit freundlichen Grüßen
  18. nikic schrieb:
    [...]


    zu 1:
    Stimme ich dir voll zu.

    zu 2:
    Idee finde ich gut, habe ich bisher noch nicht genutzt, stimme ich dir aber voll zu.
    Ergänzungen meinerseits:
    Man sollte einen Benutzerspezifischen Eintrag nutzen, der:
    - entweder konstant ist und sich nicht mehr verändert, z.B. die ID
    - oder relativ konstant ist und bei Veränderung mit dem Benutzerpasswort bestätigt werden muss

    zu 3:
    Stimme ich dir voll zu.

    zu 4 "Key Stretching":
    Stimme ich dir auch zu, allerdings halte ich mehr als hundertfaches Verschlüsseln für durchschnittliche Websites zu viel.

    Ich sehe weiterhin eine theoretische Gefahr, die ich allerdings nicht beurteilen kann.
    Kann es passieren, dass sich durch n viele Verschlüsselungsschritte, die Schlüssel mit jedem Schritt immer ähnlicher werden?
    Die Verschlüsselungen md5 hat Kollisionen, deshalb müsste theoretisch nach unendlich vielen Schritten zum Schluss sehr ähnliche Schlüssel heruaskommen.
    Beispiel:
    1) aaa -> aab -> ... -> baa (Kollision) -> aab
    2) bbb -> bab -> ... -> aaa (Kollision) -> aab

    Bezgl. "Security By Obfuscation":
    Wenn jemand in die Datenbank einer Website eindringt, sollte es nicht möglich sein von da aus irgendwie die PHP Scripte so zu manipulieren, dass sie sich selbst verändern.
    Wie gesagt, sollte.
    Wenn der Lesezugriff möglich ist, dann ist auch der Schreibzugriff meist nicht fern und dann kann man sich - überspitzt gesagt - die Verschlüsselung fast sparen. ;-)

    Gruß Lucas
  19. Ich sehe weiterhin eine theoretische Gefahr, die ich allerdings nicht beurteilen kann.
    Kann es passieren, dass sich durch n viele Verschlüsselungsschritte, die Schlüssel mit jedem Schritt immer ähnlicher werden?
    Die Verschlüsselungen md5 hat Kollisionen, deshalb müsste theoretisch nach unendlich vielen Schritten zum Schluss sehr ähnliche Schlüssel heruaskommen.
    Beispiel:
    1) aaa -> aab -> ... -> baa (Kollision) -> aab
    2) bbb -> bab -> ... -> aaa (Kollision) -> aab

    Ja, diese Gefahr besteht. Du musst aber bedenken, dass die Anzahl der Kollisionen nur linear zunimmt. Und da die Wahrscheinlichkeit von Kollisionen bei Hashalgorithmen sehr gering ist, so ist dies auch bei hunderttausend Iterationen noch kein Problem. Dennoch kann es sinnvoll sein dem entgegenzuwirken, indem man den Salt bei jeder Iteration anhängt, nicht nur ganz am Anfang.

    Das tue ich auch in dem Snippet, das ich unten gepostet habe:
    function pwHash($string, $salt, $runs = 100, $algorithm = 'sha512) {
        // some nice big salt
        $salt = hash($algorithm, $salt);
    
        // apply $algorithm $runs times for slowdown
        while ($runs--) {
            $string = hash($algorithm, $string . $salt, $raw);
        }
    
        return $string;
    }


    Beitrag zuletzt geändert: 9.2.2011 15:33:34 von nikic
  20. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!