我知道這種類型的問題在這裏被問到超過很多次,但是在每個問題中都有建議將這些問題提交給知道他們在做什麼的人。 (所以我們可以瞭解我們在做什麼,以及)這個哈希/驗證類是否足夠安全?
我也找不到足夠令人滿意的例子有更新的PHP函數..
因此,這裏是我的一個開源開發我的散列類項目。我有4個步驟
- 的base64與服務器端密鑰使用SHA256
- 合併編碼密碼,更安全的加密格式
- 合併密碼,合併密碼和胡椒,與將被存儲在隨機密鑰數據庫(稱爲膽固醇,防止混淆,因爲作爲主要散鹽我使用password_hash默認隨機鹽)
- 哈希與password_hash結果,默認河豚,有16個成本
我不確定的部分是密鑰長度,我應該使用另一個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);
}
}
如果您使用密碼散列API就足夠了。步驟1-3是完全不必要的。 –
@CharlotteDunois說什麼,你真的需要添加的唯一東西是檢查存儲的散列是否是最新的(PHP可以稍後改變默認算法)[password_needs_rehash](http://php.net/manual/en/ function.password-需求,rehash.php) – JimL