php - 希望找到一个可用的 PHP/MySQL 应用程序密码加盐解决方案?

标签 php passwords hash salt

在阅读了一整天的密码散列/加盐处理后(没有谎言!),我需要找到一个有效的解决方案,可以持续使用,并且足够安全适用于使用共享代码库的各种不同站点/应用程序。

所以,这是一个 MySQL 用户表的想法:

users { id, username, password_hash, password_salt }

..和伪代码:

$s_algo       = 'sha1';
$i_iterations = 1000;
$s_password   = 'mypw123xyuACE&.!3';
$s_salt       = hash($s_algo,uniqid(mt_rand(),true));
$s_result     = $s_password;
for ($i       = 0; $i < $i_iterations; $i++) {
    $s_result    = hash($s_algo,$s_result . $s_salt);
}

echo 'Password: ' . $s_password . "\n";
echo 'Algorithm: ' . $s_algo . "\n";
echo 'Iterations Completed: ' . $i . "\n";
echo 'Salt  : ' . $s_salt . "\n";
echo 'Result: ' . $s_result . "\n";
echo 'Length: (Salt:) ' . strlen($s_salt) . ' (Result:) ' . strlen($s_result) . "\n";

PHP 和 MySQL 之间的交互 ​​(SQL) 被视为读取,PHP 代码的位也是如此,这些代码在身份验证时根据存储的(加盐的)哈希实际验证来自用户空间的给定密码。这不是火箭科学。这是从已经做了所有这些事情的角度来看的,但是使用未加盐的纯哈希密码存储。

根据我的阅读,我怀疑关于 $s_algo 到底应该是什么(好吧,可能不是 md5)以及 $i_iterations 可能会有无休止的争论。因此,让我们只考虑它们是此问题场景中的变量,它们可能会根据特定上下文(即存储限制、服务器负载问题等)发生变化。

撇开这些不谈,这种在 PHP 中创建每个用户加盐密码的方法是否普遍合理? “for”循环是否需要在那里?最初的盐创建代码可以吗?在存储方面,salt-length 是否过度杀伤(等于最终的散列长度)。请人们,挑漏洞(但不要太多!)..

其他想法:
- hash_hmac() 怎么样 - 这是对多个 hash() 迭代的重大改进吗?
-PBKDF2?

最佳答案

抱歉,我会在帖子上发表评论,但还没有获得足够的代表。

我会为我的哈希算法使用 SHA256,并将迭代次数保持在 25 左右。超过这个数,它真的有点过分了。我对一个框架使用了一个非常相似的解决方案,我现在已经应用于六个站点。我选择创建一个过于复杂的随机字符生成器,​​但我在很多其他地方使用过它,包括标记化财务数据。

另一个编辑:使用这样的随机字符生成器作为盐:

function randomChar($length) {
    $characters = array("A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "~", "!", "@", "#", "%", "^", "&", "(", ")", ":", "{", "[", "]", "}", "|", "<", ">", ".", ",", "/", "?", "_", "+", "-", "=");
    $charactersNumber = count($characters);
    $charactersNumber--;
    $randomLength = 0;
    while ($randomLength < $length) {
        $currentCharacter = $characters[rand(0,$charactersNumber)];
        if ($currentCharacter == $previousCharacter) {
            $currentCharacter = $characters[rand(0,$charactersNumber)];
        }
        $random .= $currentCharacter;
        $previousCharacter = $currentCharacter;
        $randomLength++;
    }
    return $random;
}

对迭代问题的回应: 如果 x = hash(password + salt) 从那时起 x = hash(x + salt)

x 的 1 次评估需要 10 毫秒,然后 2 次需要 20 毫秒,依此类推。 所以... 25 次评估 = 250 毫秒 1000 = 10,000 毫秒。

虽然每个都不需要 10 毫秒,但即使超过 1000 0.5 毫秒也仍然是半秒。

如果您只接受字母数字密码,并且密码长度为 8 个字符,则每次迭代都会增加 62^8(如果他们还没有找到密码)更多的哈希值,因为他们必须为每个组合执行另一个 has他们尝试过。

关于php - 希望找到一个可用的 PHP/MySQL 应用程序密码加盐解决方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4557892/

相关文章:

php - 让 Laravel 的 notIn 验证规则不区分大小写

batch-file - 如何在批处理文件中加密密码?

ffmpeg - 如何给 ffmpeg 命令解码密码中包含 '?' 的 rtsp 流?

hash - 生成 SHA256/512 哈希时,是否至少需要哈希 'safe' 数据量?

Ruby:合并嵌套哈希

php - 使用 PHP 5.5 的 password_hash 和 password_verify 函数

JavaScript PHP $_Get 问题

java - 在 Java 应用程序中集成 MySQL + Webserver + PHP

php - 像在 GOOGLE NEWS 中一样将相似的新闻内容分组在一起

php - 如何正确使用password_verify()?