我知道这里的问题已经在很多次上被问到了,但是在每个问题下都有建议将这些事情告诉知道自己在做什么的人。 (所以我们也可以了解我们在做什么)
此外,我无法通过更新的php函数找到足够令人满意的示例..
所以这是我正在为一个开源项目开发的哈希类。我有4个步骤
我不确定的部分是密钥长度,我应该使用另一个base64编码以防止sha256 的原始字节问题,并且生成的哈希是否正确直接插入mysql的格式。
此类使用本身的安全性。
这是班级:
<?php
namespace shotwn\lazywork;
/**
* add manual here
* pepper is a static server-side key, generated with hash_hmac sha256 and random keys
*
* cholesterol is a random, 22digit?(need more?) database stored key which has been used as salt with
* hash_hmac sha256
*
* main structure is
* password_hash(hash_hmac(sha256, hash_hmac(sha256, base64_encode(password), pepper),cholesterol))
*
*/
class PasswordKitchen {
private static $password_pepper;
function __construct() {
try {
self::$password_pepper = include "/../.nope/biber.key";
} catch (Exception $e) {
throw new Exception("No pepper key");
}
}
private function season(string $password, string $cholesterol = null) {
//use site-wide password pepper
$password_safe = base64_encode ($password);
if(isset($cholesterol) && $cholesterol != null) {
$password_cholesterol = $cholesterol;
} else {
$password_cholesterol = substr(base64_encode(openssl_random_pseudo_bytes(17)),0,22);; //will be user-based mysql recorded
$password_cholesterol = str_replace("+",".",$password_cholesterol);
}
$password_with_pepper = hash_hmac("sha256",$password_safe,self::$password_pepper);
$password_with_pepper_and_cholesterol = hash_hmac("sha256",$password_with_pepper,$password_cholesterol);
$seasonedPassword = (array) [
"password_w_PaC" => $password_with_pepper_and_cholesterol,
"password_cholesterol" => $password_cholesterol,
];
return $seasonedPassword;
}
public function hash(string $password, $cost = 16) {
$options = [
'cost' => $cost, //change for admin accounts
];
$seasoning = $this->season($password);
$seasoned_password = $seasoning["password_w_PaC"];
$password_cholesterol = $seasoning["password_cholesterol"];
$passwordHash = password_hash($seasoned_password, PASSWORD_DEFAULT);
return (array) [
"hash" => $passwordHash,
"cholesterol" => $password_cholesterol,
];
}
public function validate(string $password, string $cholesterol, string $hash) {
$seasonThePassword = $this->season($password, $cholesterol);
return password_verify($seasonThePassword["password_w_PaC"], $hash);
}
}
答案 0 :(得分:2)
这就是password_hash()已经执行的操作:
因此无需采取额外步骤来安全存储您的密码。尤其是随机盐(胆固醇)的产生已经由该功能完成。您传递给函数的成本因素从未使用过。
所以我建议直接使用password_hash():
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_DEFAULT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
如果您想要更高的成本因素,您可以在选项中传递它,请注意,将成本因子增加一倍会使计算时间加倍,16似乎是一个不必要的高因素。
如果您想要包含服务器端密钥,可以更好地将其添加为胡椒。而是加密生成的哈希。您可以在我的教程结尾处找到关于safely storing passwords的进一步说明。