Question

This is my first attempt in securely storing passwords and I would like to make sure that everything is done correctly. I was advised to use SHA-256 hashing alongside salt.

Assuming user submitted their password thorough form, we get the password via

$password = $_POST["password"];

What is correct way to salt $password and use SHA-256 hashing on it, so it can than be stored in a password field "password CHAR(64)" in a database?

Once done and stored how would I than compare value stored in a database to one user entered in a login form? Lets assume $loginPassword = $_POST["loginPassword"]; is what user entered.

Was it helpful?

Solution

Instead of using SHA family methods, you can use the crypt() function to salt it for you.

Here is an example script (save and login) using PDO.

Save password in DB

<?php
// Set the password
$password = 'mypassword';

// Get the hash, letting the salt be automatically generated
$hash = crypt($password);

echo $hash; // for testing purposes only

$mysql_username = 'username'; // for DB
$mysql_password = 'password'; // for DB

$dbh = new PDO('mysql:host=localhost;dbname=database_name', $mysql_username, $mysql_password);

$stmt = $dbh->prepare("INSERT INTO table_name (name,pass) VALUES (:name,:pass)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':pass', $pass);

// insert rows
// $name = $_POST['name'];
// $name = $_POST['pass'];

$name = "username";
$pass = $hash;
$stmt->execute();

Login script

<?php
$mysql_username = 'username'; // for DB
$mysql_password = 'password'; // for DB

$dbh = new PDO('mysql:host=localhost;dbname=database_name', $mysql_username, $mysql_password);

/*
$username = $_POST['username'];
$password = $_POST['password'];
*/

$username = "username";
$password = "mypassword";

$sql = "SELECT * FROM table_name WHERE name=:username";
$statement = $dbh->prepare($sql);
$statement->bindValue(':username',$username,PDO::PARAM_STR);

if($statement->execute())
{
    if($statement->rowCount() == 1)
    {
        $row = $statement->fetch(PDO::FETCH_ASSOC);

 if (crypt($password, $row['pass']) === $row['pass'])

        {
            $username = $row['name'];
            $email = $row['email'];

echo "Stage 1";

echo "<hr noshade size=\"1\">";

echo "Hello " .$username;

            exit;
        }
        else
        {
            // include "error_login.php";

echo "Stage 2 - ERROR";

        }
    }
    else
    {
       // include "error_login.php";

echo "Stage 3 error";
    }
}

OTHER TIPS

If you're on PHP 5.5 or later, there's the built-in password_hash() and password_verify() with Bcrypt - if you're on PHP 5.3.7 or later, there's the password_compat compatibility library; all this is per the PHP.net Safe Password Hashing FAQ entry.

Essentially, on PHP 5.3.7 and above, replace the old crypt() with password_hash() and password_verify().

See my answer to PHP Secure password generation and storage for some more details on cost choice, but it boils down to the very simple:

<?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' => 12,
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options)."\n";
?>

to generate the hash, then you store the output string, and then verify with:

<?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.';
}
?>

Both examples come from the PHP.net Password Hashing page.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top