Rectangle 27 1

php How can I store my users' passwords safely?


<?php
// $hash is what you would store in your database
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]);

// $hash would be the $hash (above) stored in your database for this user
$checked = password_verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}
<?php
require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hash (above) stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}
<?php
use Netsilik/Lib/PepperedPasswords;

// Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper).
$config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF');

$hasher = new PepperedPasswords($config['pepper']);

// $hash is what you would store in your database
$hash = $hasher->hash($_POST['password']);

// $hash would be the $hash (above) stored in your database for this user
$checked = $hasher->verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}
Netsilik/PepperedPasswords

do not use MD5 or SHA1 anymore

  • WordPress 2.5+ as well as bbPress

(In case you are still using legacy 5.3.7 or newer you can install ircmaxell/password_compat to have access to the build-in functions)

Because security tends to be a lot more complicated and with more invisible screw up possibilities than most programmers could tackle alone, using a standard library is almost always easiest and most secure (if not the only) available option.

Currently, using crypt, with CRYPT_BLOWFISH is the best practice. CRYPT_BLOWFISH in PHP is an implementation of the Bcrypt hash. Bcrypt is based on the Blowfish block cipher, making use of it's expensive key setup to slow the algorithm down.

Example of code using PHP's password API:

Example of code using phpass (v0.2):

Good answer - thanks. phpass is a good option. But note that the "standard libraries" in some popular frameworks and apps are bad. See e.g. the horrid story of the MySQL OLD_PASSWORD cryptanalysis? and the sad story of their bad replacement: Looking for example of well-known app using unsalted hashes - IT Security The latter link has other examples of bad standard password functions.

If you are using PHP version 5.5.0 or newer, you can use the new simplified password hashing API

If you want extra security, the security folks now (2017) recommend adding a 'pepper' to the (automatically) salted password hashes.

MD5 and SHA1 are not broken in general (though they have some weaknesses, and for general purpose hashing SHA-2 should be used instead), they are just too fast to avoid bruteforce/dictionary password attacks (as SHA-2 and probably SHA-3, too).

Please note: you should not be needing this anymore! This is only here for historical purposes.

Take a look at: Portable PHP password hashing framework: phpass and make sure you use the CRYPT_BLOWFISH algorithm if at all possible.

The easiest way to get your password storage scheme secure is by using a standard library.

The good thing is that you do not need to worry about the details, those details have been programmed by people with experience and reviewed by many folks on the internet.

There is a simple, drop in class that securely implements this pattern, I recommend: Netsilik/PepperedPasswords (github). It comes with a MIT License, so you can use it however you want, even in proprietary projects.

Yes, yes, a thousand times yes.

Note
Rectangle 27 1

php How can I store my users' passwords safely?


<?php
// $hash is what you would store in your database
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]);

// $hash would be the $hash (above) stored in your database for this user
$checked = password_verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}
<?php
require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hash (above) stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}
<?php
use Netsilik/Lib/PepperedPasswords;

// Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper).
$config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF');

$hasher = new PepperedPasswords($config['pepper']);

// $hash is what you would store in your database
$hash = $hasher->hash($_POST['password']);

// $hash would be the $hash (above) stored in your database for this user
$checked = $hasher->verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}
Netsilik/PepperedPasswords

do not use MD5 or SHA1 anymore

  • WordPress 2.5+ as well as bbPress

(In case you are still using legacy 5.3.7 or newer you can install ircmaxell/password_compat to have access to the build-in functions)

Because security tends to be a lot more complicated and with more invisible screw up possibilities than most programmers could tackle alone, using a standard library is almost always easiest and most secure (if not the only) available option.

Currently, using crypt, with CRYPT_BLOWFISH is the best practice. CRYPT_BLOWFISH in PHP is an implementation of the Bcrypt hash. Bcrypt is based on the Blowfish block cipher, making use of it's expensive key setup to slow the algorithm down.

Example of code using PHP's password API:

Example of code using phpass (v0.2):

Good answer - thanks. phpass is a good option. But note that the "standard libraries" in some popular frameworks and apps are bad. See e.g. the horrid story of the MySQL OLD_PASSWORD cryptanalysis? and the sad story of their bad replacement: Looking for example of well-known app using unsalted hashes - IT Security The latter link has other examples of bad standard password functions.

If you are using PHP version 5.5.0 or newer, you can use the new simplified password hashing API

If you want extra security, the security folks now (2017) recommend adding a 'pepper' to the (automatically) salted password hashes.

MD5 and SHA1 are not broken in general (though they have some weaknesses, and for general purpose hashing SHA-2 should be used instead), they are just too fast to avoid bruteforce/dictionary password attacks (as SHA-2 and probably SHA-3, too).

Please note: you should not be needing this anymore! This is only here for historical purposes.

Take a look at: Portable PHP password hashing framework: phpass and make sure you use the CRYPT_BLOWFISH algorithm if at all possible.

The easiest way to get your password storage scheme secure is by using a standard library.

The good thing is that you do not need to worry about the details, those details have been programmed by people with experience and reviewed by many folks on the internet.

There is a simple, drop in class that securely implements this pattern, I recommend: Netsilik/PepperedPasswords (github). It comes with a MIT License, so you can use it however you want, even in proprietary projects.

Yes, yes, a thousand times yes.

Note
Rectangle 27 1

php How can I store my users' passwords safely?


<?php
var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT));

$options = array(
    'cost' => 7, // this is the number of rounds for bcrypt
    // 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended
);
var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options));
?>
password_hash
string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."
var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));

var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));

As you might see, the string contains the salt as well as the cost that was specified in the options. It also contains the algorithm used.

I hope that providing these built-in functions will soon provide better password security in case of data theft, as it reduces the amount of thought the programmer has to put into a proper implementation.

In most cases it is better to omit the salt parameter. The function creates a salt from the random source of the operating system, there is very little chance that you can provide a better salt on your own.

Most examples show how to add both parameters, even when it is not recommended to add a salt, so i wonder why? And to be honest, i read only the comment behind the code, not on the next line. Anyway, wouldn't it be better when the example shows how to use the function best?

That's what I wrote, didn't I? "if no salt is specified, it is randomly generated, for that reason it is preferable to not specify a salt"

Therefore, when checking the password (for example when the user logs in), when using the complimentary password_verify() function it will extract the necessary crypto parameters from the password hash itself.

When not specifying a salt, the generated password hash will be different upon every call of password_hash() because the salt is generated randomly. Therefore comparing a previous hash with a newly generated one will fail, even for a correct password.

With PHP 5.5 (what I describe is available to even earlier versions, see below) around the corner I'd like to suggest to use its new, built-in solution: password_hash() and password_verify(). It provides several options in order to achieve the level of password security you need (for example by specifying a "cost" parameter through the $options array)

how should i check if the saved password and entered password are the same?i am using password_hash() and password_verify no matter what password(correct or not) i used i end up with correct password

Note
Rectangle 27 1

php How can I store my users' passwords safely?


<?php
var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT));

$options = array(
    'cost' => 7, // this is the number of rounds for bcrypt
    // 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended
);
var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options));
?>
password_hash
string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."
var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));

var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));

As you might see, the string contains the salt as well as the cost that was specified in the options. It also contains the algorithm used.

I hope that providing these built-in functions will soon provide better password security in case of data theft, as it reduces the amount of thought the programmer has to put into a proper implementation.

In most cases it is better to omit the salt parameter. The function creates a salt from the random source of the operating system, there is very little chance that you can provide a better salt on your own.

Most examples show how to add both parameters, even when it is not recommended to add a salt, so i wonder why? And to be honest, i read only the comment behind the code, not on the next line. Anyway, wouldn't it be better when the example shows how to use the function best?

That's what I wrote, didn't I? "if no salt is specified, it is randomly generated, for that reason it is preferable to not specify a salt"

Therefore, when checking the password (for example when the user logs in), when using the complimentary password_verify() function it will extract the necessary crypto parameters from the password hash itself.

When not specifying a salt, the generated password hash will be different upon every call of password_hash() because the salt is generated randomly. Therefore comparing a previous hash with a newly generated one will fail, even for a correct password.

With PHP 5.5 (what I describe is available to even earlier versions, see below) around the corner I'd like to suggest to use its new, built-in solution: password_hash() and password_verify(). It provides several options in order to achieve the level of password security you need (for example by specifying a "cost" parameter through the $options array)

how should i check if the saved password and entered password are the same?i am using password_hash() and password_verify no matter what password(correct or not) i used i end up with correct password

Note
Rectangle 27 1

php How can I store my users' passwords safely?


The Nettuts+ is a very bad article to use as a model - it includes use of MD5 which can be brute forced very easily even with salt. Instead, just use the PHPass library which is far, far better than any code you may find on a tutorial site, i.e. this answer: stackoverflow.com/questions/1581610/

There is a good article about security in PHP at Nettuts+, password salting is also mentioned. Maybe you should take a look at: net.tutsplus.com/tutorials/php/

Your users will be much safer if you used parameterized queries instead of concatenating SQL statements. And the salt should be unique for each user and should be stored along with the password hash.

Note
Rectangle 27 1

php How can I store my users' passwords safely?


The Nettuts+ is a very bad article to use as a model - it includes use of MD5 which can be brute forced very easily even with salt. Instead, just use the PHPass library which is far, far better than any code you may find on a tutorial site, i.e. this answer: stackoverflow.com/questions/1581610/

There is a good article about security in PHP at Nettuts+, password salting is also mentioned. Maybe you should take a look at: net.tutsplus.com/tutorials/php/

Your users will be much safer if you used parameterized queries instead of concatenating SQL statements. And the salt should be unique for each user and should be stored along with the password hash.

Note