md5($password.md5($password))
这个用于密码哈希的是否足够好?我不是在比较它和像bcrypt这样的东西。
如果不安全,请告诉我原因。
md5("12345".md5("12345"))
并查看是否匹配任何条目。有关更多详细信息,请查看 Coding Horror 文章,“您可能存储密码不正确”。
它对字典攻击没有太大作用,与单个md5
相比,计算一个字典只有两倍难度,并且现在的md5
非常便宜。
MD5本身不安全,因为它部分被破解(碰撞)且摘要太小。如果您不想使用类似于bcrypt、scrypt或PBKDF2的适当密码派生函数,则至少应该在新设计中使用SHA-256(并制定计划以在SHA-3推出时进行迁移,因此请确保存储用于使用结果哈希密码的方案,使两个方案可以共存当人们更改密码时使用新的哈希过程)。
如果您打算销售使用MD5的程序,则在任何方面使用MD5都可能成为大多数政府销售的障碍(例如在美国,使用的算法必须得到FIPS 140-2批准,许多其他国家也有同样的要求)。
通过您的解决方案,您基本上破坏了使用盐来防范预先计算字典攻击的目的。
使用预先计算的字典表,正如其名称所示,某人已经提前为特定单词创建了哈希表(计算出的md5
结果)。
考虑这个哈希表hashtable
(仅用于说明目的的想象哈希值)
word | hash
------------
foo | 54a64
bar | 3dhc5
baz | efef3
通过将这些值与您的表进行比较,可能只需要这样:
SELECT h.word
FROM hashtable h, yourtable y
WHERE y.password = MD5( CONCAT( h.word, h.hash ) );
如果有匹配,你就可以得到密码。
然而,如果在将密码再次连接并哈希之前没有对其进行哈希处理,则使用预先计算的字典攻击它会更加困难。因为此时密码可能是md5('testtest')
,这使得预先计算的表变得毫无价值,如果预先计算的表只考虑了单词的单个实例。
您可以轻松地看出,如果您没有使用密码作为盐,而是使用另一个随机字符串作为盐,那么情况会变得更加困难。如果您为每个密码创建唯一的盐,那么情况会变得更加困难。当然,如果您为每个密码创建唯一的盐,您需要在数据库行中与密码一起保存盐。
所以我的建议是:
md5( 'uniquesalt' . 'password' );
实际上,不要使用md5
,而是使用更好的sha1
、sha256
(或更高级别的)哈希算法。
为什么建议使用随机密码盐来哈希密码,这样一个知道密码哈希值的攻击者就无法将其与彩虹表中预先计算出的字典哈希值进行比较。
如果您使用密码作为盐,攻击者可以首先从他们的字典中预先计算$word.md5($word)的哈希值。
md5($password.md5($id))
,这样会更好吗? - wiiman