gpt4 book ai didi

php - 如何正确存储 PBKDF2 密码哈希

转载 作者:可可西里 更新时间:2023-11-01 13:21:30 25 4
gpt4 key购买 nike

我一直在研究散列/加密密码并将其存储在数据库中的正确方法。我知道 Salt 和 Hashing,所以我环顾四周,发现 PBKDF2 似乎是一个不错的选择。所以我找到了this website这提供了一个很好的教程以及 PBKDF2 的 PHP 改编版(这是我在我的网站上使用的)。

因此,我已将我的网站设置为使用这些函数来生成/创建密码,但正如您在以下代码中看到的那样:

function create_hash($password) {
// format: algorithm:iterations:salt:hash
$salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" . $salt . ":" .
base64_encode(pbkdf2(
PBKDF2_HASH_ALGORITHM,
$password,
$salt,
PBKDF2_ITERATIONS,
PBKDF2_HASH_BYTES,
true
)); }

salt 在 create_hash 函数中生成,并存储在最终看起来像 sha256:1000:salt:hashed_pa​​ssword 的结果哈希中。这是我必须存储在我的数据库中的内容,并且由于盐包含在生成的哈希中,所以我不需要将它添加到我的数据库中。然而,在生成了一些测试用户之后,我想知道在数据库中的哈希密码中包含 PBKDF2 设置是否真的是一件好事。他们以我的新手自认为是黑客的方式,在破解我的数据库之后,会看到这些一堆 sha256:1000:salt:password 东西,并弄清楚每个部分代表什么,这对他的尝试有很大帮助,不?

因此我对其进行了一些修改,使其具有生成并存储在数据库中的外部盐,并在通过 PBKDF2 运行之前将盐包含在密码中。然后我做同样的事情来比较给定的密码和我在数据库中的登录密码,并且它有效。我唯一担心的是,使用 128 位盐后,生成的密码哈希长度仅为 50 个字符,这对我来说似乎不正确。

这是我当前的代码:

define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 10000);
define("PBKDF2_SALT_BYTES", 128);
define("PBKDF2_HASH_BYTES", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password, $salt)
{
// format: salthash
return
base64_encode(pbkdf2(
PBKDF2_HASH_ALGORITHM,
$password,
$salt,
PBKDF2_ITERATIONS,
PBKDF2_HASH_BYTES,
true
));
}

function validate_password($password, $salt, $good_hash)
{
$pbkdf2 = base64_decode($good_hash);
return slow_equals(
$pbkdf2,
pbkdf2(
PBKDF2_HASH_ALGORITHM,
$password,
$salt,
PBKDF2_ITERATIONS,
PBKDF2_HASH_BYTES,
true
)
);
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
$diff = strlen($a) ^ strlen($b);
for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
{
$diff |= ord($a[$i]) ^ ord($b[$i]);
}
return $diff === 0;
}

function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
die('PBKDF2 ERROR: Invalid hash algorithm.');
if($count <= 0 || $key_length <= 0)
die('PBKDF2 ERROR: Invalid parameters.');

$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);

$output = "";
for($i = 1; $i <= $block_count; $i++) {
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}

if($raw_output)
return substr($output, 0, $key_length);
else
return bin2hex(substr($output, 0, $key_length));
}

我对这种密码保存格式的担忧是否有意义?还是它只是等同于同一件事,因为通过在我的数据库中加入我的盐,一旦它被破解,黑客仍然可以暴力破解?

谢谢,很抱歉问了这么长的问题。

最佳答案

My only concern is that a with 128bit salt, the resulting password hash is barely 50 characters long, that doesn't seem right to me.

生成的散列的大小与盐的大小、密码和迭代次数完全无关。无论输入如何,现代安全哈希算法(如 sha256)的输出总是相同的长度。零长度输入与 25TB 输入具有相同长度的输出。

Or will it just amount to the same thing anyway, since by having my salt in my database, once it's cracked, the hacker can still brute-force his way through?

通过将 salt 分成两部分,您会增加代码的复杂性(通常是一件坏事)。根据您储存盐 block 的方式,在某些情况下您可能会受益匪浅。例如,如果静态盐片段存储在数据库外部,则数据库的转储不会为攻击者提供足够的信息来对数据库中的密码哈希执行离线攻击。

如果盐碎片彼此分开存储,则 yield 是少量的纵深防御。它是否超过复杂性成本是一个判断电话,但我认为很有可能将时间花在寻找 XSS 和 SQL 注入(inject)漏洞上(攻击者通常获取数据库的方式)上面提到的转储),并使用 SSL 和证书或强密码保护系统各个组件之间的连接。

关于php - 如何正确存储 PBKDF2 密码哈希,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11734495/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com