Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When do I need to use password_needs_rehash()?

I have a processing file for a login to an app. I either do not understand the purpose of password_needs_rehash() or it is not working. The login is authenticating and passing me through to the correct page. But I can't get the code to even echo the new hash.

Am I doing this correctly?

Does the if not throw a new hash because it does not need rehashed? If so when would a password need rehashed if it was properly hashed and stored in the DB?

My processing file is below:

$email = $_POST["li_email"];

try {
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    // set the PDO error mode to exception
    $stmt = $conn->query("SELECT * FROM users WHERE email='$email'");
    $stmt->execute();
    while($row=$stmt->fetch()){ //for each result, do the following
        $hash = $row['hash'];
        $userPassword = $_POST["li_password"];
        if (password_verify($userPassword, $hash)) {
            if ( password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12]) ) {
                $newhash = password_hash($userPassword, PASSWORD_DEFAULT, ['cost' => 12]);
                echo $newhash;
            }
        } else {
            header('Location: http://' . $_SERVER['HTTP_HOST'] . '?error=loginfailed');
            exit();
        }
    }
} catch(PDOException $e) {
    echo $sql . "<br>" . $e->getMessage();
}

$conn = null;

Thank you for the help!

like image 757
theRyanMark Avatar asked Oct 17 '22 18:10

theRyanMark


1 Answers

The function password_needs_rehash() only needs to be used if you change the $options which usually refers to the cost.

The more the cost, the more CPU time it takes to hash the password but the more difficult it becomes to crack it. If you change hosting or move over to a cloud based system where multiple computers can calculate the hash for you, you are able to increment it at your own discretion.

You only need to check if the password needs a rehash at user login, since password_verify() can still verify the password if you changed the $options. If password_needs_rehash() returns true at that point, use password_hash() with the new options and replace the old hash.

try {
  $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
  $stmt = $conn->prepare($sql = "SELECT * FROM users WHERE email=?"); // otherwise $sql is not defined in catch()

  if($stmt->execute([$_POST["li_email"]])){
    // preventing sql injection

    if(($data = $stmt->fetch()) != false){
      // only expecting 1 row from db since an email should be unique.

      if(password_verify($_POST["li_email"], $data['hash'])){
        // valid login

        if(password_needs_rehash($data['hash'], PASSWORD_DEFAULT, $options = ['cost' => 12])){
          $newhash = password_hash($_POST["li_email"], PASSWORD_DEFAULT, options);
          // store new hash in db.
        }
      } else {
        header('Location: http://' . $_SERVER['HTTP_HOST'] . '?error=loginfailed');
        exit();
      }
    } else {
      // no results
    }
  } else {
    // query failed
  }
} catch(PDOException $e) {
    echo $sql . "<br>" . $e->getMessage();
}
like image 171
Xorifelse Avatar answered Oct 20 '22 15:10

Xorifelse