password_verify werkt niet

  • Hallo,


    Ik ben bezig om het registreren en inloggen aan te passen naar een andere beveiliging.
    De beveiliging zet ik om naar een password hash, zie hier voor meer informatie.
    Ik gebruik hiervoor het voorbeeld met PASSWORD_BCRYPT.


    Echter zit ik nu met een klein probleem, het aanmaken van het wachtwoord werkt naar behoren, maar het inloggen werkt niet. Bij het inloggen komt er te staan dat het wachtwoord niet overeen komt.


    Registratie
    $_POST['password'] is het veld wat wordt ingevoerd bij de registratie.

    PHP: Registratie
    $options = ['cost' => 12,];
    $passwordFromPost = $_POST['password'];
    $hash = password_hash($passwordFromPost, PASSWORD_BCRYPT, $options);




    Inloggen:
    $_POST['gn'] en $_POST['ww'] komen vanaf de velden die ingevuld worden.


    Ik hoop dat jullie me hiermee kunnen helpen :D


    Bedankt!

  • Allereerst, heb je vastgesteld dat je PHP-versie nieuw genoeg is? Minimale versie is 5.5.0.


    Vervolgens, heb je al het een en ander gedebugged? Is het loginscript verder foutvrij?


    En dan maak je je het jezelf wel erg moeilijk met het kopiëren van allerlei variabelen.


    Ook lijkt het mij niet nodig dat je $_POST['ww'] escaped (en trimt?) omdat je deze variabele toch niet in een SQL-passage stopt.


    Daarnaast controleer je niet of je query wel resultaten heeft (of liever gezegd, precies één resultaat oplevert).


    Het ophalen van alle kolommen is wellicht ook overkill als je enkel het wachtwoord en/of enkele andere kolommen nodig hebt.


    Maak anders eerst eens een heel simpel test scriptje:

    PHP
    <?php
    $hash = password_hash('test', PASSWORD_BCRYPT, ['cost' => 12]);
    
    
    if (password_verify('test', $hash)) {
        echo 'cake';
    } else {
        echo 'no cake';
    }
    ?>[end]

    Hier zou:

    Citaat

    cake[end]

    Uit moeten rollen.

  • Hoi FangorN,


    Bedankt voor je reactie.


    Ik zit momenteel op PHP 7.0 dat zal het probleem niet zijn.


    Wanneer ik controleer wat uit het resultaat komt zie ik elke keer een andere hash terwijl ik hetzelfde wachtwoord invoer.


    Ik heb je test script gebruikt en het werkt zolang ik het wachtwoord test gebruik.


    Wanneer ik test weghaal en een variabel hierin zet zoals het wachtwoord wat wordt ingevoerd (POST) en het wachtwoord wat wordt opgeslagen in SQL werkt het script niet meer.


    Nu heb ik Cake en No Cake aangepast naar Goed en Fout, hierin heb ik bij Fout de $hash meegenomen en de hash uit SQL om te kijken of deze overeen komen alleen is de $hash die wordt ingevoerd als wachtwoord elke keer anders en komt niet overeen met het wachtwoord uit de SQL.


    Resultaat:
    $ww = ingevoerde wachtwoord
    $password = wachtwoord uit SQL

    PHP
    $hash = password_hash($ww, PASSWORD_BCRYPT, ['cost' => 12]);
    if (password_verify($password, $hash)) {
     echo 'Goed';
    } else {
     echo 'Fout '.$ww.' '.$hash.'';
    }


    Hash SQL:
    $2y$12$ETACJqjCZHMI9iRuW30tXOLXPh18oSE6bA4ysSIgiVjL8xNk817Qq


    Hash Post wachtwoord: (veranderd elke keer)
    $2y$12$Zo9KwV0/ilp63NHGnpox8uR4Xcsf.DAuSG0a.pvWYici8BQqdWtPK

  • Dat klopt ook want je krijgt een gehashde variant retour waar een salt op is toegepast. Je berekent dus een eindresultaat op grond van een aantal cryptografische bewerkingen. Vervolgens test password_verify() of er een gelijkwaardig (maar dus mogelijk verschillend) resultaat berekend kan worden met behulp van het oorspronkelijke wachtwoord en een hash hiervan waar deze functie ook weer informatie uit kan halen zodat deze weet hoe er met het oorspronkelijke wachtwoord gerekend dient te worden.


    Zet het maar eens in een loop:


    Dit levert bijvoorbeeld:



    Laten we het eens over een andere boeg gooien. Waaruit blijkt dat je login-functionaliteit niet werkt, je zegt dat je een melding krijgt dat de wachtwoorden niet overeenkomen? Het enige wat je hoeft te doen is te kijken wat password_verify() teruggeeft. Als dit true is, dan was het (oorspronkelijk) ingevoerde wachtwoord juist.


    De hashes verschillen als het goed is dus altijd, maar password_verify() toetst of deze gelijkwaardig zijn.

  • Onderstaand is te zien hoe het inlog script eruit ziet.
    Wanneer ik het wachtwoord test hash en dan probeer met onderstaande code werkt het inloggen naar behoren.


    Wanneer ik "if (password_verify('test', $hash)) {" aanpas naar "if (password_verify($gn['password'], $hash)) {" geeft de code aan Wachtwoord is fouttief.


    In het veld password (binnen SQL) wordt de hash van het wachtwoord weergegeven, in dit geval dus test.


    De hashes verschillen altijd van elkaar.

  • Okay, dat werkt misschien, maar dat verklaart niet waarom het voorheen niet werkte.


    Er begint mij al iets te dagen.


    Hoe was het wachtwoord opgeslagen in de database?
    Hoe luidt de kolomdefinitie voor deze wachtwoord-hash? (heeft deze genoeg ruimte?)
    Genereer je de hash (gegenereerd met behulp van het wachtwoord uit het loginformulier) op dezelfde manier als bij de opgeslagen wachtwoord-hash het geval was? Dat wil zeggen, met hetzelfde algoritme en ook dezelfde opties?
    Escape je de DATA-delen in de SQL-query met de daarvoor bestemde escaping-functies?
    Komen overal (database, database-connectie, formulier-data, HTML-bestand en -headers?) de gebruikte character encoderingen overeen?


    Het lijkt mij zeer belangrijk dat je niet alleen zorgt dat iets werkt, maar ook dat je snapt wat er gebeurt en daarmee ook kunt verklaren waarom het werkt. Simpelweg omdat iets werkt, maakt het nog niet juist.


    EDIT:
    De bovenstaande code lijkt mij onjuist. Het lijkt erop dat je een onversleuteld wachtwoord ophaalt uit de database en het wachtwoord uit je formulier hasht? Is dit niet de omgekeerde wereld? Het hele idee van password_hash() is juist dat je wachtwoorden versleuteld opslaat en deze daardoor nooit naar het origineel te herleiden zijn. In een loginformulier zou dus ook nooit password_hash() moeten voorkomen, maar enkel password_verify() waarbij je het wachtwoord (uit het formulier) verifieert aan de hand van de hash (uit de database).


    Daarnaast controleer je nog steeds niet of $inlog resultaten oplevert...


    Zorg eens voor wat debugging zodat je precies achterhaalt wat er misgaat? Dit lijkt mij nogal belangrijk.

  • Binnen de SQL database heb ik de volgende gegevens van de kolom: password varchar(200).


    Lijkt mij genoeg voor een versleuteld wachtwoord. aangezien het wachtwoord 60 karakters bevat.


    Bij het aanmelden of opvragen van het wachtwoord wordt het wachtwoord versleuteld door de hash. Bij het inloggen heb ik enkel de code password_verify() staan.


    Ja ik gebruik dezelfde algoritme en ook dezelfde opties.


    Ik begrijp je conclusie, ik begrijp wat de functies en functionaliteiten zijn. niet alleen omdat het nu functioneert maar ook waarom.


    Ik heb debugging uitgevoerd op alle connecties en data binnen het script. De mogelijkheid die ik nu heb toegepast werkt naar behoren. Waarom PASSWORD_BCRYPT niet werkt(te) ben ik nog niet uit.

  • Ik heb debugging uitgevoerd op alle connecties en data binnen het script. De mogelijkheid die ik nu heb toegepast werkt naar behoren. Waarom PASSWORD_BCRYPT niet werkt(te) ben ik nog niet uit.

    Maar heb je dat nu al in afzondering getest, zonder tussenkomst van een database?


    Het doel van debugging is mede om dingen uit te sluiten. Met een test die geen database gebruikt, dus gewoon een test met password_hash() i.c.m. PASSWORD_BCRYPT en password_verify() kun je uitsluiten of het nu echt hier aan ligt. En dit lijkt mij onwaarschijnlijk, omdat PASSWORD_DEFAULT standaard ook van bcrypt gebruik maakt. Dit kun je ook aan de hash zien, hier zit namelijk het algoritme en de cost in verwerkt. En dit kun je ook testen.



    PHP
    <?php
    // levert bijvoorbeeld $2y$10$zrgHKhyvih.WoEt5mB85X.zG1/TOOyN1xJURjQXhfTGis4JvbncbC
    echo password_hash('test', PASSWORD_DEFAULT);
    // levert bijvoorbeeld $2y$10$8EbRJ99.CHc0vkdinYD8uOuOiQ2ZETvzCIW6IT1NTvSrCvosOzXaO
    echo password_hash('test', PASSWORD_BCRYPT);
    ?>

    (NB in het bovenstaande fragment zijn het algoritme en de cost identiek, ondanks het feit dat je verschillende algoritme-constantes opgeeft)


    Voer deze test eens uit op jouw webserver en kijk of de algoritmes ($2y$) of de cost ($10$) van elkaar verschillen.


    En zelfs dat zou niet uit moeten maken, want de enige plaats waar je password_hash() gebruikt is bij het opslaan of wijzigen van het wachtwoord. Moet je wel deze zelfde hash als uitgangspunt nemen om het gehashde wachtwoord opnieuw te berekenen met password_verify() uiteraard. Dus als de bovenstaande test verschillende resultaten oplevert en je gebruikt dan een andere hash als waarmee de wachtwoord-hash is opgesteld... tja, dan ben je toch echt appels met peren aan het vergelijken.


    Dus, ik vermoed nog steeds dat er iets bij het opslaan of uitlezen van je database-data misgaat.


    Gewoon maar van algoritme wisselen omdat je niet weet wat er misgaat... weet niet of dat slim is :/.

  • @FangorN ik heb wel degelijk mijn testen uitgevoerd. zowel met en zonder tussenkomst van de database.


    Zonder database werkt het naar behoren, met database niet.


    Ik heb gecontroleerd welke waarden uit alle koppelingen komen, zowel van de gebruikersnaam als de wachtwoorden zonder hash en met hash.


    Het begin van de algoritmes en cost zijn beide $2y$10$.


    De login-functionaliteit was opgebouwd met md5, dus werkte hiermee naar behoren, ik bouw de functionaliteit om van md5 naar password_hash().


    @Ferhat.Remory Bedankt voor je opmerking dit heb ik inderdaad al eens getest en geeft geen verschil, gebruikersnaam wordt als 1 waarde opgepakt.



    Ik heb wel een aanpassing gedaan in het opslaan van het wachtwoord (hash) met de database, met de aanpassing wordt het wachtwoord opgeslagen en geeft de code voor het inloggen nu een goed resultaat.


    Bedankt voor jullie hulp.

  • Ik heb wel een aanpassing gedaan in het opslaan van het wachtwoord (hash) met de database, met de aanpassing wordt het wachtwoord opgeslagen en geeft de code voor het inloggen nu een goed resultaat.

    Wellicht interessant voor de kijkers thuis wat deze aanpassing nu precies was. Controleer je nu ook of je precies één resultaat hebt voordat je je query-resultaten ophaalt bij het inloggen? Het lijkt mij nogal belangrijk dat dit alles 100% correct geschiedt (vooral als het de veiligheid en beveiliging van je website betreft), hier enkel hash/verify saus overheen gooien lijkt mij onvoldoende. Misschien is het ook interessant om wat code te plaatsen hoe alles er nu ongeveer uitziet?


    En bottom line was dus (inderdaad) dat het geen probleem was met password_hash() / password_verify() maar een issue ergens onderweg met je database. Het is belangrijk dat dit soort "waarheidsvinding" op een goede en grondige manier gebeurt, want hier leer je gewoon het meeste van.

Participate now!

Heb je nog geen account? Registreer je nu en word deel van onze community!