Loginpasswort richtig hashen - password_hash() & password_verify()

  • Naja, ich bin auf der Suche nach Funktion, die das Ganze dynamisch klärt =)
    zB
    $interval_days = 100; # also alle 100 tage


    Aber es loggt sich ja nicht jeder Nutzer jeden Tag ein. Also muss da eine Prüfung mit rein, ob der letzte Interval schon war, ...
    Weiß grad nich, wo ich ansetzen soll.

  • Was ist damit?

    PHP
    if (date("j") == 1)
        $hash = password_needs_rehash(...) ? password_needs_rehash(...) : $hash;


    Jeden Monat am ersten, wenn sich da wer einloggt... man koennte auch nen Zeitraum eingeben, zB in den ersten zehn Tagen jedes Monats...
    Ich denke mal zumindest, wenn die Leute auch nur halbwegs aktiv sind, sollten sie sich wenigstens einmal alle drei Tage einloggen ;) Und selbst wenn es seltener ist, mit 10 Tagen Zeitraum, sollte man gut laufen, muss man aber ausprobieren...


    Nachtrag, weil Quote entdeckt...

    das bedeutet ja doppeltes Hashen


    Das stimmt so nicht, weil: Wie weiter vorne im Thread erklaert, wird ja Salt und Cost direkt an den Anfang des Hashes gesetzt. Dh password_needs_rehash prueft erstmal nur die ersten paar Zeichen des Hashes, ob sie den Vorgaben entsprechen, die neu mitgegeben wurden.
    Da wird noch nichts gehasht, das ist nur ein kurzer Stringvergleich.
    Und erst, wenn diese Pruefung das Ergebnis ungleich lieferte, dann wird gehasht. Also kann man das im Endeffekt ohne Probleme auch bei jedem Login einbauen, weil ein Stringvergleich mehr oder weniger ist ja noch nicht die Welt. Bei hashen hast du recht, das wuerde schon ein bisschen an der Geschwindigkeit kratzen.


    Aber nur mal nebenbei: Wenn ich aktuell Youtube aufrufe (was auf schnellen Servern liegt) braucht die Seite knapp 7 Sek zum aufbauen (bei zwangsweise VPN ueber Oesterreich).
    Da ist ein 5 Sek Login auf einem langsameren Server auch ok...

  • ......
    [*]Am allerwichtigsten: Man nutzt es mit Sicherheit! Hier ist allerdings zu sagen, md5() und sha1() für Passwörter sind ungenügend, besser sind password_hash() oder crypt()
    .....

    Ungenügend... Wer sagt denn sowas? :S
    Ein Vorwurf, der sich schon ewig hällt. Eine Kombination aus z.B. ID+Username+md5(Passwort) Kann garnicht Unsicher sein.


    "abc" als passwort_hash und abc als MD5-Hash sind gleich unsicher!

  • Algorithmen wie md5 und sha1 sind kryptografisch theoretisch nicht mehr sicher und sollten deshalb nicht verwendet werden (für md5 gibt es z.B. lookup-Tabellen).. Es geht ja nicht um die Sicherheit des Einloggens an sich, sondern um die Sicherheit falls jemand Zugriff auf die Datenbank bekommt.


    Zitat

    "abc" als passwort_hash und abc als MD5-Hash sind gleich unsicher!


    falsch. password_hash hasht (wenn ich richtig informiert bin) mit einem starken one-way Algorithmus und einem zufälligen salt, der dann in den hash eingebaut wird damit password_verify das passwort überprüfen kann.
    man kann zwar auch bei md5 zusätzlich einen salt einbauen, allerdings ist dann der Algorithmus immer noch wesentlich schwächer.

  • sysop, leider fehlen mir bei deinen Aussagen die Begründungen? So etwas einfach in den Raum stellen ist meistens eher ungünstig.


    md5 und password_hash unterscheiden sich schon alleine darin das man das Ergebnis von password_hash beeinflussen und auf seinen Server abstimmen kann, bei md5 funktioniert dies nicht, somit habe ich "abc" als Passwort mit md5 Verschlüsselung in unter einer Minute geknackt, je nachdem wie schnell die Datenbank läd, bei password_hash brauche ich zusätzlich zum Beispiel den Salt.

  • Ungenügend... Wer sagt denn sowas? :S
    Ein Vorwurf, der sich schon ewig hällt. Eine Kombination aus z.B. ID+Username+md5(Passwort) Kann garnicht Unsicher sein.


    "abc" als passwort_hash und abc als MD5-Hash sind gleich unsicher!


    Das stimmt absolut nicht. abc als md5 Hash habe ich mit einer normalen Grafikkarte in längstens 5 Sek geknackt, mit Rainbowtable im Bruchteil einer Zehntelsekunde. Für den Password_hash() brauche ich schon eine Viertelstunde.
    Und zwar aus folgenden Gründen:


    Regel 1) Je öfter etwas den Algorithmus durchläuft, desto sicherer wird es
    md5() und sha1() sind beides sehr schnelle Verschluesselungsalgorithmen, was heißt, der Algorithmus wird nur einmal angewandt. Durch ein häufigeres Durchlaufen des Verschlüsselungsalgorithmus kommt aber mehr Chaos, mehr "Zufall" in den Hash, was dafür sorgt, dass bei der einzigen heute möglichen Methode des Hash-Entschlüsselns, des Brute Force, mehr Rechenleistung pro Hash gebraucht wird.
    password_hash() mit Blowfish im Hintergrund, hat durch den Cost die Möglichkeit, die Anzahl der Durchläufe zu wählen, wenn n der Cost ist ist 2^n die Anzahl der Durchläufe


    Regel 2) Ein guter Salt macht Brute Force zum Albtraum
    md5() und sha1() liefern keine automatisch generierten Salts. Dadurch kann man bei einfachem Abgleich mit Rainbowtables den Rechenaufwand um ein Vielfaches minieren.
    password_hash() hingegen generiert automatich einen zufälligen Salt für jedes passwort, mit weltweit von Kryptographieexperten anerkannten Methoden. Selbst gebaute Saltgeneratoren für md5() sind einfach nicht so zufällig.


    Regel 3) Der Algorithmus im Hintergrund ist am Wichtigsten
    Alles obige ist für die Katz, wenn der Verschlüsselungsalgorithmus selbst nicht sicher ist. Und md5() und sha1() bieten zwar keine Entschlüsselungsmöglichkeit, genauso wenig wie password_hash(), aber letzteres ist um ein Vielfaches kollisionsresistenter. D.h., wenn man sich ausschließlich den eigentlichen Hash anschaut, ist es bei md5() und sha1() wesentlich leichter, zu einem Hash eine passende Zeichenkette zu finden, welche nicht einmal unbedingt das Passwort sein muss, als bei password_hash(). Collisions for Hash Functions [...]MD5[...] (pdf)


    Regel 4) Verschlüsselung sollte immer auf dem neuesten Stand sein
    Durch die leistungsfähigeren Computer muss auch eine immer leistungsfähigere Verschlüsselungsmaschinerie her (man denke an einen umfunktionierten ASIC Bitcoinminer für Bruteforcing...). md5() und sha1() sind schon seit Jahren gleich, und damit veraltet. password_hash(), speziell mit der Standardeinstellung PASSWORD_DEFAULT aktualisiert in neuen PHP Versionen automatisch den verwendeten Hash, wodurch man ohne eigenes Umprogrammieren stets einen aktuellen Algorithmus verwenden kann. Besonders, wenn man die komplette PHP Password API mit password_needs_rehash() wie empfohlen verwendet.


    Noch Fragen?

  • So, ich melde mich hier nochmal, da ich vor Kurzem eine echt nette Anleitung zu dem Thema gefunden habe:
    "Wie man mit Pfeffer den Fisch versalzt" - Tutorial über das sichere Speichern von Passwörtern.


    Der hat auch noch Folgendes geliefert: Passwort Hashes mit bcrypt generieren und, auf der Seite ein bisschen scrollen, Sichere Passwort-Reset Funktion.
    Vor allem Letzteres klingt sehr interessant, ich zB habe gemerkt, dass ich mir darum gar keine Gedanken gemacht hatte, sondern nur um sicheres Speichern von PWs :whistling:


    Wurde alles in diesem Jahr unter Berücksichtigung der PHP Password API und mit Bezug auf allgemeine Algorithmus-Sicherheit (*hust*md5) aktualisiert, lohnt sich also, sich das mal anzuschauen.

  • Dann "rechtfertige" ich mal. 8)


    Die Antworten hier habe ich übrigens erwartet, zeigen mir aber auch, dass das Thema nicht generell zuende gedacht wird/wurde.


    Was soll den mit einer Verschlüsselung erreicht werden?
    Zunächst soll ein "Text" erst einmal unkenntlich gemacht werden, damit man den "Klartext" nicht offensichtlich vor Augen hat. Er muss ein One-Way-Ticket sein, sprich man darf den String/Text nicht wieder entschlüsseln können (sofern der Verschlüsselungsalgorithmus auch funktioniert). Er muss reproduzierbar sein (der selbe Text muss den selben Hash produzieren), sonst lassen sich Passwort-hashes nicht miteinander vergleichen. Und genau DORT liegt die grosse Unsicherheit.
    3 Stellige Passwörter generieren zu lassen ist kein Aufwand für Rechner und NICHT die Verschlüsselung selbst ist hier das Problem, sonderen die verfügbare Rechenleistung die diese Aufgabe in wenigen Sekunden erledigen kann.


    Rainbow-Table setzt zunächst voraus, dass ich irgend wie an den Hash komme, was für sich genommen schon fast einem geknackten Passwort (Code) gleich kommt. Erste Voraussetzung für ein sicheres Passwort ist also, den Hash nicht bekannt zu geben!

    Zitat

    .......aber letzteres ist um ein Vielfaches kollisionsresistenter. D.h.,

    Etwas, was ich in meinem obigen Post übrigens mit der Kombination von ID+Username+Passwort ebenfalls ähnlich realisiert hätte und darauf habe ich extra hingewiesen. Die Kombination aus MD5(ID+Passwort) setzt auch Rainbowtabellen ausser Kraft und hat zudem noch den Vorteil, dass ein User, der sich z.B. in mehreren Foren mit dem selben Passwort anmeldet verschiedene MD5-Hashes zugewiesen bekommt (das klappt natürlich auch mit allen anderen Verschlüsselungen, aber darum geht es ja eigentlich nicht).


    Zitat

    Regel 1) Je öfter etwas den Algorithmus durchläuft, desto sicherer wird es
    ....
    Durch ein häufigeres Durchlaufen des Verschlüsselungsalgorithmus kommt aber mehr Chaos, mehr "Zufall" in den Hash
    ....

    Hier wird schon implizit angenommen, dass der Hash nach aussen dringt. Man verlässt sich darauf, dass die Unlesbarkeit ein sicherheitsrelevantes feature ist. Ist es aber nicht. Kleines Beispiel:



    Ergebnis:

    Code
    Standard MD5: 0cc175b9c0f1b6a831c399e269772661
    Doppelt MD5 : d7afde3e7059cd0a0fe09eec4b0008cd
    MD5 + Prefix: cce00359c0f1b6a831c399e269772661
    Standard DES: rlm7yWjICSgV.
    Extended DES: _J9..rasmWuvos8B/9gQ
    SHA-256     : $5$rounds=5000$usesomesillystri$CV9NHgkKMD/0AlV.nDuk.R1O2LWDpPQh0nnvMwUoNG0
    SHA-512     : $6$rounds=5000$usesomesillystri$EgFOhWMt0i19wAdCx0mX7vXrnzkh1u.78VGGmXxjMOtkA/TQjHF88ANJB4BaDpw.pjHOpKQXO0FGBSgK5rtk31


    Ich behaupte mal, aus keinem der oben generierten Hashes kannst du das Passwort "a" herausraten. Setzt du ein Wörterbuch oder ein kleines Script darauf an, ist das Passwort in weinigen Sekunden geknackt und der doppelte MD5-Hash hat keinerlei Sicherheitswirkung. Obige Aufgabe lässt sich sogar händisch problemlos lösen.


    Der wesentlichste Schritt zur Sicherheit ist ein Passwort aus (was weiss ich) mindestens 8 Zeichen, mit Gross/Kleinschreibung, Zahlen und Sonderzeichen. Ein Script tut sich hier auch schon um einiges schwerer. Wie lange ein Script für 8 oder mehr Zeichen brauchen würde weiss ich nicht, aber auch hier gillt, liegt der Hash als Vergleich vor mir, habe ich die halbe Miete schon verschossen.


    Lasse ich beliebig viele Eingabeversuche zu, gillt:
    Das Passwort "!Grf5mn&" ist bei ordentlicher Programmierung nahezu gleich sicher als MD5-Hash wie auch als SHA-256 oder SHA-512.
    Was ich übrigens noch zusätzlich einbaue ist eine MUSS-Pause von 3 Sekunden zwischen 2 Passwort-Eingaben, was einen Robot-Einsatz zu einer langweiligen Sache macht.


    Ich formuliere es mal so:
    Was mich an obigem Text gestört hat, ist die Tatsache, dass der Eindruck entsteht, man kann mit einer entsprechenden Verschlüsselung ruhig das Passwort "abc" verwenden, es ist sicher, man nutzt ja eine sichere Verschlüsselung. Wesentlich ist aber das Passwort selbst, dass das Passwort (der Hash) nie nach aussen dringt und ein entsprechend sicheres Passwort gesetzt wurde. Mit einer Limitierung der Eingabe sind Unterschiede in der Sicherheit gegen NULL-laufend.


    Ein Thema übrigens, dass auch in anderen Foren sehr kontrovers diskutiert wird.

  • Du gehst ehrlich gesagt mMn völlig falsch an das Thema ran: Die Sicherheit eines Algos, und um den geht es grade, sollte in keiner Weise vom zu verschlüsselnden String abhängen. Dann läuft was grundsätzlich falsch.
    Und mit der Verschlüsselung soll natürlich erreicht werden, dass der Angreifer nix mit den PWs anfangen kann, wenn er sie erstmal hat. Ich meine, würde ich davon ausgehen, dass er nicht mal in meine Tabelle kommt, wozu dann die Mühe des Verschlüsselns?


    Reproduzierbar: ja, aber auch kollisionsresistent. Denn "Kollision" in diesem Fall heißt: zwei verschiedene Strings, der gleiche Hash. Und das ist bei md5 viel wahrscheinlicher, als bei bcrypt, oder sha256, da hast du offenbar "kollisionsresistent" nicht wirklich verstanden, scheint mir.


    Durchlaufen des Algos heißt nicht, sie werden immer wieder neu verschlüsselt, sondern es ist wesentlich komplexer, schau mal in die Wikipedia zu sha 256 oder so. Das Resultat jedenfalls ist ein komplexerer Hash, was auch zur Kollisionsresistenz beiträgt.


    Rainbowtable natürlich, immer noch beliebtester Angriff, und der Angreifer hat den Hash, siehe Anfang des Posts. Aber dagegen hilft kein Algo der Welt, da diese genutzt werden um die tables zu erstellen, sondern die Zusatzkomponenten Salt und Pepper. Und diese müssen möglichst zufällig sein. Pepper ist kein Problem da sind md5() die PW API gleich, einmal den PW Generator und fertig, aber guter Salt für jedes PW? Möglichst zufällig? Das macht md5() einfach nicht selber, password_hash() dagegen automatisch.
    Und ein gleichwertiger Saltgenerator für md5 ist einfach sehr schwer zu proggen. Bzw. wenn, dann wesentlich langsamer als der von der PW API native.


    Und ein Durchprobieren direkt am Loginmodul hat nichts mit dem Algo selbst zu tun, das ist ein völlig anderes Thema, nämlich die Formularsicherung gegen Bots. Also, nicht ablenken ^^


    Und natürlich ist "abs" als PW nicht sicher, aber dafür gibts nen hübschen Artikel: Warum 123456 als Passwort okay ist. Oder kurz: Wenn sie blöde Passwörter nutzen, ist ihnen der Acc nicht wichtig. Aber auch das hat nichts mit dem Algo dahinter zu tun.
    Und nochmal anders: Auf Nutzereingaben sollte man nie vertrauen, Goldene Regel 1) der PHP Programmierung. Das gilt auch für PWs. Deshalb kommen ja Salt zur PW Verlängerung und Pepper gegen Wörterbuchangriffe zum Einstatz. Nutzt man beides wird aus dem String "a" plötzlich ein "afvcdövfdjhö3587pfscbwöeriuztü8o". Und das ist definitiv sicher. Aber auch hier gilt: Ich muss nicht unbedingt diesen obigen String finden, wenn der Algo selbst nicht kollisionsresistent ist.
    Und dann nehme man md5(), von welchem bekannt ist, dass es eine hohe Kollisionsrate hat und das unten erwähnte GPU Cluster... der Angriff gilt übrigens in diesem Fall dann für zwei beliebige String ;) Dann doch lieber bcrypt, also password_hash().


    Aber ich glaube, diese Diskussion sollte in den Thread zu Passwortgenerierung, da ist sie besser aufgehoben als hier. Wäre das möglich, basii oder lauras? Danke ^^

  • indeed.
    sysop lies Dir mal das hier Durch: Loginpasswort richtig hashen - password_hash() & password_verify()
    und auf der letzten Seite im Post von The Scout erwäht: http://www.martinstoeckli.ch/hash/de/
    Wie The Scout schon sagte - du hast da was falsch verstanden.


    Und ja - man MUSS davon ausgehen, dass jemand mal an die Sql tables kommt. Denn man will als Verantwortlicher selbst mit runtergelassenen Hosen noch sicher auf dem Boden stehen.


    btw: jemand mitbekommen? http://www.heise.de/newsticker…p-de-kopiert-2156965.html (http://www.chip.de/artikel/Mitteilung_68834577.html)

  • Dazu gehörend: http://www.heise.de/newsticker…-GPU-Cluster-1762654.html
    Ein GPU Cluster als BruteForce Center, mit ein paar Zahlen (Hashes/sec):
    md5: ca 180.000.000.000 (Milliarden)
    sha1: ca 63.000.000.000 (Milliarden)
    sha512: ca 364.000 (Tausend)
    Bcrypt (was momentan bei password_hash() genutzt wird): ca. 71.000 (Tausend)


    Und dann sag nochmal, md5 sei genauso sicher wie password_hash() ;) Ist ja nur ein Hash-Verhältnis von rund 2535211 : 1 :P

  • An dieser Stelle müsste mal beachtet werden das sich dieses Forum nicht an Nutzer sondern an Coder wendet, folglich ist die Kritik ein Passwort sei nur so sicher wie der String (und andere Faktoren wie zum Beispiel regelmäßige Aktualisierung) hier unangebracht denn der Titel lautet "Loginpasswort richtig hashen [...]" und nicht "Sicheres Passwort". sysop dein Beitrag geht irgendwie leicht am Thema vorbei.


    Beim Thema Sicherheit gehen wir selbstverständlich davon aus das der Angreifer an die Hashes kommt, denn das ist für erfahrene Hacker absolut kein Problem ;) Es ist sicher nicht mehr so einfach wie vor ein paar Jahren aber es ist immer noch ganz gut machbar.


    Außerdem ist die Anleitung ja keine strikte Vorschrift sondern wie immer in diesem Forum nur ein Ansatz den man fortführen soll, entweder durch Google oder durch eine Diskussion hier.

  • Hmm nun wurden meine Beiträge hierher verschoben, ich hatte nicht hier gepostet sondern hier


    Passwörter vor Zugriffen zu schützen, b.z.w Hindernisse zum Knacken in den Weg zu legen ist das Eine, deshalb lasse ich das hier an dieser Stelle.
    Wie schon richtig gesagt, geht es in diesem Thema um etwas anderes.


    Schönen Tag noch.

  • Nur zur Ergänzung: Passwortlänge / Limit
    http://stackoverflow.com/quest…h-maximum-password-length


    aber


    Zitat von http://blog.nic0.me/post/63180966453/php-5-5-0s-password-hash-api-a-deeper-look-under


    A lot of people probably think there should be no maximum password length, but this is actually wrong. Calculating the hash of a normal password is fast, but attackers may send a large, multiple megabyte file as password, and this will take bcrypt (or any other hashing algorithm for that matter), a lot of time to calculate. This method can be used to DDoS your server. Since password_hash() allows any given length, you should absolutely check for it yourself.


    Also richtig sicher bin ich mir nu nich, ob da eine Grenze bei der Funktion password_hash() existiert. Aber Fakt ist wohl: um so länger das zu prüfende Passwort, desto mehr Aufwand/Ressourcen.
    Also tut man sich schon selbst einen Gefallen, wenn man von vorn herein Passwörter länger als (Bsp!) 30 Zeichen durchfallen läst (also NICHT in die Prüfung password_verify() schickt).
    Natürlich muss man das dem Nutzer auch mitteilen =)

  • Ich hätte gesagt, sogar 20 Zeichen reichen schon.
    Die meisten nehmen seltenst Passwörter länger als 8 Zeichen, und wer das doch macht, ist eigentlich nie über 20.


    Wer wirklich mehr als 20 Zeichen für ein Passwort braucht, arbeitet entweder bei der NSA oder der chin. Regierung ;)

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!