如何在 PHP 中使用 Blowfish 创建和存储密码哈希

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4983697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 16:26:28  来源:igfitidea点击:

How to create and store password hashes with Blowfish in PHP

phpsecuritypasswordsblowfishcrypt

提问by

1) How do you create secure Blowfish hashes of passwords with crypt()?

1) 如何使用 crypt() 创建安全的 Blowfish 密码哈希?

$hash = crypt('somePassword', 'a$nGYCCmhrzjrgdcxjH$');

1a) What is the significance of "$2a"? Does it just indicate that the Blowfish algorithm should be used?
1b) What is the significance of "$07"? Does a higher value imply a more secure hash?
1c) What is the significance of "$nGYCCmhrzjrgdcxjH$"? Is this the salt that will be used? Should this be randomly generated? Hard-coded?

1a) “$2a”的意义是什么?它是否只是表明应该使用 Blowfish 算法?
1b) “$07”的意义是什么?更高的值是否意味着更安全的哈希?
1c) "$nGYCCmhrzjrgdcxjH$" 的意义是什么?这是要使用的盐吗?这应该是随机生成的吗?硬编码?

2) How do you store Blowfish hashes?

2) 你如何存储 Blowfish 哈希?

echo $hash;
//Output: a$nGYCCmhrzjrgdcxjH$$$$.xLJMTJxaRa12DnhpAJmKQw.NXXZHgyq

2a) What part of this should be stored in the database?
2b) What data type should be used for the column (MySQL)?

2a) 这其中的哪一部分应该存储在数据库中?
2b) 列(MySQL)应该使用什么数据类型?

3) How should one verify a login attempt?

3) 如何验证登录尝试?

采纳答案by xyphoid

You should store the entire output of crypt, there's not a lot of point in splitting it up, because you need to generate a new salt for each password you're hashing in any case. Using a fixed hidden salt as mentioned by Matt is wrong - the salt should be different for every hash.

您应该存储 crypt 的整个输出,拆分它没有什么意义,因为无论如何您都需要为每个要散列的密码生成一个新的盐。使用 Matt 提到的固定隐藏盐是错误的 - 每个散列的盐应该不同。

For more information see http://www.openwall.com/articles/PHP-Users-Passwords- I recommend using the phpass library because it handles generating a random salt for you, unlike crypt().

有关更多信息,请参阅http://www.openwall.com/articles/PHP-Users-Passwords- 我建议使用 phpass 库,因为它与 crypt() 不同,它可以为您生成随机盐。

回答by Matt

1a) Strength of encryption - requirement in the range of 4..31. See http://php.net/manual/en/function.crypt.php

1a) 加密强度 - 要求在 4..31 范围内。见http://php.net/manual/en/function.crypt.php

1b) See 1a

1b) 见 1a

1c) See 1a. 'salt' should not be random, or you would not be able to regenerate the same hash for a given input - see 3.

1c) 见 1a。'salt' 不应该是随机的,否则您将无法为给定的输入重新生成相同的散列 - 参见 3。

2a) Strictly speaking, everything except the hash (in case database is compromised). Also, store your salt in a file not accessible beneath the web server's document root and include it. Set it with the strictest permissions possible; ideally read only to web host service (e.g. apache), no write or execute privileges. Less strictly speaking, depends how defensive you wish to be against hackers. Not storing the salt just makes life more difficult; they still have to get the data being input to the algorithm right - but why make it easier?

2a) 严格来说,除散列外的所有内容(以防数据库遭到破坏)。此外,将您的盐存储在 Web 服务器的文档根目录下无法访问的文件中,并将其包含在内。使用最严格的权限设置它;理想情况下只读到 web 主机服务(例如 apache),没有写入或执行权限。不太严格地说,这取决于您希望如何防御黑客。不储存盐只会让生活变得更加困难;他们仍然需要正确地将数据输入到算法中——但为什么要让它更容易呢?

2b) VARCHAR(32) should be fine for blowfish, if not storing the hash

2b) VARCHAR(32) 应该适合河豚,如果不存储哈希

3) Assuming you've already run the proper injection prevention code, etc.. so please don't just copy the below blindly(and ideally use PDO instead of mysql extension). The below is specific to blowfish, SHA-256 and SHA-512 which all return the salt within the hash. Would need modification for other algorithms...

3) 假设您已经运行了正确的防止注入代码等。所以请不要盲目复制以下内容(最好使用 PDO 而不是 mysql 扩展)。以下特定于河豚、SHA-256 和 SHA-512,它们都返回散列中的盐。需要修改其他算法...

//store this in another file outside web directory and include it
$salt = 'a$somevalidbutrandomchars$'

...

//combine username + password to give algorithm more chars to work with
$password_hash = crypt($valid_username . $valid_password, $salt)

//Anything less than 13 chars is a failure (see manual)
if (strlen($password_hash) < 13 || $password_hash == $salt)
then die('Invalid blowfish result');

//Drop the salt from beginning of the hash result. 
//Note, irrespective of number of chars provided, algorithm will always 
//use the number defined in constant CRYPT_SALT_LENGTH
$trimmed_password_hash = substring($password_hash, CRYPT_SALT_LENGTH);
mysql_query("INSERT INTO `users` (username,p assword_hash) VALUES '$valid_username', '$trimmed_password_hash'");

...

$dbRes = mysql_query("SELECT password_hash FROM `users` WHERE username = '$user_input_username' LIMIT 1");
//re-apply salt to output of database and re-run algorithm testing for match
if (substring($salt, CRYPT_SALT_LENGTH) . mysql_result($dbRes, 0, 'password_hash') ) ===
        crypt($user_input_username . $user_input_password, $salt) ) {
    //... do stuff for validated user
}