Simon: Vorteile ein Passwort mit "Salt" zu speichern

Hi,

hab gerade das erste mal bei einem Script gesehen dass das Passwort welches sich in einer DB befindet nicht einfach mit dem eingegeben verglichen wird, sondern, dass vorher der "Salt" (Ein Hash ?) angehängt wird und dann verglichen wird. Das Passwort ist auch so in der DB gespeichert:

also: md5($pass.$salt).

Hat das irgendwelche Vorteile??

MfG
Simon

  1. hab gerade das erste mal bei einem Script gesehen dass das Passwort welches sich in einer DB befindet nicht einfach mit dem eingegeben verglichen wird, sondern, dass vorher der "Salt" (Ein Hash ?) angehängt wird und dann verglichen wird. Das Passwort ist auch so in der DB gespeichert:

    also: md5($pass.$salt).

    Hat das irgendwelche Vorteile??

    Durch Kenntnis des Hashes und Nutzung einer Brute-Force- oder Rainbow-Table erhältst du durch eine Kollision kein gültiges Passwort mit dem du dich einloggen kannst.

    Du musst für jeden Hash eine eigene Tabelle berechnen sofern der Salt je Datensatz unterschiedlich ist - ansonsten erhältst du dadurch keinen weiteren Vorteil.

    Das A und O:
    Verwende als Salt eine zufällige Zeichenkette die je Passwort zusätzlich im Datensatz gespeichert wird.

    1. Nachtrag: noch sicher ist es, zwei Salt-Komponenten zu verwenden. Ein Salt wird mit dem Passwort (unterschiedlich je Datensatz) in die Datenbank gespeichert, der zweite Teil ist statisch und liegt irgendwo auf der Platte.

      Kryptographisch ist das zwar nicht sicherer, aber wenn nur nur die Datenbank mit den Passwörtern flöten geht (was ja anscheinend sehr oft passiert) erschwert das das herrausfinden des Salts enorm und verzögert das errechnen noch ein Stück weiter.

      Wenn jemand ein Passwort wirklich will, ist das aber ebenfalls kein Schutz - es ist lediglich bei der Massenverarbeitung ein Grund, dass das Vorhaben unrentabel machen könnte.

      1. Ok, perfekt Danke
        MfG
        Simon

    2. Hi suit.

      Durch Kenntnis des Hashes und Nutzung einer Brute-Force- oder Rainbow-Table erhältst du durch eine Kollision kein gültiges Passwort mit dem du dich einloggen kannst.

      Wenn das Passwort einfach mit dem Salt konkateniert wird, dann erhaeltst Du eben einen String, von dem das Passwort ein Teilstring ist. Das ist nun wirklich nicht erheblich besser.

      Du musst für jeden Hash eine eigene Tabelle berechnen sofern der Salt je Datensatz unterschiedlich ist

      Bzw - wenn der Salt nicht bekannt ist, dann ist die notwendige Rainbowtabelle eben erheblich groesser, weil der verschluesselte Wert schlicht und einfach laenger ist.

      ansonsten erhältst du dadurch keinen weiteren Vorteil.

      Je nach Umgebung liefert der Salt noch einen ganz entscheidenden Vorteil: Er entschaerft das Problem, dass Passwoerter von vielen Leuten scheisse gewaehlt werden, z.B. als Vornamen oder Woerter aus dem Woerterbuch. Wenn die ohne Salt verschluesselt werden, braucht ne darauf ausgelegte Rainbow-Attacke heutzutage u.U. nicht laenger als ein paar Sekunden, um sie zu knacken.

      Viele Gruesse,
      der Bademeister

      1. Hi suit.

        Durch Kenntnis des Hashes und Nutzung einer Brute-Force- oder Rainbow-Table erhältst du durch eine Kollision kein gültiges Passwort mit dem du dich einloggen kannst.

        Wenn das Passwort einfach mit dem Salt konkateniert wird, dann erhaeltst Du eben einen String, von dem das Passwort ein Teilstring ist. Das ist nun wirklich nicht erheblich besser.

        Sicher ist das besser - durch die breitere Entropie kann man mit einer Kolision nichts mehr anfangen.

        angenommen das Passwort ist foobar und dein Salt 123456 der Hash ist 1a2b3c4d

        Dir ist der Hash und der Klartext bekannt.

        Wenn du über deinen Angriff nun "bröckerlhusten" und "1234567890" als mögliche Klartext erhältst, kannst du dich mit diesen Phrasen nicht einloggen. Erst wenn du dediziert einen Klartext findest, der den Salt in der Verwendeten Form beinhaltet (also z.B. "123456foobar") kannst du unter Kenntnis des Salts das echte Passwort herrausfinden und dich einloggen.

        Ohne Salt würdest du dich mit jeder Kollision einloggen können, ohne des Klartextpasswort zu kennen.

        Beim Massenknacken von Passwörtern ist ein Salt hinterlich und erschwert das Vorhaben - beim gezielten Knacken eines einzelnen Passworts hingegen erleichtert ein Salt hingegen paradoxerweise das Auffinden des echten Passworts.

        Bzw - wenn der Salt nicht bekannt ist, dann ist die notwendige Rainbowtabelle eben erheblich groesser, weil der verschluesselte Wert schlicht und einfach laenger ist.

        Nicht notwendigerweise - bei einer Rainbow-Table reicht es, die Ketten länger zu machen. Die Tabelle wird dadurch kein gramm größer, sofern sich die Stringlänge in der Kette nicht ändert.

        Je nach Umgebung liefert der Salt noch einen ganz entscheidenden Vorteil: Er entschaerft das Problem, dass Passwoerter von vielen Leuten scheisse gewaehlt werden, z.B. als Vornamen oder Woerter aus dem Woerterbuch. Wenn die ohne Salt verschluesselt werden, braucht ne darauf ausgelegte Rainbow-Attacke heutzutage u.U. nicht laenger als ein paar Sekunden, um sie zu knacken.

        Siehe oben - das ist ansich kein Vorteil sondern ein entscheidender Nachteil von Salts bei dämlichen Passwörtern :)

        1. Sicher ist das besser - durch die breitere Entropie kann man mit einer Kolision nichts mehr anfangen.

          Ah ok, jetzt hab auch ich begriffen, was Du meinst. Grundsaetzlich Zustimmung - allerdings sollten(!) Kollisionen grundsaetzlich kein zu hoch zu bewertendes Sicherheitsproblem sein - wenn sie es doch sind, ist die benutzte Hash-Funktion schlecht gewaehlt.

          Bzw - wenn der Salt nicht bekannt ist, dann ist die notwendige Rainbowtabelle eben erheblich groesser, weil der verschluesselte Wert schlicht und einfach laenger ist.

          Nicht notwendigerweise - bei einer Rainbow-Table reicht es, die Ketten länger zu machen. Die Tabelle wird dadurch kein gramm größer, sofern sich die Stringlänge in der Kette nicht ändert.

          Grmpf :-)

          Wenn Du etwa einen 8-Byte-Salt anhaengst und die Rainbow-Tabelle "gleich gross" (im Sinne von Speicherbedarf) sein soll, dann muss jede Kette um den Faktor 2^16 verlaengert werden, um die gleiche Trefferwahrscheinlichkeit beim Abgleich mit einem einzelnen Passwort zu haben. Das macht schon einen kleinen Unterschied.

          Unter der Groesse einer Rainbow-Tabelle verstand (und verstehe) ich die Anzahl der anhand ihr auffindbaren Passwoerter. Alles andere ist doch unsinnig als Mass. Wie gross der Speicherbedarf beim Angreifer fuer seine Rainbow-Tabellen ist, ist doch wirklich sein Problem :-)

          Siehe oben - das ist ansich kein Vorteil sondern ein entscheidender Nachteil von Salts bei dämlichen Passwörtern :)

          Du bist irgendwie sehr viel weniger gelassen als ich in Bezug auf Kollisionen. Da musste ma lockerer werden ;-)

          Viele Gruesse,
          der Bademeister

          1. Ah ok, jetzt hab auch ich begriffen, was Du meinst. Grundsaetzlich Zustimmung - allerdings sollten(!) Kollisionen grundsaetzlich kein zu hoch zu bewertendes Sicherheitsproblem sein - wenn sie es doch sind, ist die benutzte Hash-Funktion schlecht gewaehlt.

            Jein - wenn die Kollisionen absichtlich erzeugt werden können (Preimage) ist es ein Problem, wenn die Kollisionen zufällig entstehen lässt sich das aber nicht vermeiden.

            Bei einer Kollision ist zwar das Passwort sicher, das Login selbst aber nicht - das kann auch ein Sicherheitsproblem sein, wenn z.B. das Ziel des Angriffs das geschütze System nicht aber das Passwort ist.

            Wenn Du etwa einen 8-Byte-Salt anhaengst und die Rainbow-Tabelle "gleich gross" (im Sinne von Speicherbedarf) sein soll, dann muss jede Kette um den Faktor 2^16 verlaengert werden, um die gleiche Trefferwahrscheinlichkeit beim Abgleich mit einem einzelnen Passwort zu haben. Das macht schon einen kleinen Unterschied.

            Natürlich :) darum schrieb ich "nicht notwendigerweise".

            Unter der Groesse einer Rainbow-Tabelle verstand (und verstehe) ich die Anzahl der anhand ihr auffindbaren Passwoerter.

            Verstanden.

            Alles andere ist doch unsinnig als Mass. Wie gross der Speicherbedarf beim Angreifer fuer seine Rainbow-Tabellen ist, ist doch wirklich sein Problem :-)

            Ja, genau das ist ja eines der Probleme von Wörterbüchern oder Vorberechneten Hash -> Klartexttabellen. Der Speicherplatz. Der einzige Sinn eine Rainbow-Table ist es, den Speicherplatz klein zu halten oder bei derselben Größe mehr potentielle Klartexte abzudecken.

            Du bist irgendwie sehr viel weniger gelassen als ich in Bezug auf Kollisionen. Da musste ma lockerer werden ;-)

            Schon klar, dass Kollisionen recht unwahrscheinlich sind, aber je länger die Zeichenketten werden, desto wahrscheinlicher ist, dass es Kollisionen mit ähnlicher länge gibt.

            Dass ein 8-stelliges Passwort mit einem anderen 8-stelligen String kollidiert ist sehr unwahrscheinlich, dass eine 64-Byte-Zeichenwurst mit einer anderen 64-Byte-Zeichenwurst kolidiert ist bei einem 32-bit-Hash schon sehr wahrscheinlich.

            1. Dass ein 8-stelliges Passwort mit einem anderen 8-stelligen String kollidiert ist sehr unwahrscheinlich, dass eine 64-Byte-Zeichenwurst mit einer anderen 64-Byte-Zeichenwurst kolidiert ist bei einem 32-bit-Hash schon sehr wahrscheinlich.

              Nein. Die Wahrscheinlichkeit einer Kollision von zwei (festen) 64-Byte-Zeichenwuersten[TM] ist genau so hoch wie die zweier 8-Byte Strings. Die Gefahr von Kollisionen wird nur dann gross, wenn die Menge(!) der infrage kommenden (bzw. vom Angreifer geprueften) Passwoerter gross im Vergleich zur Laenge der Hashs ist.

              Etwa im Woerterbuchmodell:
              Um ein Passwort zu knacken, das im Woertrbuch steht (sofern der Angreifer das vermutet) und ohne Salt gehasht ist, tuts ne normale Hash-Tabelle, ca. 100.000 Eintraege (ueber den Daumen), da braucht man nicht mal ne echte Rainbow-Tabelle.

              Wenn Du nun nen Salt hinten dran haengst, sagen wir 16 Byte, dann ist die Angreifbarkeit anhand der Woerterbuch-Sache entschaerft. Und zwar nicht nur, weil die Rainbow-Tabelle ohnehin erheblich groesser wird, sondern es ist auch kaum noch moeglich, die Woerterbuch-Sache fuer sich zu nutzen, weil eine vernuenftige Invertierungsfunktion (zum Berechnen der Ketten), die auf den Raum der Woerter mit einem Praefix aus dem Woertbuch beschraenkt ist, wohl kaum zu konstruieren ist (schaetze ich mal (?)).

              Auf der anderen Seite - wenn man es doch hinbekommen wuerde, dafuer ne vernuenftige Rainbow-Tabelle zu berechnen: Die Menge der Klartexte ist dann ca. 100.000 * 2^128, also ca. 2^142 oder so. Nehme ich einen SHA-2-Hash mit 256 bit, dann gibt es also ca. 2^114 mal so viele Hashs wie potentielle Passwoerter. Kollisionen gibt es also eventuell keine einzige, jedenfalls nur sehr wenige (obwohl man die Wahrscheinlichkeit von Kollisionen auch nicht unterschaetzen darf).

              Meine Meinung ist also: Der Gefahr von Kollisionen sollte mit der richtigen Hash-Funktion entgegengewirkt werden (auch wenn man sie natuerlich damit nicht ausschliessen kann).

              Viele Gruesse,
              der Bademeister

              1. Dass ein 8-stelliges Passwort mit einem anderen 8-stelligen String kollidiert ist sehr unwahrscheinlich, dass eine 64-Byte-Zeichenwurst mit einer anderen 64-Byte-Zeichenwurst kolidiert ist bei einem 32-bit-Hash schon sehr wahrscheinlich.

                Nein. Die Wahrscheinlichkeit einer Kollision von zwei (festen) 64-Byte-Zeichenwuersten[TM] ist genau so hoch wie die zweier 8-Byte Strings. Die Gefahr von Kollisionen wird nur dann gross, wenn die Menge(!) der infrage kommenden (bzw. vom Angreifer geprueften) Passwoerter gross im Vergleich zur Laenge der Hashs ist.

                Erwischt - Erklärungsfehler :) Ich wollte eigentlich sagen, dass die Menge der 8-stelligen Passwörter mit einem definierten Zeichenvorrat kleiner ist als die Menge der 64-stelligen Passwörter mit einem definierten Zeichenvorrat und die Wahrscheinlichkeit einer Kollision über die gesamte Menge der jeweiligen Passwörter beim Erstellen einer vollständigen Tabelle aller Klartexte -> Hashes größert ist.

                Wenn man jeweils nur zwei Passwörter hat, ist die Wahrscheinlichkeit einer Kollision gleich groß (wenn man Faktoren wie die Maximallänge der Eingabezeichenkette nicht beachtet).

                weil eine vernuenftige Invertierungsfunktion (zum Berechnen der Ketten), die auf den Raum der Woerter mit einem Praefix aus dem Woertbuch beschraenkt ist, wohl kaum zu konstruieren ist (schaetze ich mal (?)).

                Das halte ich für ein Gerücht :) Es ist keine Hexerei die Reduktionsfunkion so zu schreiben, dass sie an das neue Passwort in der Kette einfach wieder den Salt in definierter Form anhängt.

                klartext+salt -> hash(0) -> reduktion(0)+salt -> hash(1) ...

                Wenn der Salt hingegen geheim ist, ist man ohnehin "aufgeschmissen" und benötigt etwas mehr Zeit.

                Auf der anderen Seite - wenn man es doch hinbekommen wuerde, dafuer ne vernuenftige Rainbow-Tabelle zu berechnen: Die Menge der Klartexte ist dann ca. 100.000 * 2^128, also ca. 2^142 oder so. Nehme ich einen SHA-2-Hash mit 256 bit, dann gibt es also ca. 2^114 mal so viele Hashs wie potentielle Passwoerter. Kollisionen gibt es also eventuell keine einzige, jedenfalls nur sehr wenige (obwohl man die Wahrscheinlichkeit von Kollisionen auch nicht unterschaetzen darf).

                Wenn der Salt unbekannt ist, der Algorithmus aber schon hilft bei möglichen gefundenen Klartexten ansich nur Brute-Force - ausser man hat den Fall "Dämliches Passwort".

                Annahme hash(salt+password), der mögliche Klartext ist "R(c)Y)(A}kmk3o5s|F)7sYz1)!" - so ist unmöglich zu unterscheiden ob der Salt nun "R(c)Y)(A}" und das Passwort "kmk3o5s|F)7sYz1)!" ist oder doch "R(c)Y)(A}kmk3o" und "5s|F)7sYz1)!". Bei einem dämlichen Passwort hingegen wirds schon einfacher "R(c)Y)(A}kmk3o5s|F123456890" - was wird da wohl das Passwort sein? :)

                Es ist halt immer eine Ermessenssache wie man die Passwörter seiner Mitglieder absichert - bei einem dämlichen Passwort kann ein Salt gefährlich sein, wenn es darum geht das dämliche Passwort zu schützen :)

                Meine Meinung ist also: Der Gefahr von Kollisionen sollte mit der richtigen Hash-Funktion entgegengewirkt werden (auch wenn man sie natuerlich damit nicht ausschliessen kann).

                Ohne Salt wäre ein Kollision ein Problem - allerdings nur, wenn die Möglichkeit einer Preimage-Attacke besteht und ein Account gezielt angegriffen wird, das eigentliche Passwort aber irrelevant ist - eine zufällige Kollision (Geburtstagsproblem) ist, wie du sagst, extrem unwahrscheinlich.

                Meines wissens gibts aber auch für MD5 immer noch keine Möglichkeit zu einem Preimage-Angriff.

                1. weil eine vernuenftige Invertierungsfunktion (zum Berechnen der Ketten), die auf den Raum der Woerter mit einem Praefix aus dem Woertbuch beschraenkt ist, wohl kaum zu konstruieren ist (schaetze ich mal (?)).

                  Das halte ich für ein Gerücht :) Es ist keine Hexerei die Reduktionsfunkion so zu schreiben, dass sie an das neue Passwort in der Kette einfach wieder den Salt in definierter Form anhängt.

                  Das meinte ich nicht. Um sich (als Angreifer) die Tatsache, dass das Passwort aus dem Woerterbuch stammt, zunutze zu machen, muss man den Raum der zu checkenden Passwoerter irgendwie auf eben diese Woerter beschraenken. Um dafuer Rainbow-Tabellen zu berechnen, braeuchte man ne Reduktionsfunktion, die den Hash eines Woerterbuchwortes (bzw. Woerterbuchwort + Salt) wieder auf ein Woerterbuchwort abbildet (bzw., wenn mit Salt gespeichert, ein Wort, das mit einem Woerterbuchwort beginnt). Das auf hinreichend pseudo-zufaellige Weise zu machen, ist nicht effizient moeglich (sofern die Menge der Weorterbuchwoerter keine regulaere Sprache ist, was z.B. im deutschen m.W. der Fall ist ;-)).

                  Daher faellt die effiziente Berechnung von Rainbowtabellen bei einer Woerterbuchattacke flach. Bei Woerterbuchwoertern, die ohne Salt gespeichert werden, ist das nicht schlimm, weil man keine echte Rainbowtabelle braucht - eine lineare Liste mit allen Hashs ist kein grosser Aufwand. Die Menge aller Woerter mit "Woertbuch-Praefix" (d.h. Woerterbuchwort + irgendein Hash) ist dafuer aber zu gross.

                  Viele Gruesse
                  der Bademeister

                  1. Das meinte ich nicht. Um sich (als Angreifer) die Tatsache, dass das Passwort aus dem Woerterbuch stammt, zunutze zu machen, muss man den Raum der zu checkenden Passwoerter irgendwie auf eben diese Woerter beschraenken. Um dafuer Rainbow-Tabellen zu berechnen, braeuchte man ne Reduktionsfunktion, die den Hash eines Woerterbuchwortes (bzw. Woerterbuchwort + Salt) wieder auf ein Woerterbuchwort abbildet (bzw., wenn mit Salt gespeichert, ein Wort, das mit einem Woerterbuchwort beginnt). Das auf hinreichend pseudo-zufaellige Weise zu machen, ist nicht effizient moeglich (sofern die Menge der Weorterbuchwoerter keine regulaere Sprache ist, was z.B. im deutschen m.W. der Fall ist ;-)).

                    Das ist klar - wenn ich ohnehin NUR ein definiertes Wörterbuch verwende und danach auf weitere Angriffe verzichte, brauch ich keine Rainbow-Table. So groß kann das Wörterbuch garnicht sein, dass es nicht auf einen handelsüblichen USB-Stick passen würde ;)

                    Die Menge aller Woerter mit "Woertbuch-Praefix" (d.h. Woerterbuchwort + irgendein Hash) ist dafuer aber zu gross.

                    Natürlich - das ist ja der Sinn, eben Rainbow-Tabellen unrentabel bzw. unnütz zu machen - die Sicherheit eines einzelnen Passworts erhöht das aber kaum. Dass der Angreifer länger für seine Aufgabe benötigt ist kein wirkliches Sicherheitskriterum - ausser vielleicht bei Systemen mit beschränkter Dültigkeitsdauer der Passwörter. Aber auch das wäre kurzsichtig ;)

                    1. Hallo suit,

                      Dass der Angreifer länger für seine Aufgabe benötigt ist kein wirkliches Sicherheitskriterum

                      *hüstel* So ziemlich jeder Kryptoalgorithmus außer One Time Pads basiert aber auf eben diesem Prinzip: Dass Angriffe auf diese Algorithmen nicht praktikabel sind. Prinzipiell kannst Du doch genauso jede SSL-Kommunikation dekodieren - es dauert nur einfach *VIEL* zu lange auf aktueller Hardware. Betonung liegt auf *VIEL*.

                      Viele Grüße,
                      Christian

  2. Tach,

    also: md5($pass.$salt).

    für neue Projekte sollte man MD5 meiden und gleich einen der im Moment noch als sicher zu betrachtenden Algorithmen der SHA-2-Familie nutzen.

    mfg
    Woodfighter

    1. für neue Projekte sollte man MD5 meiden und gleich einen der im Moment noch als sicher zu betrachtenden Algorithmen der SHA-2-Familie nutzen.

      Nachdem man mit einem Salt das Passwört sowieso für jegliche Weiternutzung "versaut" (wie es auch sein soll) ist es unerheblich, welchen Hash-Algorithmus man verwendet. Prinzipiell kann man also gleich wie du sagst SHA-2-Hashes verwenden.

      1. Hallo,

        für neue Projekte sollte man MD5 meiden und gleich einen der im Moment noch als sicher zu betrachtenden Algorithmen der SHA-2-Familie nutzen.

        Nachdem man mit einem Salt das Passwört sowieso für jegliche Weiternutzung "versaut" (wie es auch sein soll) ist es unerheblich, welchen Hash-Algorithmus man verwendet.

        Jain. Wenn ich Salt + Passwort durch CRC32 jage, dann ist das auf heutigen Rechnern vermutlich innerhalb von Minuten geknackt.

        Was stimmt: Die bisher praktikabel ausnutzbaren Schwächen in MD5 betreffen gesaltete Passwörter noch nicht. Daher muss man sich im Moment keine Sorgen machen, wenn man noch MD5 als Hash für gesaltete Passwörter einsetzt.

        Allerdings: Man will ja für die Zukunft planen. Und es kann durchaus sein, dass jemand noch einen besseren Angriff auf MD5 findet, der es dann sehr einfach macht, mit MD5 gehashte Passwörter zu brechen (auch mit Salt).

        Daher: Wenn man neue Software schreibt (die sich an der Stelle nicht an Schnittstellen halten muss), sollte man MD5 nicht mehr verwenden, sondern lieber gleich die SHA-2-Familie nutzen. Auch bei sowas wie Passwort-Hashes.

        Übrigens: Um das Knacken weiter zu erschweren empfiehlt es sich, das Passwort mehrfach durch die Hash-Funktion zu jagen. Das kostet zwar Rechenzeit, die ist aber für das einmalie Prüfen vernachlässigbar, erhöht aber die nötige Zeit für's Durchprobieren. Pseudocode:

        Resultat := KlartextPasswort
        FOR i := 0 TO 1000
          Resultat := Hash(Salt || Resultat)
        END FOR

        Die Zahl 1000 natürlich möglichst groß gewählt, dass es noch praktikabel ist für normale Anwendungen.

        Man kann sich auch kompliziertere Schemen ausdenken, wie z.B. der MD5-Crypt-Algorithmus wie er vom Apache für .htaccess-Dateien verwendet wird, aber da muss man aufpassen, damit man sich die Entropie des Passworts nicht wieder kaputt macht - daher würde ich persönlich lieber zur einfachen Lösung raten.

        Viele Grüße,
        Christian

        1. Jain. Wenn ich Salt + Passwort durch CRC32 jage, dann ist das auf heutigen Rechnern vermutlich innerhalb von Minuten geknackt.

          Ich meinte mit "Versauen" dass ich ohne den Algorithmus zu übernehmen den Wert aus dem Datenbankfeld nicht verwenden kann.

          Wenn ein System als Loginverfahren einen md5-Hash nutzt, kann ich diesen Hash nicht in einem System verwenden wo ein Salt vorne drangehängt wird oder hinten oder irgendwie anders.

          Daher: Wenn man neue Software schreibt (die sich an der Stelle nicht an Schnittstellen halten muss), sollte man MD5 nicht mehr verwenden, sondern lieber gleich die SHA-2-Familie nutzen. Auch bei sowas wie Passwort-Hashes.

          Richtig, genau darauf wollte ich eben hinaus - wenn man sich an eine Schnittstelle halten muss, die verlangt dass das Passwort "sicher" in einer bestimmten Form abgelegt wird, kann man eben nicht einfach mal das Hash-Verfahren ändern ohne alle bisherigen Passwörter unbrauchbar zu machen.

          Übrigens: Um das Knacken weiter zu erschweren empfiehlt es sich, das Passwort mehrfach durch die Hash-Funktion zu jagen. Das kostet zwar Rechenzeit, die ist aber für das einmalie Prüfen vernachlässigbar, erhöht aber die nötige Zeit für's Durchprobieren. Pseudocode:

          Das hatte ich auch schon erwähnt - allerdings in Form von hash(variabler_salt + hash(salt + passwort)) oder  hash(salt + variabler_salt + passwort) - das ist allerdings nur Verschleierung die den Zeitaufwand erhöht, sicherer wird es dadurch nicht (sofern der Algorithmus bekannt ist und man nicht auf Security Through Obscurity setzt).

          1. Hi,

            Richtig, genau darauf wollte ich eben hinaus - wenn man sich an eine Schnittstelle halten muss, die verlangt dass das Passwort "sicher" in einer bestimmten Form abgelegt wird, kann man eben nicht einfach mal das Hash-Verfahren ändern ohne alle bisherigen Passwörter unbrauchbar zu machen.

            Innerhalb eines bestehenden Systems kann man die Umstellung aber auch „live“ durchführen, ohne den Nutzer damit zu belästigen.

            Zur alten Spalte, die alteHashFunktion(passwort+salt) enthält, legt man eine weitere an, in der neueHashFunktion(passwort+salt) abgelegt wird.
            Wenn der Nutzer sich einloggt, und in der neuen Spalte noch kein Passwort-Hash eingetragen ist, dann vergleicht man alteHashFunktion(passwort+salt) mit dem alten Hash. Ist der Vergleich erfolgreich, hat sich der Nutzer also erfolgreich authentifiziert, dann trägt man neueHashFunktion(passwort+salt) in die zugehörige Spalte ein, und verwendet künftig das zum Vergleich. Der alte Passwort-Hash wird dann gelöscht.

            Alle Nutzer, die sich regelmäßig einloggen, haben damit nach einer gewissen Zeitspanne nur noch den neuen Passwort-Hash in der DB.
            Die paar, die nicht dazu gehören, kann man dann zu dem Zeitpunkt, wo man den alten Hash entgültig entsorgen will, noch mal gesondert anschreiben - die kriegen dann bspw. einen Link geschickt, mit dem sie ihren Account wieder reaktivieren, und dabei ein neues Passwort eingeben können.

            MfG ChrisB

            --
            “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
          2. Hallo suit,

            Übrigens: Um das Knacken weiter zu erschweren empfiehlt es sich, das Passwort mehrfach durch die Hash-Funktion zu jagen. Das kostet zwar Rechenzeit, die ist aber für das einmalie Prüfen vernachlässigbar, erhöht aber die nötige Zeit für's Durchprobieren. Pseudocode:

            Das hatte ich auch schon erwähnt - allerdings in Form von hash(variabler_salt + hash(salt + passwort)) oder  hash(salt + variabler_salt + passwort) - das ist allerdings nur Verschleierung die den Zeitaufwand erhöht, sicherer wird es dadurch nicht

            Doch, da der Zeitaufwand für's Brute-Forcen (und auch der Zeitaufwand zum Generieren von und Abgleichen mit Rainbow-Tables) stark erhöht wird, wenn die Anzahl an Iterationen groß genug ist.

            Natürlich ist sowas nur das i-Tüpfelchen oben drauf, aber es bringt durchaus etwas.

            Viele Grüße,
            Christian

            1. Doch, da der Zeitaufwand für's Brute-Forcen (und auch der Zeitaufwand zum Generieren von und Abgleichen mit Rainbow-Tables) stark erhöht wird, wenn die Anzahl an Iterationen groß genug ist.

              Natürlich ist sowas nur das i-Tüpfelchen oben drauf, aber es bringt durchaus etwas.

              Wie eben schon gesagt: wenn es darum geht, massenhaft Daten zu verarbeiten und so an Passwörter zu kommen ist das natürlich durchaus ein Argument - durch den Aufwand wirds unrentabel - dafür sind Salts oder vergleichbare "Verkomplizierungsmechanismen" auch primär da, eben um Massendaten zu schützen. Bei einem gezielten Angriff auf ein einzelnes Passwort mit einem bekannten algoritmus ist das aber kein großes Hindernis.

              Wenn bekannt ist, dass das Passwort 1.000 mal gehasht wird, erzeuge ich mir halt einfach eine Rainbow-Table in der jedes Glied der Kette auch 1.000 mal gehasht wird -> Problem gelöst.

              1. Hi,

                Wenn bekannt ist, dass das Passwort 1.000 mal gehasht wird, erzeuge ich mir halt einfach eine Rainbow-Table in der jedes Glied der Kette auch 1.000 mal gehasht wird -> Problem gelöst.

                Ab dem zweiten Schritt brauchst du ja gar keine Hashes von beliebigen Passwörtern mehr bilden - sondern nur noch Hashes von Hashes.

                D.h., die Daten für Schritt zwei bis 1.000 kannst du statisch vorhalten, und brauchst das Passwort nur noch ein mal im ersten Schritt hashen, um zu schauen, welcher Hash sich dabei ergibt.

                MfG ChrisB

                --
                “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
                1. Ab dem zweiten Schritt brauchst du ja gar keine Hashes von beliebigen Passwörtern mehr bilden - sondern nur noch Hashes von Hashes.

                  D.h., die Daten für Schritt zwei bis 1.000 kannst du statisch vorhalten, und brauchst das Passwort nur noch ein mal im ersten Schritt hashen, um zu schauen, welcher Hash sich dabei ergibt.

                  Wieso? Innerhalb der Kette einer Rainbow-Table werden abwechselnd Hashes und mögliche Klartextpasswörter gebildet.

                  Wenn der Hash eines Klartextpassworts durch 1000x hashen gebildet wird, muss in der Kette auch nach jedem reduzieren des Hashes das neue Klartextpasswort auch wieder 1000x gehasht werden.

                  Das macht das Berechnen der Rainbow-Table zwar zeitintensiver, das Abfragen aber nicht.

                2. Hallo,

                  Wenn bekannt ist, dass das Passwort 1.000 mal gehasht wird, erzeuge ich mir halt einfach eine Rainbow-Table in der jedes Glied der Kette auch 1.000 mal gehasht wird -> Problem gelöst.

                  Ab dem zweiten Schritt brauchst du ja gar keine Hashes von beliebigen Passwörtern mehr bilden - sondern nur noch Hashes von Hashes.

                  D.h., die Daten für Schritt zwei bis 1.000 kannst du statisch vorhalten, und brauchst das Passwort nur noch ein mal im ersten Schritt hashen, um zu schauen, welcher Hash sich dabei ergibt.

                  Wenn Du diese Logik anwendest bräuchtest Du aber für jedes mögliche Salt eine unterschiedliche Rainbow-Tabelle, was das ganze dann unpraktikabel machen würde.

                  Viele Grüße,
                  Christian

                  1. Hi,

                    Wenn Du diese Logik anwendest bräuchtest Du aber für jedes mögliche Salt eine unterschiedliche Rainbow-Tabelle, was das ganze dann unpraktikabel machen würde.

                    OK, du meintest wohl, zwischen dem erneuten Hashen auch immer wieder zu salzen - das hatte ich anders verstanden.

                    MfG ChrisB

                    --
                    “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
              2. Hallo suit,

                Bei einem gezielten Angriff auf ein einzelnes Passwort mit einem bekannten algoritmus ist das aber kein großes Hindernis.

                Warum nicht?

                Wenn bekannt ist, dass das Passwort 1.000 mal gehasht wird, erzeuge ich mir halt einfach eine Rainbow-Table in der jedes Glied der Kette auch 1.000 mal gehasht wird -> Problem gelöst.

                Man erzeugt sich nicht "mal eben" so eine Rainbow-Tabelle - da steckt ja auch enormer Rechenaufwand dahinter. Außerdem: Rainbow-Tables lohnen sich ja sowieso nur, wenn Du das mehrfach anwenden willst; wenn Du nur ein einzelnes Passwort knacken willst (und noch keine Tabelle hast), dann bist Du besser dran, durchzuprobieren, als Dir vorher eine Tabelle anzulegen, wo Du im Zweifel mehr Rechenschritte drauf verbrätst. Zudem: Wenn es für $HASHFUNKTION 2 Monate dauert, sich die Rainbow-Tabelle zu erzeugen, man aber die Funktion 1000 mal iteriert anwendet, dann brauchst Du jetzt plötzlich etwa 2000 Monate, um die Tabelle zu bauen.

                Ferner: Wenn Salts im Spiel sind, dann ist die Rainbow-Table grundsätzlich *sehr* viel größer als one Salt - oder aber (bei "kleinen" Tables) es steigt der Rechenaufwand, um ein Passwort in der Tabelle zu finden, dramatisch.

                Nehmen wir doch nur mal Salts:

                Die reine (ungesalzene) SHA1-Summe des Passworts "hallo" ist:

                fd4cef7a4e607f1fcc920ad6329a6df2df99a4e8

                Das kannst Du inzwischen schon bei Google eingeben, um das Passwort zu bekommen.

                Wenn ich dagegen das Passwort mit dem zufälligen String Phaigh3ahH salze, dann erhalte ich

                65890aa07dba00a6778e22b8f11a4f61e63c489a

                als SHA1-Hash von dem Konstrukt. Selbst wenn Du das in einer SHA1-Rainbow-Table finden solltest, ist nicht sichergestellt, dass der zugehörige Klartext gleich anfängt (Du könntest sehr wohl auf eine Kollision stoßen) - und im Gegensatz zu reinem SHA1 (ohne Salt), wo eine Kollision als Klartextpasswort genauso funktionieren würde, kannst Du die im Falle der Verwendung von Salts nicht verwenden - sondern müsstest weitersuchen.

                Insofern: Sowohl Salts als auch das mehrfache Iterieren der Hash-Funktion erhöhen die Sicherheit des Hashwerts des Passworts.

                Viele Grüße,
                Christian

                1. Warum nicht?

                  Wenn jemand den Algorithmus zum Schutz des Passworts in die nötigen Eckdaten hat und ernsthaft daran interessiert ist, ins System zu gelangen, lässt er sich von sowas nicht aufhalten.

                  Man erzeugt sich nicht "mal eben" so eine Rainbow-Tabelle - da steckt ja auch enormer Rechenaufwand dahinter.

                  Übertreibs nicht, so enorm ist der auch nicht :) In ein paar Stunden ist eine sehr umfassende Tabelle generiert.

                  Außerdem: Rainbow-Tables lohnen sich ja sowieso nur, wenn Du das mehrfach anwenden willst;

                  Natürlich, darum hängt es eben vom verwendeten Algorithmus ab - wenn die Salt-Komponente variabel ist, kann man gleich wieder Brute-Force anwenden.

                  Die Rainbow-Table bietet im Vergleich zu einem flachen Tabelle den Vorteil, dass sie weniger Platz benötigt bzw. bei gleicher Größe theoretisch mehr Klartexte aufnehmen kann - mit dem Nachteil, dass möglicherweise nicht alles abgedeckt wird.

                  wenn Du nur ein einzelnes Passwort knacken willst (und noch keine Tabelle hast), dann bist Du besser dran, durchzuprobieren, als Dir vorher eine Tabelle anzulegen, wo Du im Zweifel mehr Rechenschritte drauf verbrätst.

                  Wörterbuch gefolgt von Brute-Force mit Zufallsfolgen sind da sicher schlauer, ja.

                  Zudem: Wenn es für $HASHFUNKTION 2 Monate dauert, sich die Rainbow-Tabelle zu erzeugen, man aber die Funktion 1000 mal iteriert anwendet, dann brauchst Du jetzt plötzlich etwa 2000 Monate, um die Tabelle zu bauen.

                  Ich weiß nicht, welche vorstellungen du von Rainbow-Tabellen hast - aber es dauert keine 2 Monate eine zu berechnen - eine umfangreiche Tabelle mit sagen wir 1 bis 2 TiB ist in rund einem Tag berechnet.

                  Ferner: Wenn Salts im Spiel sind, dann ist die Rainbow-Table grundsätzlich *sehr* viel größer als one Salt - oder aber (bei "kleinen" Tables) es steigt der Rechenaufwand, um ein Passwort in der Tabelle zu finden, dramatisch.

                  Ja - die Tabelle wenn der Salt einfach durch Verkettung benutzt wird exakt um n*Salt größer als ohne Salt (wobei n der Anzahl der Datensätze entspricht).

                  als SHA1-Hash von dem Konstrukt. Selbst wenn Du das in einer SHA1-Rainbow-Table finden solltest, ist nicht sichergestellt, dass der zugehörige Klartext gleich anfängt (Du könntest sehr wohl auf eine Kollision stoßen) - und im Gegensatz zu reinem SHA1 (ohne Salt), wo eine Kollision als Klartextpasswort genauso funktionieren würde, kannst Du die im Falle der Verwendung von Salts nicht verwenden - sondern müsstest weitersuchen.

                  Genau aus dem Grund: keine dämlichen (kurzen) Salts verwenden "Phaigh3ahH" ist kein Salt "HarWhBdh|3VacE-QE9jEGA>6M)O-^2pr}|z]KH- ;@cl7@>[ZKTKgi9j?*Pl4m*>(:{2UQ9+xn3+E=HyS,C-,D<Goq[df-u{FA.=<&4L[.yle$iOn(zYZ,Z~aS|oBZ" ist schon besser geeignet.

                  Insofern: Sowohl Salts als auch das mehrfache Iterieren der Hash-Funktion erhöhen die Sicherheit des Hashwerts des Passworts.

                  Wenn du das so siehst ja - aber ein geheimer zusätzlicher Salt ist da wesentlich praktikabler als das mehrfache durchsemmeln durch eine Hashfunktion bzw. hinzufügen von Salts die ohnehin bekannt sind.

                  1. Hallo suit,

                    Bevor wir uns in Details verzetteln:

                    Mir ging es um folgendes Angriffsszenario: User-DB-Dump landet durch irgend eine Lücke plötzlich in den Händen von $Angreifer. Der will die Passwörter knacken, um ins System zu kommen.

                    Meine Aussage ist lediglich, dass es einfache Maßnahmen gibt, die Rainbow-Tabellen (und auch flache) gegenüber Brute-Force unpraktikabel machen - und Salting i.V.m. mehrfacher Iteration der Hashfunktion (wobei jedes Mal der Salt wieder hinzugefügt wird) leistet so etwas. In dem Fall bleibt dem Angreifer dann wieder nur Brute-Force übrig - was aber dank der mehrfachen Iteration der Hashfunktion selbst sehr, sehr teuer wird.

                    Jemand mit ausreichend Hardware und Zeit wird sich daran natürlich auch nicht stören - allerdings kann man durchaus die Latte so hoch setzen, dass es sich selbst für die am besten ausgestatteten Angreifer nicht mehr lohnt, das zu versuchen.

                    Dein Vorschlag, einen geheimen (ich vermute in der Config eingestellten oder sowas) zusätzlichen Salt einzubauen, ist natürlich ein weiterer Baustein, der die Sicherheit erhöhen kann (aber nicht muss, hängt davon ab, ob ein Angreifer die Config gleich mitdumpen kann oder nicht) und der meine Vorschläge gut komplimentiert - aber nicht ersetzt.

                    Viele Grüße,
                    Christian

                    PS: Ja, mein Beispiel für einen Salt war nicht sehr gut gewählt. Deine Wahl war aber dann in die andere Richtung übertrieben.

                    1. Dein Vorschlag, einen geheimen (ich vermute in der Config eingestellten oder sowas) zusätzlichen Salt einzubauen, ist natürlich ein weiterer Baustein, der die Sicherheit erhöhen kann (aber nicht muss, hängt davon ab, ob ein Angreifer die Config gleich mitdumpen kann oder nicht) und der meine Vorschläge gut komplimentiert - aber nicht ersetzt.

                      Der geheime Salt hilft natürlich nichts, wenn der Angreifer bereits Vollzugriff auf sämtliche Daten hat - aber im "genannten" Szenario kommt die Datenbank abhanden, der Rest aber nicht. Es gibt genug Helden, die Ihre SQL-Dumps im Stammverzeichnis des Webs liegen lassen - eine Filetype-Suche in der Suchmaschine deiner Wahl wird erschreckendes ans Tageslicht befördern :)

                      PS: Ja, mein Beispiel für einen Salt war nicht sehr gut gewählt. Deine Wahl war aber dann in die andere Richtung übertrieben.

                      Ein 128-Byte ist ggf. etwas übertrieben, aber 64 solltens imho schon sein :)

                      1. Hallo suit,

                        PS: Ja, mein Beispiel für einen Salt war nicht sehr gut gewählt. Deine Wahl war aber dann in die andere Richtung übertrieben.

                        Ein 128-Byte ist ggf. etwas übertrieben, aber 64 solltens imho schon sein :)

                        Nein, das ist völlig unnötig. Alleine mit Groß- und Kleinschreibnug sowie Zahlen und 2 Sonderzeichen kommst Du schon auf ein Alphabet mit 64 Zeichen (Du hattest sogar etwas mehr, irgendwo in der Gegend von 70 oder 75 Zeichen). Das heißt, dass Du bei 64 Zeichen mindestens 64^64 verschiedene Möglichkeiten hast - und das ist weit mehr, als Du mögliche Hashes (2^256) bei SHA-256 hast [1]. Das bringt Dir gar nichts. Bei einem Alphabet von 64 Zeichen wären also, um den kompletten Keyspace eines SHA-256-Hashes abzudecken, schon 42 bis 43 Zeichen ausreichend - bei einem Alphabet von 75 Zeichen nur noch 41.

                        Viele Grüße,
                        Christian

                        [1] Unter der Annahme, dass SHA-256 surjektiv ist, was m.W. vermutet wird, aber nicht bewiesen wird.

                        1. Nein, das ist völlig unnötig. Alleine mit Groß- und Kleinschreibnug sowie Zahlen und 2 Sonderzeichen kommst Du schon auf ein Alphabet mit 64 Zeichen (Du hattest sogar etwas mehr, irgendwo in der Gegend von 70 oder 75 Zeichen). Das heißt, dass Du bei 64 Zeichen mindestens 64^64 verschiedene Möglichkeiten hast - und das ist weit mehr, als Du mögliche Hashes (2^256) bei SHA-256 hast [1]. Das bringt Dir gar nichts. Bei einem Alphabet von 64 Zeichen wären also, um den kompletten Keyspace eines SHA-256-Hashes abzudecken, schon 42 bis 43 Zeichen ausreichend - bei einem Alphabet von 75 Zeichen nur noch 41.

                          Da hast du natürlich recht, aber wer sagt denn, dass wir SHA-256 verwenden? Warum nicht SHA-512/384 :)

                          Nein, ersthaft: ich verstehe, was du meinst :)

  3. hi,

    Hat das irgendwelche Vorteile??

    Das salt braucht ein *Script*, was vom Benutzer das Passwort als Zeichenkette bekommt, nur mit dem richtigen salt kann das *Script* die Eingabe zu demselben Hash encrypten. Zumindest ist das mit der Encrypt-Methode crypt() so. Zu md5 o.a. müsste ich nachschauen.

    Rolf

    --
    Die Schwerkraft brauche ich nur zum Krafttraining, was mich am Boden hält ist meine Frau.