加盐

hash("hello")                    = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hello" + "QxLUF1bgIAdeQX") = 9e209040c863f84a31e719795b2577523954739fe5ed3b58a75cff2127075ed1
hash("hello" + "bv5PehSMfV11Cd") = d1d3ec2e6f20fd420d50e2642992841d8338a314b8ea157c9e18477aaef226ab
hash("hello" + "YYLmfY6IehjZMQ") = a49670c3c18b9e079b9cfaf51634f563dc8ae3070db2c4a8544305df1b60f007

查找表和彩虹表之所以有效,是因为每个密码都是以完全相同的方式进行散列的。如果两个用户拥有相同的密码,则他们也将拥有相同的密码散列值。我们可以通过随机化每个散列值来防止这种攻击,这样,当相同的密码被散列两次时,散列值会是不一样的。

我们可以在运行散列前向密码之后或之前添加一个称为 盐(Salt) 的随机字符串来随机化散列值。如上例所示,这使得相同的密码每次散列后都变成完全不同的字符串。为了检查密码是否正确,我们需要盐,因此它通常与散列值一起存储在用户账户数据库中,或者作为散列值字符串本身的一部分。

盐不需要保密。仅仅通过随机化散列值,查找表、反向查找表和彩虹表就会变得无效。攻击者不会预先知道盐是什么,因此他们无法预先计算查找表或彩虹表。如果每个用户的密码都使用不同的盐进行散列,那么反向查找表攻击也将不起作用。

在下一节中,我们将展示盐通常是如何被错误地实现的。