Search code examples
phphtmlpassword-hash

php password_hash and password_verify issue


I try to understand how form, and password_hash and verify work. Here is the simple code that I wrote. The result that I get is "invalid Password"

What am I missing?

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
</head>

<body>

  <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" name="pwd"> 
Password: 
 <table> 
   <tr> 
     <td><input name="passwd" type="text"/></td> 
   </tr> 
   <tr> 
     <td align="center"><br/> 
      <input type="submit" name="submit_pwd" value="hash"/> 
     </td> 
   </tr> 
 </table>   
</form> 

<?php
$passwd = $_POST['passwd'];

echo "Password :   <BR>".$passwd."\n <BR>" ; 
echo "Hash     :   <BR>".$hash = password_hash($passwd, PASSWORD_DEFAULT).  "\n <BR>";

if (password_verify($passwd, $hash)) {
echo 'Password is valid!';
} else {
    echo 'Invalid password.';
} 

?>

</body>
</html>

Solution

  • Let me explain what is going (and not going) on here.

    What the following does...

    $hash = password_hash($passwd, PASSWORD_DEFAULT). "\n <BR>"
    

    is an assignment, where you're trying hash a password, which will also contain a line break, a space and a <BR> tag.

    Then, trying to verify if the entered password matches the entered password, and a line break, and a space and <BR>.

    • That would be pretty hard to do, wouldn't you agree?

    You should also be getting an undefined index notice about $passwd = $_POST['passwd'];, so wrap that whole code in a conditional statement using the named submit input.

    You will need to change your code to the following, while removing . "\n <BR>" entirely.

    if(isset($_POST['submit_pwd'])){
    
        $passwd = $_POST['passwd'];
    
        echo "Password :   <BR>".$passwd."\n <BR>" ; 
        echo "Hash     :   <BR>".$hash = password_hash($passwd, PASSWORD_DEFAULT);
    
    if (password_verify($passwd, $hash)) {
        echo 'Password is valid!';
    } else {
        echo 'Invalid password.';
       } 
    }
    

    Here's a simple test using MD5 as an example in order to prove this, (note I didn't use password_hash() here, since that produces a different hash and would be hard to actually prove the difference); code partially borrowed from http://php.net/manual/en/function.md5.php

    Keep in mind that MD5 produces the same hash value.

    $str_good = 'apple';
    $str_bad = 'apple'.  "\n <BR>";
    
    echo md5($str_good); // produces 1f3870be274f6c49b3e31a0c6728957f
    echo "<br>";
    echo md5($str_bad); // produces cb2a3d3161fcc99dcf5e4ccd3bfbb14c
    echo "<br>";
    
    if (md5($str_good) === '1f3870be274f6c49b3e31a0c6728957f') {
        echo "Would you like a green or red apple?";
    }
    

    You will notice that the assignment without the added . "\n <BR>" produces a different value than the other.

    • This is the same thing that is happening to your code here.

    "What am I missing?"

    • The question isn't about what is missing, but about what is too much.

    The fix is as simple as just removing . "\n <BR>" which is "what is too much".