使用PHP 5.5的password_hash和password_verify函数

时间:2022-08-15 16:45:57

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)?

比如说,我想为用户存储一个密码,这是用PHP 5.5的password_hash()函数(或者这个版本的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
}

4 个解决方案

#1


59  

Ignoring the issues with your database statements for now, I'll answer the question regarding password_hash.

暂时忽略数据库语句的问题,我将回答关于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.

简而言之,不,你不是这样做的。您不希望单独存储salt,您应该同时存储散列和salt,然后使用这两个来验证密码。password_hash返回一个包含这两个字符串的字符串。

The password_hash function returns a string that contains both the hash and the salt. So:

password_hash函数返回一个包含散列和salt的字符串。所以:

$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

此外,正如评论所指出的,如果您对安全性感兴趣,您可能需要查看mysqli (PHP5.5不支持ext/mysql),以及本文关于SQL注入的文章:http://php.net/manual/en/security.database.sql-injection.php

#2


10  

Using your own salt is not recommended and, as of PHP 7, its use is deprecated. To understand why, read the author's thoughts

不建议使用您自己的salt,并且不建议使用PHP 7。要理解原因,请阅读作者的思想

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).

有一件事我已经非常清楚:选择食盐是危险的。我还没有见过任何一种使用salt的方法,这种方法甚至还不错。每种用法的范围从坏的(传递mt_rand()输出)到危险的(静态字符串)到疯狂的(传递密码作为它自己的salt)。

I've come to the conclusion that I don't think we should allow users to specify the salt.

我得出的结论是,我认为我们不应该允许用户指定盐。

#3


6  

Note this from php.net

从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.

在PHP 7.0.0中,salt选项已被弃用。现在它更倾向于使用默认生成的盐。

Conclusion? Forget about salt option.

结论?忘记盐的选择。

This would be quite enough password_hash('password', PASSWORD_DEFAULT) *(or _BCRYPT)

这就足够了password_hash('password'、PASSWORD_DEFAULT) *(或_BCRYPT)

#4


4  

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.

插入到数据库(或文件或其他你使用的)整个函数返回的字符串。它包含:算法id、代价id、salt(22字符)和哈希密码。

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.

使用password_verify()需要整个字符串。Salt是随机的,如果落入坏人之手(使用散列密码)也无妨。这可以防止(或非常困难)使用生成的密码列表和散列-彩虹表的现成集。

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)

您应该考虑添加成本参数。默认值(如果省略)是10——如果更高,那么函数计算哈希值就会更长。将生成散列所需的成本增加1倍(从而延长了破解密码所需的时间)

$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).

您应该根据服务器上的速度检查设置这个参数。建议该函数执行100ms+(有些人更喜欢250 ms)。通常成本= 10或11是个不错的选择(在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().

为了提高安全性,您可能需要在密码中添加一个长(50-60个字符是很好的选择)的秘密字符串。在使用password_hash()或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.

注意,对于algo参数使用PASSWORD_BCRYPT将导致密码参数被截断为72个字符。

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).

如果$password将大于72字符,并且您更改或添加了73或90个字符,哈希将不会更改。可选,粘贴$secret_string应该在末尾(在用户的密码之后,而不是之前)。

#1


59  

Ignoring the issues with your database statements for now, I'll answer the question regarding password_hash.

暂时忽略数据库语句的问题,我将回答关于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.

简而言之,不,你不是这样做的。您不希望单独存储salt,您应该同时存储散列和salt,然后使用这两个来验证密码。password_hash返回一个包含这两个字符串的字符串。

The password_hash function returns a string that contains both the hash and the salt. So:

password_hash函数返回一个包含散列和salt的字符串。所以:

$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

此外,正如评论所指出的,如果您对安全性感兴趣,您可能需要查看mysqli (PHP5.5不支持ext/mysql),以及本文关于SQL注入的文章:http://php.net/manual/en/security.database.sql-injection.php

#2


10  

Using your own salt is not recommended and, as of PHP 7, its use is deprecated. To understand why, read the author's thoughts

不建议使用您自己的salt,并且不建议使用PHP 7。要理解原因,请阅读作者的思想

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).

有一件事我已经非常清楚:选择食盐是危险的。我还没有见过任何一种使用salt的方法,这种方法甚至还不错。每种用法的范围从坏的(传递mt_rand()输出)到危险的(静态字符串)到疯狂的(传递密码作为它自己的salt)。

I've come to the conclusion that I don't think we should allow users to specify the salt.

我得出的结论是,我认为我们不应该允许用户指定盐。

#3


6  

Note this from php.net

从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.

在PHP 7.0.0中,salt选项已被弃用。现在它更倾向于使用默认生成的盐。

Conclusion? Forget about salt option.

结论?忘记盐的选择。

This would be quite enough password_hash('password', PASSWORD_DEFAULT) *(or _BCRYPT)

这就足够了password_hash('password'、PASSWORD_DEFAULT) *(或_BCRYPT)

#4


4  

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.

插入到数据库(或文件或其他你使用的)整个函数返回的字符串。它包含:算法id、代价id、salt(22字符)和哈希密码。

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.

使用password_verify()需要整个字符串。Salt是随机的,如果落入坏人之手(使用散列密码)也无妨。这可以防止(或非常困难)使用生成的密码列表和散列-彩虹表的现成集。

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)

您应该考虑添加成本参数。默认值(如果省略)是10——如果更高,那么函数计算哈希值就会更长。将生成散列所需的成本增加1倍(从而延长了破解密码所需的时间)

$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).

您应该根据服务器上的速度检查设置这个参数。建议该函数执行100ms+(有些人更喜欢250 ms)。通常成本= 10或11是个不错的选择(在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().

为了提高安全性,您可能需要在密码中添加一个长(50-60个字符是很好的选择)的秘密字符串。在使用password_hash()或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.

注意,对于algo参数使用PASSWORD_BCRYPT将导致密码参数被截断为72个字符。

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).

如果$password将大于72字符,并且您更改或添加了73或90个字符,哈希将不会更改。可选,粘贴$secret_string应该在末尾(在用户的密码之后,而不是之前)。