PHP password_hash(), default or custom salt? [duplicate] - php

This question already has answers here:
Using PHP 5.5's password_hash and password_verify function
(4 answers)
Closed 7 years ago.
I am thinking of using password_hash() function to encrypt user passwords. I understand that this function generates salt by default if you don't provide it, and it is even encouraged to use the default salt instead of your own. I am currently weighing in 3 options and can't decide which one to go with so I'd appreciate it if you could help me out.
1. option: password_hash() with default salt
$passwordInput = $_POST['password'];
$passwordHash = password_hash($passwordInput, PASSWORD_BCRYPT);
//INSERT $passwordHash INTO DATABASE
2. option: password_hash() with custom salt
$options = ['salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM)];
$passwordInput = $_POST['password'];
$passwordHash = password_hash($passwordInput, PASSWORD_BCRYPT, $options);
//INSERT $passwordHash INTO DATABASE
3. option: not using password_hash() at all
I am basing this option on a post from 2014: The definitive guide to form-based website authentication. Basically if it is a more secure approach than password_hash() I'd use something like this:
$salt = uniqid(rand(0, 1000000);
$passwordInput = $_POST['password'];
$password = hash('sha512', $salt . $passwordInput);
//INSERT $password AND $salt INTO DATABASE SEPARATELY

The really short answer to this question is to use password_hash() with the default salt (your first option), custom salt is deprecated in PHP7 because, to quote php.net:
The salt option for the password_hash() function has been deprecated to prevent developers from generating their own (usually insecure) salts. The function itself generates a cryptographically secure salt when no salt is provided by the developer - therefore custom salt generation should not be needed.
By the same token, your third option, hash() should be avoided as again you'll need to generate your own salt.

Related

Verifying salted MD5 passwords in a Bcrypt form [duplicate]

Say I wanted to store a password for a user, would this be the right way to do it with PHP 5.5's password_hash() function (or this version for PHP 5.3.7+: https://github.com/ircmaxell/password_compat)?
$options = array("cost" => 10, "salt" => uniqid());
$hash = password_hash($password, PASSWORD_BCRYPT, $options);
Then I would do:
mysql_query("INSERT INTO users(username,password, salt) VALUES($username, $hash, " . $options['salt']);
To insert into database.
Then to verify:
$row = mysql_fetch_assoc(mysql_query("SELECT salt FROM users WHERE id=$userid"));
$salt = $row["salt"];
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10, "salt" => $salt));
if (password_verify($password, $hash) {
// Verified
}
Ignoring the issues with your database statements for now, I'll answer the question regarding password_hash.
In short, no, that is not how you do it. You do not want to store the salt alone, you should be storing both the hash and salt, and then using both to verify the password. password_hash returns a string containing both.
The password_hash function returns a string that contains both the hash and the salt. So:
$hashAndSalt = password_hash($password, PASSWORD_BCRYPT);
// Insert $hashAndSalt into database against user
Then to verify:
// Fetch hash+salt from database, place in $hashAndSalt variable
// and then to verify $password:
if (password_verify($password, $hashAndSalt)) {
// Verified
}
Additionally, as the comments suggest, if you're interested in security you may want to look at mysqli (ext/mysql is deprecated in PHP5.5), and also this article on SQL injection: http://php.net/manual/en/security.database.sql-injection.php
Using your own salt is not recommended and, as of PHP 7, its use is deprecated. To understand why, the author of password_hash shared these thoughts (link defunct)
One thing has become abundantly clear to me: the salt option is
dangerous. I've yet to see a single usage of the salt option that has
been even decent. Every usage ranges from bad (passing mt_rand()
output) to dangerous (static strings) to insane (passing the password
as its own salt).
I've come to the conclusion that I don't think we should allow users
to specify the salt.
He even made this comment in SO chat noting how bad passing your own salt can be
Note this from php.net
Warning
The salt option has been deprecated as of PHP 7.0.0. It is now
preferred to simply use the salt that is generated by default.
Conclusion? Forget about salt option.
This would be quite enough password_hash('password', PASSWORD_DEFAULT) *(or _BCRYPT)
You should not enter own salt, leave salt empty, function will generate good random salt.
Insert into database (or file or whatever you use) whole the string returned by the function. it contains:
id of algorithm, cost, salt (22 chars) and hash password.
The entire string is required to use password_verify (). Salt is random and does not harm to fall into the wrong hands (with hashed password). This prevents (or very difficult) to use ready sets generated lists of passwords and hashes - rainbow tables.
You should consider add cost parameter. Default (if omitted) is 10 - if higher then function compute hash longer. Increasing the cost by 1, double time needed to generate a hash (and thus lengthen the time it takes to break password)
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10));
you should set this parameter based on speed check on your server. It is recommended that the function performed 100ms+ (some prefer to make it 250 ms). Usually cost = 10 or 11 is a good choice (in 2015).
To increase security, you might want to add to passwords a long (50-60 characters is good choice) secret string. before you use password_hash() or password_verify().
$secret_string = 'asCaahC72D2bywdu##$##$234';
$password = trim($_POST['user_password']) . $secret_string;
// here use password_* function
Caution
Using the PASSWORD_BCRYPT for the algo parameter, will result in the password parameter being truncated to a maximum length of 72 characters.
If $password will be longer than 72 chars and you change or add 73 or 90 characters hash will not change. Optional, sticking $secret_string should be at the end (after the user's password and not before).

What way is the best way to hash a password? [duplicate]

This question already has answers here:
Secure hash and salt for PHP passwords
(14 answers)
Closed 9 years ago.
I'm working on a website that should be very safe for the users, so I need the hash the passwords. Usually I'm using the MD5, but I read that it doesn't safe anymore. So I tried PHPass, but then I read that it also has been cracked. So I tried password_hash() of PHP 5.5, but I use HostGator, and the PHP there is 5.4. Also I want to be able to add salt without knowing it (like time() * userid()), like in the password_hash().
The hash strength is very important to me because I want to be 100% sure that my users are safe. So is there a way that very safe and not something like SHA that will be hacked soon?
Use this library which provides forward compatibility with the password_* functions.
Example usage :
require_once("password.php"); // imports the library, assuming it's in the same directory as the current script
$password = "HelloStackOverflow"; // example password
$hash = password_hash($password, PASSWORD_BCRYPT); // here's the hash of the previous password
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10)); // you can set the "complexity" of the hashing algorithm, it uses more CPU power but it'll be harder to crack, even though the default is already good enough
if (password_verify($password, $hash)) { // checking if a password is valid
/* Valid */
} else {
/* Invalid */
}
PHP comes with built-in hash algorithms such as MD5, SHA1 etc. However, from a security perspective, it's not recommended to use these functions to hash passwords as they can be easily broken via bruteforce attack using tools like Passwordpro.
It's better if you use salting as a way to secure your passwords. Below is an example :
$password = 'yourpassword';
$salt = 'randomstr!ng';
$password = md5($salt.$password);
An even better way of generating the salt is by hashing it first:
$password = 'yourpassword';
$salt = sha1(md5($password));
$password = md5($password.$salt);
The advantage is that this way the salt value is random and it changes for each password, making it nearly impossible to break.
Take a look at http://php.net/manual/de/function.crypt.php
You should consider using salts to prevent rainbow table attacks
You can find a tutorial here: http://www.yiiframework.com/wiki/425/use-crypt-for-password-storage/
I tink that the best thing is using a library to manage passwords.
If you cannot use php 5.5 you can try this library that works for php5.3+, have a look at this project:
http://rchouinard.github.io/phpass/

How do I update my security in my login script from MD5 to something more secure? [duplicate]

This question already has answers here:
How do you use bcrypt for hashing passwords in PHP? [duplicate]
(11 answers)
Closed 9 years ago.
I have a PHP login script with salt on the database, but in my register script I see:
$qry = "INSERT INTO accounts(username, firstname, lastname, password) " .
VALUES('$username','$fname','$lname','" . md5($_POST['password']) . "')";
and for the login:
$qry="SELECT * FROM accounts WHERE username='$username' AND password='" .
md5($_POST['password']) . "'";
Is there some code that can replace the MD5? Something more secure?
I've heard of SHA1 or something.
Short answer
Use bcrypt not md5 or sha1
Longer answer
Using the crypt() is hard. There is a new PHP password hashing API coming in PHP version 5.5, you can read about it here:
https://gist.github.com/nikic/3707231
It uses bcrypt and makes the whole process very easy. Of course php 5.5 isn't ready yet, so in the meantime there is a library to provide this new API right now:
https://github.com/ircmaxell/password_compat
Edit: See this thread for a much more thorough answer on the topic:
How do you use bcrypt for hashing passwords in PHP?
In consideration of #jszbody post, you should also update your password field to tell you want scheme you're using.
Where you have an MD5 hash now, you might have just "BAC232BC1334DE" or something.
When you go to SHA or whatever, you should change it to: "SHA:YOURSHAHASHHERE".
Because you can't change any of your existing passwords right now. This will make it more backward compatible, since now you can support both schemes.
Since you get the original password during login, you can dynamically upgrade your passwords in place as people login.
You get your user record, check the password. If there is no scheme, use MD5, and compare passwords. If they're correct (i.e. they can log in), you can update their old MD5 password to the new SHA password.
Also, it seems you are not salting your passwords. You must salt your passwords so that when Mary Sue uses "ilovekittens" for her password, and Big Jake Mahoney uses "ilovekittens" as his password, you don't get the same has for identical passwords.
You can store the salt in the password as well: "SHA:RANDOMSALTCHARACTERS:YOURSALTEDHASHHERE".
Salting is highly recommended. Unsalted, it pretty much doesn't matter a whole lot what scheme you use.
Try using the following class:
<?php
class PassHash {
// blowfish
private static $algo = '$2a';
// cost parameter
private static $cost = '$31';
// mainly for internal use
public static function unique_salt() {
return substr(sha1(mt_rand()),0,22);
}
// this will be used to generate a hash
public static function hash($password) {
return crypt($password,
self::$algo .
self::$cost .
'$' . self::unique_salt());
}
// this will be used to compare a password against a hash
public static function check_password($hash, $password) {
$full_salt = substr($hash, 0, 29);
$new_hash = crypt($password, $full_salt);
return ($hash == $new_hash);
}
}
?>
include it in your page with the following:
include_once('passhash.class.php');
Hash the password by:
PassHash::hash("test");
And check it with:
if (PassHash::check_password($databasepassword, $formpassword)){
// do stuff
}
This function uses Blowfish encryption. For more information on Blowfish goto PHP.net/crypt
Blowfish is considered the most effective yet most powerfull way of encrypting passwords. Do not use MD5 or SHA1 without using a salt!

Using PHP 5.5's password_hash and password_verify function

Say I wanted to store a password for a user, would this be the right way to do it with PHP 5.5's password_hash() function (or this version for PHP 5.3.7+: https://github.com/ircmaxell/password_compat)?
$options = array("cost" => 10, "salt" => uniqid());
$hash = password_hash($password, PASSWORD_BCRYPT, $options);
Then I would do:
mysql_query("INSERT INTO users(username,password, salt) VALUES($username, $hash, " . $options['salt']);
To insert into database.
Then to verify:
$row = mysql_fetch_assoc(mysql_query("SELECT salt FROM users WHERE id=$userid"));
$salt = $row["salt"];
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10, "salt" => $salt));
if (password_verify($password, $hash) {
// Verified
}
Ignoring the issues with your database statements for now, I'll answer the question regarding password_hash.
In short, no, that is not how you do it. You do not want to store the salt alone, you should be storing both the hash and salt, and then using both to verify the password. password_hash returns a string containing both.
The password_hash function returns a string that contains both the hash and the salt. So:
$hashAndSalt = password_hash($password, PASSWORD_BCRYPT);
// Insert $hashAndSalt into database against user
Then to verify:
// Fetch hash+salt from database, place in $hashAndSalt variable
// and then to verify $password:
if (password_verify($password, $hashAndSalt)) {
// Verified
}
Additionally, as the comments suggest, if you're interested in security you may want to look at mysqli (ext/mysql is deprecated in PHP5.5), and also this article on SQL injection: http://php.net/manual/en/security.database.sql-injection.php
Using your own salt is not recommended and, as of PHP 7, its use is deprecated. To understand why, the author of password_hash shared these thoughts (link defunct)
One thing has become abundantly clear to me: the salt option is
dangerous. I've yet to see a single usage of the salt option that has
been even decent. Every usage ranges from bad (passing mt_rand()
output) to dangerous (static strings) to insane (passing the password
as its own salt).
I've come to the conclusion that I don't think we should allow users
to specify the salt.
He even made this comment in SO chat noting how bad passing your own salt can be
Note this from php.net
Warning
The salt option has been deprecated as of PHP 7.0.0. It is now
preferred to simply use the salt that is generated by default.
Conclusion? Forget about salt option.
This would be quite enough password_hash('password', PASSWORD_DEFAULT) *(or _BCRYPT)
You should not enter own salt, leave salt empty, function will generate good random salt.
Insert into database (or file or whatever you use) whole the string returned by the function. it contains:
id of algorithm, cost, salt (22 chars) and hash password.
The entire string is required to use password_verify (). Salt is random and does not harm to fall into the wrong hands (with hashed password). This prevents (or very difficult) to use ready sets generated lists of passwords and hashes - rainbow tables.
You should consider add cost parameter. Default (if omitted) is 10 - if higher then function compute hash longer. Increasing the cost by 1, double time needed to generate a hash (and thus lengthen the time it takes to break password)
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10));
you should set this parameter based on speed check on your server. It is recommended that the function performed 100ms+ (some prefer to make it 250 ms). Usually cost = 10 or 11 is a good choice (in 2015).
To increase security, you might want to add to passwords a long (50-60 characters is good choice) secret string. before you use password_hash() or password_verify().
$secret_string = 'asCaahC72D2bywdu##$##$234';
$password = trim($_POST['user_password']) . $secret_string;
// here use password_* function
Caution
Using the PASSWORD_BCRYPT for the algo parameter, will result in the password parameter being truncated to a maximum length of 72 characters.
If $password will be longer than 72 chars and you change or add 73 or 90 characters hash will not change. Optional, sticking $secret_string should be at the end (after the user's password and not before).

Php Mysql Secure Password Store [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do you use bcrypt for hashing passwords in PHP?
What is the secure way or hash function to store password to Mysql Database? Now I'm using this sha1() function to store my password to DB with following code. Is it really Safe?
<?php
$pass = 123456789;
$pass = sha1($pass);
echo $pass;
?>
Thanks for your advise.
Update
I see salt is something like this.
$salt = "this is a salt";
$password = 'this is an password';
$hash = sha1($salt.$password);
So, Can i use any number/random number/something to $salt value? After that is it Now SAFE?
The SHA* variants should not be used for password hashing. Use the Blowfish algorithm and the crypt() function.
phpass is a PHP password hashing library that can simplify this for you.
You could also do more research on the topic and write some code to generate your own Bcrypt/Blowfish compatible Salts and use crypt() directly, rather than using the phpass library.
The best (and recommended) way of hashing passwords in PHP is using crypt().
Here's a simple example from the PHP documentation:
$hashed_password = crypt('mypassword');
// now store $hashed_password in the database
Later, to check an entered password (assuming $user_input is the entered password):
// retrieve $hashed_password from the database, then:
if (crypt($user_input, $hashed_password) == $hashed_password) {
echo "Password verified!";
}
Note that in this example (above) the salt is automatically generated when the password is first hashed. This is dangerous and should be avoided. A pseudo-random salt should be provided and could be generated like so:
$salt = substr(str_replace('+', '.', base64_encode(pack('N4', mt_rand(), mt_rand(), mt_rand(), mt_rand()))), 0, 22);
For a much better explanation, see the Stack Overflow question linked by citricsquid.
You cannot use a random value for salt, since you wont be able to compare the inputed password and the one stored in database afterwards.
You encryption is mainly ok, but you can go real crazy if you want...
<?php
$salt = "fF#$GGG$T##4309g9jERGWrgrew#GH";
$pepper = "vV###V90Ù39009gfjigwjorn)(";
$pass = "123456789";
$pass = $salt.$pass.$pepper;
for ($i=0;$i<40;$i++){
$pass = hash("sha256", $pass)
}
echo $pass;
?>

Categories