加盐哈希真的像常识所暗示的那样安全吗?

信息安全 密码 哈希
2021-09-01 16:50:24

我正在为我的网页上的用户密码实现一个盐函数,我想知道一些事情。

salt 是添加到密码的扩展名,然后进行哈希处理,这意味着密码在数据库中存储为hash(password+salt). 但是人们在哪里储存盐呢?盐只是让彩虹表“无用”,对吗?

攻击者不能建立一个彩虹表,然后转换所有的哈希值并移除盐吗?毕竟,盐存储在数据库中的某个位置。因此,如果可以找到散列密码,则应该能够找到相应的盐。在我看来,盐只会使密码更长,从而迫使彩虹表运行更长时间。

那么如何最大限度地发挥盐的功效呢?除了动态地使密码更长之外,我并没有真正看到它的多种安全原因,但是可以再次将它们转换为字符串中的位。

我对盐如何工作的假设是否正确?如果没有,我应该如何正确存储它和加盐密码?

4个回答

您对彩虹表的工作原理有一个基本的误解。

彩虹表或哈希表是由攻击者在攻击之前构建的。假设我构建了一个哈希表,其中包含 7 个字符以下的字符串的所有哈希值MD5如果我破坏了您的数据库并获取了哈希列表,我所要做的就是在表上查找哈希以获取您的密码。

使用盐,您无法在攻击之前为特定算法生成彩虹表。盐并不意味着保密,您将其与哈希一起存储在数据库中。

x = hash(salt+password)然后,您将把它以这样的格式存储在您的数据库中,salt+x这会使彩虹表和哈希表变得无用。

像往常一样,不要自己滚动,使用bcryptscrypt或者pbkdf2为您处理所有细节,包括腌制。请参阅如何安全地散列密码?

彩虹表是一种通过蛮力反转散列的优化。它通过权衡取舍:你做了大量的预计算来构建一个巨大的数据结构,然后你可以快速破解许多哈希。

彩虹表只能帮助它覆盖的搜索空间中的破解哈希。具体来说,彩虹表是为由可打印字符组成的纯文本构建的,并且[达到一定长度。加盐的基本原理是散列后的明文既包含密码又包含盐;添加盐后,搜索空间变得太大而无法构建彩虹表

因此,通过在密码中添加盐,无法将暴力攻击的成本分摊到许多破解上。攻击者必须为每个哈希完成所有工作,只有在他知道盐时才开始。

给定一个哈希和一个盐,没有办法“去除盐”。这是哈希函数的一个基本属性:即使您知道两个字符串是相关的(例如,您知道密码是密码+盐的子字符串),它也不能帮助您找到哈希(密码)知道哈希(密码+盐)。没有必要对攻击者隐藏盐:它需要是唯一的(而不是从密码派生的),但它不需要比哈希更秘密。(您可以添加一种额外的秘密盐,称为胡椒,但它仅在少数情况下有用。)

给哈希加盐只是成功的一半。安全散列密码的另一部分是散列函数必须很慢,因为这对破解者的伤害比对验证者的伤害更大。不要自己动手,使用经过专家审查的方法。使用bcryptPBKDF2scrypt实现密码存储不应该涉及自己进行任何加密,调用库函数。

对于您想了解的有关散列密码的所有信息、您不想了解的有关散列密码的所有信息,以及您甚至可能不知道的有关散列密码的所有信息,请阅读如何安全地散列密码?

您基本上是正确的,它只是使密码更长,但它确实添加了一些额外的东西。此外,平均密码不是那么长或安全,“免费”增加长度很少是坏事。salt 使得攻击者无法对“password”进行一次哈希处理,然后查找每个密码为“password”的用户。

相反,他们将不得不生成“password03j9834nfp-3028n408”和“passwordn0438wnvas89v5sne”的哈希值......这大大增加了对识别不安全密码的保护,并且仍然对增加找到安全密码的难度有积极的好处。

当您说“攻击者不能建立一个彩虹表,然后转换所有哈希并删除盐时,您的理解会误入歧途吗?”。这里有几个问题。

首先是碰撞。彩虹表不能保证产生原始输入,它只对产生产生所需输出的输入感兴趣。由于盐将添加到用户输入的任何内容中,因此攻击者必须找到用于哈希的确切输入。

由于必须找到确切的输入,彩虹表利用碰撞的好处就失去了。此外,暴力破解所有可能的盐所需的大小对于几乎任何攻击者来说都太大了。

您也不能简单地从哈希中删除盐而不弄清楚原始输入是什么。您将不得不寻找一些以与给定哈希相对应的盐结尾的值。这需要为数据库中的每个盐值生成一个单独的彩虹表,这破坏了预先计算的能力,因为为每个可能的盐制作一个彩虹表是不可行的。

一种独特的盐解决了一个问题——一个巨大的蛮力尝试不能同时攻击每个帐户。

假设您尝试构建一个包含 8 个字符长1的所有可打印 ASCII 密码的彩虹表那是 96 8 ~ 720 亿 (7.2 x 10 15 ) 的可能性。如果您的 GPU 以每秒 10 亿的速度生成密码,那么破解大约需要一个月左右的时间(在 200W 的情况下,每千瓦时 0.10 美元,平均约为 200 美元;最坏的情况是您的电费约为 400 美元)。

因此,您可以通过某种 SQL 注入或查找带有旧备份的硬盘驱动器来找出linkedin 上每个帐户的哈希值。你有一百万个用户的哈希值。现在,如果它们是未加盐的哈希,您可以在两个月内用一个 GPU 破解这些哈希中的绝大多数,而电费约为 400 美元。如果它们都是唯一盐渍的,并且你想打破所有这些盐,那么现在将需要 4 亿美元的电力,因为每个独特的盐都必须有自己的独立攻击。现在在你说之前,我将构建一个更大的包含盐的彩虹表,请意识到典型的盐至少有 5 个十六进制字符(16**5),这意味着创建彩虹需要一百万倍的时间表(例如,您需要在电力上花费 4 亿美元来发电)。

现在添加密钥强化,而不是进行一次哈希,而是迭代过程 N 次(例如,三次迭代的哈希函数将是:)hash(salt+hash(salt+hash(salt+pw)))现在,他们无法每秒破解十亿个哈希值,而是每秒破解十亿个/N个哈希值,因此所有攻击的成本都将增加 N 倍。(典型的 N 是 5000;因此破解单个哈希将花费大约 200 万美元的电力;超大 N 的问题在于它在您的服务器上用于验证密码尝试的计算资源更多)。

1 - 这不是破解密码的最有效方法。数百万个以前使用过的密码的字典列表更有效,因为许多密码都很弱。我不建议人们自己生成密码(通常熵非常低)或重复使用密码。使用 keepassx 之类的服务,它允许您为每个站点创建随机密码并存储在加密文件中。密钥强化+独特的盐意味着除了最简单的哈希之外,尝试破解任何东西都是不可行的。