希望在 PHP/MySQL 应用程序中找到一个可用的密码加盐解决方案?
在阅读了一整天有关密码散列/加盐的内容(没有谎言!)之后,我需要找到一个可行的、可以一致使用的、并且对于各种安全足够的解决方案使用共享代码库的不同站点/应用程序。
所以,这是 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”循环是否需要在那里?最初的盐创建代码可以吗?存储方面的盐长度是否过度(等于最终的哈希长度)。请大家挑漏洞(但不要太多!)..
其他想法:
- hash_hmac() 怎么样 - 这是对多次 hash() 迭代的关键改进吗?
- PBKDF2?
After reading about password hashing/salting for an entire day (no lie!), I'm in need of arriving at a solution that works, can be used consistently, and is about secure enough for a variety of different sites/applications that are using a shared codebase.
So, here's an idea of a MySQL user table:
users { id, username, password_hash, password_salt }
..and pseudo-ish code:
$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";
The interaction (SQL) between PHP and MySQL is taken as read, as are the bits of PHP code that actually verify the given password from user-land against the stored (salted) hash at authentication time. It's not rocket science. This is from the perspective of already doing all that stuff, but with un-salted hash-only password storage.
From my reading I suspect there could be endless debates about what $s_algo should really be (ok, probably NOT md5), and also $i_iterations. So let's just consider that they are variables within this problem scenario, which might change according to the specific context, i.e. storage limitations, server load concerns, etc.
These things aside, is this methodology for creating a per-user-salted passwords in PHP generally sound? Does the 'for' loop need to be in there at all? Is the initial salt creation code ok? Is the salt-length overkill, storage-wise (equal to the eventual hash length). Please people, pick holes (but not too many!)..
Other thoughts:
- What about hash_hmac() - is that a critical improvement over multiple hash() iterations?
- PBKDF2?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
抱歉,我本来想对这篇文章发表评论,但还没有得到足够的代表。
我会使用 SHA256 作为我的哈希算法,并将迭代次数保持在 25 左右。超过这个数字就真的有点矫枉过正了。我对一个框架使用了一个非常相似的解决方案,现在我已经将其应用于六个网站。我选择创建一个过于复杂的随机字符生成器,但我已经在很多其他地方使用了它,包括标记财务数据。
另一个编辑:使用像这样的随机字符生成器作为你的盐:
对迭代问题的响应:
如果 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(如果他们尚未找到密码)更多的哈希值,因为他们必须为他们尝试的每个组合执行另一个哈希值。
Sorry, I would've commented on the post but haven't got enough rep yet.
I'd use SHA256 for my hash algo and keep the iterations around 25. Any more than that and it's really overkill. I use a very similar solution for a framework that I've applied to half a dozen sites now. I chose to create an overly complicated random character generator, but I've used it in a lot of other places, including tokenizing financial data.
Another edit: Use a random character generator like this for your salt:
Response to iteration question:
If x = hash(password + salt) and from then on x = hash(x + salt)
and 1 evaluation of x takes 10ms, then 2 would take 20 and so on.
So...
25 evaluations = 250ms
and 1000 = 10,000ms.
While it's not going to take 10ms for each one, even .5ms over 1000 is still half a second.
If you only accepted alphanumeric passwords, and a password was 8 characters long, each iteration would add 62^8 (if they hadn't yet found the password) more hashes because they would have to do another has for every single combination they tried.
我昨天读了一篇文章,回答了我关于安全的一个问题:http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what -you-need-to-know-about-s.html
它特别指出,加密速度越快,效果就越差,并且将 MD5 和 SHA1 列为最差的一些。尽管它们相距微秒,但在制作彩虹表时会转换为很长的时间。
我在 php 手册中读到: http://www.php.net/ Manual/en/function.hash.php#89574 那里的人对每个算法进行了测试,并得出了每个算法的速度。根据我的阅读,我使用 RipeMD 和 50 个字符的盐。
关于你问的事情:
问题是您正在生成随机盐,然后将其存储在数据库中,这似乎不必要地冗余。我个人宁愿在我的 php 代码中隐藏一种盐,而不是在数据库中嵌套许多独特的盐。另外你为什么要散列盐?
I read an article yesterday in response to one of my questions on security here: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
It specifically says that the faster the encryption is the worst it is and it listed MD5 and SHA1 as some of the worst. Although they are microseconds apart, that converts to very long times in making a rainbow table.
I read in php manuals this: http://www.php.net/manual/en/function.hash.php#89574 where the guy ran a test of each algo and came up with speeds of each one. And based on my readings and that I use RipeMD with a 50 character salt.
On the things you were asking:
The thing is you are generating a random salt and then storing it in the database which seems unnecessarily redundant. I'd personally rather have one salt hidden in my php code rather then many unique salts nested in a database. Plus why are you hashing the salt?