password_verify werkt niet

    ICTscripters maakt gebruik van cookies. Door het gebruiken en browsen naar onze site gaat je automatisch akkoord met het gebruik van cookies. Klik hier voor meer informatie

    • 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 Source Code: Registratie

      1. $options = ['cost' => 12,];
      2. $passwordFromPost = $_POST['password'];
      3. $hash = password_hash($passwordFromPost, PASSWORD_BCRYPT, $options);




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

      PHP Source Code: Inloggen

      1. $loggie = ucfirst(strtolower($mysqli->real_escape_string(trim($_POST['gn']))));
      2. $ww = $mysqli->real_escape_string(trim($_POST['ww']));
      3. $inlog = $mysqli->query("SELECT * FROM `[users]` WHERE `login`='".$loggie."'");
      4. $gn = $inlog->fetch_array(MYSQLI_ASSOC);
      5. $passwordPost = $ww;
      6. $password = $gn['md5_wachtwoord'];
      7. if (password_verify($passwordPost, $password))
      8. {
      9. // Hier komt de code wanneer het werkt
      10. }
      11. else
      12. {
      13. // Hier komt de code wanneer het NIET werkt
      14. }
      Laat alles zien

      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 Source Code

      1. <?php
      2. $hash = password_hash('test', PASSWORD_BCRYPT, ['cost' => 12]);
      3. if (password_verify('test', $hash)) {
      4. echo 'cake';
      5. } else {
      6. echo 'no cake';
      7. }
      8. ?>[end]
      Hier zou:
      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 Source Code

      1. $hash = password_hash($ww, PASSWORD_BCRYPT, ['cost' => 12]);
      2. if (password_verify($password, $hash)) {
      3. echo 'Goed';
      4. } else {
      5. echo 'Fout '.$ww.' '.$hash.'';
      6. }


      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:

      PHP Source Code

      1. <?php
      2. for ($i=0; $i < 10; $i++) {
      3. $hash = password_hash('test', PASSWORD_BCRYPT, ['cost' => 12]);
      4. echo $hash.'<br>';
      5. if (password_verify('test', $hash)) {
      6. echo 'cake<br>';
      7. } else {
      8. echo 'no cake<br>';
      9. }
      10. }
      11. ?>[end]
      Laat alles zien

      Dit levert bijvoorbeeld:

      HTML Source Code

      1. $2y$12$Ge6qV1J4r9HjcTe4oIgzsO5ZIIyWTFMNQb676T.u638FKVBsDA.Xa
      2. cake
      3. $2y$12$XnzXjpNecdXnrvnRdIibGOK5cKPBPnDLz24GaGcnaRSgpT8rzTzla
      4. cake
      5. $2y$12$2G302P20vFq.SFuv5GrLw.6KeXVePjZE8Wg7HTalYdDv1stJXsKhK
      6. cake
      7. $2y$12$VLP2U1Tz1Cfxa37UkpNewe.QfGB4z.6QU9gilP4C/4dXKm7PhHf32
      8. cake
      9. $2y$12$5dNoalz/vcPZ4ZG8hLv6geu85yahCrPWu3AOz4TpjFEJZG4Cozj4y
      10. cake
      11. $2y$12$lgSfDga67v605rAqK5wghuhiRmfiY.GU.gTSI5Uf.i..1y9JkJSqi
      12. cake
      13. $2y$12$Z1owJcJNHdXUtE6S7S..zua9nXLhvmdig9Bs7To0IU1JEnmXj7wOm
      14. cake
      15. $2y$12$SFtBrblTprcYiTVtfifbAusvi1KcDVzyDuvcJsjDRMa8jTODWIX3.
      16. cake
      17. $2y$12$eg1prXKjujZiIpKoEdjbKe6UU7c6EfuNFRlTblhKqMGcdYH5Civ6O
      18. cake
      19. $2y$12$xg8RzhNVqkvYuls.M6tKTuZTmRkTxlMIvtBEN63hg233Vo4FRQzN.
      20. cake
      21. [end]
      Laat alles zien

      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.

      PHP Source Code

      1. <?
      2. if ( isset($_POST['login']) )
      3. {
      4. $loggie = ucfirst(strtolower($mysqli->real_escape_string(trim($_POST['gn']))));
      5. $ww = $_POST['ww'];
      6. $inlog = $mysqli->query("SELECT `login`,`banuren`, `md5_wachtwoord`, `password` FROM `[users]` WHERE `login`='".$loggie."'");
      7. $gn = $inlog->fetch_array(MYSQLI_ASSOC);
      8. $options = ['cost' => 12,];
      9. $hash = password_hash($ww, PASSWORD_BCRYPT, $options);
      10. if (password_verify('test', $hash)) {
      11. $melding = '<div class="img"><img src="'.$domein.'stylesheets/img/tick.png" alt="goed" /></div> Wachtwoord juist!';
      12. } else {
      13. $melding = '<div class="img"><img src="'.$domein.'stylesheets/img/cross.png" alt="foutief" /></div> Wachtwoord is fouttief! '.$hash.'';
      14. }
      15. }
      16. ?>
      17. <div id="login-error"><?=$melding;?></div>
      18. <div id="login-balk">
      19. <form method="post" action="<?=$domein;?>index.php">
      20. <div class="loginvak"><input class="user" name="gn" type="text" value="Gebruikersnaam" onfocus="if (this.value == 'Gebruikersnaam') {this.value = '';}" onblur="if (this.value == '') {this.value = 'Gebruikersnaam';}"/></div>
      21. <div class="loginvak"><input class="ww" name="ww" type="password" autocomplete="off" value="Wachtwoord" onfocus="if (this.value == 'Wachtwoord') {this.value = '';}" onblur="if (this.value == '') {this.value = 'Wachtwoord';}"/></div>
      22. <div class="loginvak"><button class="login" type="submit" name="login">Inloggen</button></div>
      23. </form>
      24. </div>
      Laat alles zien
    • 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.

      Post werd 3x aangepast, het laatst door FangorN ().