这种散列/验证 class 足够安全吗?
is this hashing / verification class safe enough?
我知道这类问题在这里被问了 多次 次,但在每个问题下都有建议向知道自己在做什么的人问这些问题。 (这样我们也可以了解我们在做什么)
我也找不到足够令人满意的更新 php 函数的例子..
这是我为开源项目开发的散列 class。我有 4 个步骤
- 密码base64编码,更安全的加密格式
- 使用 sha256 将密码与服务器端密钥合并
- 合并,合并密码和胡椒粉,随机密钥将存储在数据库中(称为胆固醇,用于防止混淆,因为作为主要哈希盐,我使用 password_hash 默认随机盐)
- 将结果与 password_hash 进行哈希运算,默认河豚,成本为 16
我不确定的部分是密钥长度,我是否应该使用另一个 base64 编码以防止 sha256 的原始字节问题 并且生成的散列是否具有直接插入 mysql.
的正确格式
还有 class 使用本身的安全性。
这里是 class:
<?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);
}
}
这是 password_hash() 已经做的:
- 它生成安全盐
- 并计算一个成本为 BCrypt 的散列
当前 10 的系数。
因此无需采取额外步骤来安全地存储您的密码。特别是随机盐(胆固醇)的生成已经由函数完成。您传递给函数的成本因子从未被使用。
所以我建议直接使用 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.
的教程末尾找到更多解释
我知道这类问题在这里被问了 多次 次,但在每个问题下都有建议向知道自己在做什么的人问这些问题。 (这样我们也可以了解我们在做什么)
我也找不到足够令人满意的更新 php 函数的例子..
这是我为开源项目开发的散列 class。我有 4 个步骤
- 密码base64编码,更安全的加密格式
- 使用 sha256 将密码与服务器端密钥合并
- 合并,合并密码和胡椒粉,随机密钥将存储在数据库中(称为胆固醇,用于防止混淆,因为作为主要哈希盐,我使用 password_hash 默认随机盐)
- 将结果与 password_hash 进行哈希运算,默认河豚,成本为 16
我不确定的部分是密钥长度,我是否应该使用另一个 base64 编码以防止 sha256 的原始字节问题 并且生成的散列是否具有直接插入 mysql.
的正确格式还有 class 使用本身的安全性。
这里是 class:
<?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);
}
}
这是 password_hash() 已经做的:
- 它生成安全盐
- 并计算一个成本为 BCrypt 的散列 当前 10 的系数。
因此无需采取额外步骤来安全地存储您的密码。特别是随机盐(胆固醇)的生成已经由函数完成。您传递给函数的成本因子从未被使用。
所以我建议直接使用 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.
的教程末尾找到更多解释