笔记:散列算法的使用场景

你们都知道散列算法,如 MD5, SHA, 可是对其具体特性恐怕都很模糊。说不许哪些用法是可靠的,哪些用法是不可靠的,只是经过加 salt, 或者反复散列的方式提升可靠性。本文将精确地讨论它们在各类使用方法下的可靠性,本文不讨论原理,只讨论使用,如下部分资料来自网络,感谢 wxy 帮忙检验文中的论断。算法

MD5 和 SHA 系列算法都属于同一类——我还没给这类算法找到一个足够贴切的名字。首先在大的分类上,它们都是散列算法。
散列是怎么个定义呢?典型的散列算法能够是任何一个:具备无限的定义域,且具备有限的值域的函数。甚至,宽松的广义散列算法能够是任何一个(数学意义上的)函数,由于函数自己的概念就是将一个或多个值映射到一个惟一的值。数据库

从具体特征上来讲,它们(的目标)都是足够安全的信息摘要算法。究竟何谓安全?
MD5 和 SHA 系列函数所追求的安全,在于下面两个方面。缓存

  • 单向性
  • 抗冲突性

所谓单向性,就是指明文 M, 通过散列后的 hash(M). 从 hash(M) 没法推算出 M. 这是大部分摘要算法都具备的特征,由于大多数状况下,被摘要的信息长度要小于散列值,由于缺乏信息,且值域明显小于定义域,即一个散列值会对应多个(无限个)原文,因此自然地就没法从散列值反向计算出原文。MD5 和 SHA 系列函数在单向性方面目前都尚未被发现明显的漏洞。安全

可是以上讨论的只是理论上的单向性,实际使用中,攻击者能够经过穷举,即暴力破解的方式推算出可能的原文。这种状况适用于已知信息原文定义域且范围较小的状况。例如若是直接对用户的密码进行散列,由于密码大多在十位字母左右,攻击者能够以很低的成本计算全部密码组合的散列值,以获得可能的信息原文。网络

从散列算法的角度,应对暴力破解攻击没有明显有效的手段,但也能够经过『提升计算成本』和『减小散列值长度』的方式提高单向性。分布式

提升计算成本即经过将算法设计得更为复杂,增长更屡次计算,来提升对单个信息进行散列的时间。对于正常单次散列来说,即便增长十倍的计算时间,仍然是能够接受的。但当攻击者进行暴力破解时,一样须要原来十倍的计算时间,这个成本对攻击者来讲可能没法接受。除此以外,还能够改造算法,使其只能运行于 CPU 上,没法使用显卡或专用芯片进行计算,以提升暴力破解的计算成本。
但彷佛这种方式并无被业界接受,SHA 系列函数中的新成员均减小而不是提升了计算成本。函数

减小散列值长度,即经过减小散列值的长度来使得多个(大量)信息原文映射到同一个散列值,使攻击者没法分辨究竟哪一个才是真正的原文。
例如将散列值减小到 8 bit, 这样密码组合中 1/256 的密码都会映射到同一个散列值,根本没法分别哪一个才是真正的密码。
这种方式显然很扯淡,由于这种方式会明显下降下面要提到的抗冲突性。优化

实际使用中,咱们能够经过提升定义域范围的方式,来加强单向性。一样是散列用户密码的例子,咱们能够将原来的 hash(M) 改成 hash(hash(M)). 由于 hash 的值域范围一般要比密码(约 10 位字母,即约 60 bit)大, 如 MD5 的值域是 128 bit, SHA-1 的值域是 160 bit. 所以咱们经过第一次散列将第二次散列的定义域提升到了 2-4 倍,必定程度上提升了攻击者暴力破解的成本。网站

可是,攻击者会将 hash(hash(x)) 视为一个独立的散列函数 hash2(x), 除了正常地增长了一倍的计算时间,并无受到咱们增长做用域的影响。所以,这时咱们须要引入 salt(佐料,干扰), 将散列算法改成 hash(hash(x + salt)), salt 须要与散列值一同储存。设计

在已知 salt 的状况下,对攻击者其实没有任何影响,由于这个函数依旧能够转换为 hash2(x + salt), 固然,有些攻击者会经过 Rainbow Table(彩虹表) 的方式进行协做和缓存,加 salt 会使他们没法使用 Rainbow Table.

Rainbow Table, 即事先对预约范围的数据进行散列,储存散列结果。而后经过数据库或者分布式技术(小型 Rainbow Table 就不须要了), 来优化从散列值到原文的『反向』查询。类似的技术还有『字典』,即收集你们经常使用的原文(密码,或其余短语), 代替穷举,以提升暴力破解的效率。

而在这个场景中,将 hash(hash(x + salt)) 更换为 hash(hash(x) + salt) 会得到更好的效果。由于前一种状况,攻击者能够将密码和 salt 视为一个总体来使用 Rainbow Table (虽然在 Rainbow Table 中极可能查不到这些信息); 后者则不能。由于后者是一个散列值加一个 salt, 长度已经远远超出了 Rainbow Table 的范围。固然,单纯加长 salt 也能够实现 hash(hash(x) + salt) 的效果。

在攻击者不知道 salt 的状况下,有两种选择。
一是将 hash2(x) 改成 hash2(x, salt), 这种状况适用攻击者知道 salt 的长度或范围的状况,由于这个函数有两个参数,所以破解成本与 x 或 salt 的长度呈指数函数,只要 salt 足够长,那么能够认为攻击者即便暴力破解也无能为力。
二是将第二个 hash 的输入视为一个散列值,换言之就是进行两次爆破,这种方式的计算成本相比于前一种会更高,由于暴力破解的成本同原文长度也是呈指数关系的。

因此,在未知 salt 的状况下,能够防护全部暴力破解,除非攻击者拥有极其惊人的计算力。
举个例子,若是密码为 10 位的字母,salt 为 3 位的字母,暴力破解须要至关于 Bitcoin 全网计算力的约 60 天时间。

虽然咱们还拥有更强大的变种,例如:

hash(x, salt[]) = hash(hash(x + salt[1]) + hash(x + salt[2]) + ...)

可是咱们认为,使用 hash(hash(x) + salt) 和足够长的 salt(大体至关于散列值的长度), 已经足够安全。

接下来,那么如何生成 salt 呢?是否有必要为每条数据(仍是前面的例子,每一个用户)使用单独的 salt 呢。经过前面的讨论咱们看到,要保证单向性,对 salt 进行保密十分必要。若是你可以保证 salt 的绝对安全的话,那么是否使用单独的 salt 其实可有可无。不要担忧使用相同的 salt 会让攻击者找到某种规律而计算出 salt(固然前提是 salt 足够长), 由于 MD5, SHA 系列函数保证了单向性,攻击者没法从散列值推测出原文的任何信息。

至于 salt 的取值,没有什么特别的要求,基于保密的考虑,一般要使用随机生成的字符串,而后就是足够长(大约等于散列值的长度).

但咱们认为仍有必要为每条数据使用单独的 salt, 这是基于下面两点考虑。
一是虽然暴力破解须要惊人的计算力,可是若是只需破解一个散列值,就能够获知全部数据的 salt, 这个破解也是值得的,也许攻击者就可以提供这么多的计算力也说不定,虽然若是你使用足够长的 salt 的话,这种可能性极小。
二是也许你不能保证 salt 的绝对安全,当你的 salt 泄漏后,每条数据使用不一样的 salt 将会为攻击者制造最后一道障碍。

若是你全部的数据都使用一样的 salt, 那么攻击者在拿到数据后,只需进行一次暴力破解,便可破解出全部的数据(若是都命中了的话), 但若是你为每条数据使用不一样的 salt, 那么攻击者将不得不为每条数据单独运行一次暴力破解,由于每条数据至关于在使用不一样的散列函数,由于 salt 是不一样的。

综上,咱们认为网站的用户系统使用下面的散列便可保证安全性:

hash(hash(passwd) + salt)

其中 salt 是随机生成的,长度等于散列值长度的字符串。hash 能够是 MD5 或 SHA 系列函数。


咱们接着来谈抗冲突性,所谓抗冲突性即从计算上不可能找到两个有一样散列值的原文。抗冲突性分为抗强冲突性,和抗弱冲突性。
抗强冲突性,即给定一个散列值,没法找到另外一个具备一样散列值的信息原文。
抗弱冲突性,即没法找到两个具备一样散列值的信息原文。

加上单向性,这三条特性是呈阶梯状的,知足『抗弱冲突性』就必定知足『抗强冲突性』也就必定知足『单向性』同时也就知足『散列映射具备随机性和均匀性』。MD5 和 SHA 系列函数在设计上都知足这三条特征,但目前已经被发现了存在某些漏洞。

抗冲突性的主要应用场景就是为信息原文进行摘要,鉴别两段信息原文是否相同。
而攻击者的目标就是,对信息原文进行修改,而后在信息原文后(或者修改信息原文)添加给定的数据段,使其可以生成与以前相同的散列值,实现伪造数据原文。

在这种场景下攻击者是否也可以进行暴力破解呢?很难,由于在这种状况下,攻击者须要不断更换附加在信息原文后的数据,以得到和以前相同的散列值,在不理想的状况下,须要尝试全部的散列值,这个计算力被认为是没法接受的。但经过算法的一些漏洞,能够下降这个暴力破解的成本。

抗冲突性是检验散列算法设计是否优秀的重要指标,不少散列算法被淘汰都是由于抗冲突性存在漏洞。

目前 MD5 已在 2005 年被中国数学家王小云发现有抗强冲突性的漏洞,给定一个散列值,能够在几分钟内用普通计算机找到一个碰撞,即具备相同散列值的信息原文。

SHA-0 被发现漏洞能够将寻找碰撞的难度从 2^80 次暴力破解下降到 2^39 次,SHA-1 被发现漏洞能够将寻找碰撞的难度从 2^80 次下降到 2^63 次,SHA-2 系列函数还未发现漏洞。

所以目前使用 MD5 进行信息摘要并不安全,攻击者能够轻易地伪造一段散列值相同,但内容不一样的原文,虽然攻击者还不可以自由地修改原文。 而 SHA-1 和 SHA-2 系列函数目前来说是足够安全的。

相关文章
相关标签/搜索