0

I have a script code to login.

Unfortunately this using sha1 is no longer recommended. I tried to change it to password_hash() but it failed.

Original

public static function create($username, $password)
{
    $q = self::$db->prepare('INSERT INTO user(username, password, email) VALUES (:username, :password, :email)');

    return $q->execute(array(
        ':username' => $username,
        ':password' => sha1($password),
        ':email'    => $email,
    ));
}

Edit

public static function create($username, $password)
{
    $q = self::$db->prepare('INSERT INTO user(username, password, email) VALUES (:username, :password, :email)');

    $new_password = password_hash($password, PASSWORD_DEFAULT);

    return $q->execute(array(
        ':username' => $username,
        ':password' => $new_password,
        ':email'    => $email,
    ));
}

What's wrong with it?

Norax
  • 111
  • 7

1 Answers1

3

Congratulations on changing away from an ancient, insecure algorithm!!

I have some information on how to use password_hash in my answer to PHP Secure password generation and storage, but the essence of it is copied below:

In particular, you can hash the password with a high enough cost (pick a cost that takes just long enough that under your expected maximum load, your site will be not quite CPU bound) - like in password_hash Example 2, but with an updated work factor :

<?php
/**
 * In this case, we want to increase the default cost for BCRYPT to 12.
 * Note that we also switched to BCRYPT, which will always be 60 characters.
 */
$options = [
    'cost' => 14,
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options)."\n";
?>

Then you store the string it returns, which includes a cryptographically generated random salt and the work factor you set - increase the work factor as much as you can, based on the login rate at peak times compared to CPU power, remembering that at peak, all your cores can work in parallel, since they'd each be hashing for a different user!

To verify, retrieve the string it returned from wherever you stored it (i.e. your database) and compare with the password_verify example:

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

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

As always, if you want details, please read Thomas Pornin's canonical answer to How to securely hash passwords - but the PHP 5.5 password functions use Bcrypt, so you can just use a high enough cost.

Anti-weakpasswords
  • 2,604
  • 20
  • 25