在阅读了关于密码散列/腌制一整天(没有谎言!)之后,我需要找到一个有效的解决方案,可以一致地使用,并且对于各种不同的站点/应用程序来说足够安全使用共享代码库.
所以,这是一个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)被视为读取,在验证时实际验证来自user-land的给定密码与存储(盐渍)散列的PHP代码的比特.这不是火箭科学.这是从已经做过所有这些事情的角度来看,但是使用非盐渍的仅限密码存储.
从我的阅读中我怀疑可能会有关于$s_algo应该是什么(好吧,可能不是md5)以及$i_iterations的无休止的争论.因此,我们只考虑它们是此问题场景中的变量,这些变量可能会根据特定上下文(即存储限制,服务器负载问题等)而发生变化.
抛开这些问题,这种用PHP创建每用户盐渍密码的方法通常听起来不错吗? ‘for’循环是否需要在那里?初始盐创建代码是否正常?是盐长度过度,存储方式(等于最终的散列长度).请人,挑孔(但不要太多!)..
其他想法:
– 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(密码salt),那么x = hash(x salt)
x的1次评估需要10ms,然后2次需要20次,依此类推.
所以…
25次评估= 250ms
和1000 = 10,000毫秒.
虽然每个都不需要花费10毫秒,但即使0.5毫秒仍然是半秒.
如果您只接受字母数字密码,并且密码长度为8个字符,则每次迭代将添加62 ^ 8(如果他们尚未找到密码)更多哈希,因为他们必须为他们尝试的每个组合执行另一次密码.