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