21-哈希算法(上):如何防止数据库中的用户信息被脱库?

你会如何存储用户密码这么重要的数据吗?仅仅 MD5 加密一下就够了吗?

今天不会重点剖析哈希算法的原理,也不会教你如何设计一个哈希算法,而是从实战的角度告诉你,在实际的开发中,我们该如何用哈希算法解决问题

什么是哈希算法?

不管是“散列”还是“哈希”,这都是中文翻译的差别,英文其实就是“Hash”。

哈希算法的定义和原理非常简单:将任意长度的二进制值串映射为固定长度的二进制值串,这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制值串就是哈希值

但是,要想设计一个优秀的哈希算法并不容易,根据经验总结了需要满足的几点要求:

  • 从哈希值不能反向推导出原始数据(所以哈希算法也叫单向哈希算法);

  • 对输入数据非常敏感,哪怕原始数据只修改了一个 Bit,最后得到的哈希值也大不相同;

  • 散列冲突的概率要很小,对于不同的原始数据,哈希值相同的概率非常小;

  • 哈希算法的执行效率要尽量高效,针对较长的文本,也能快速地计算出哈希值。

哈希算法的应用非常非常多,我选了最常见的七个,分别是安全加密、唯一标识、数据校验、散列函数、负载均衡、数据分片、分布式存储。这节我们先来看前四个应用。

应用一:安全加密

说到哈希算法的应用,最先想到的应该就是安全加密。最常用于加密的哈希算法是 MD5(MD5 Message-Digest Algorithm,MD5 消息摘要算法)和 SHA(Secure Hash Algorithm,安全散列算法)。除此之外还有 DES、AES。

上面提到的哈希算法四点要求,对用于加密的哈希算法来说,有两点格外重要。第一点是很难根据哈希值反向推导出原始数据,第二点是散列冲突的概率要很小。

事实上关于第二点,基于“鸽巢原理”,我们只能尽量减少碰撞冲突的概率,理论上是没办法做到完全不冲突的。

不过,即便哈希算法存在散列冲突的情况,但是因为哈希值的范围很大,冲突的概率极低,在有限的时间和资源下,哈希算法还是被很难破解的。

没有绝对安全的加密。越复杂、越难破解的加密算法,需要的计算时间也越长。

应用二:唯一标识

比如,用 hash 算法(比如 MD5)给每一个图片取一个唯一标识,或者说信息摘要,就可以比较方便的从海量图库中搜索一张图是否存在。如果还想继续提高效率,我们可以把每个图片的唯一标识,和相应的图片文件在图库中的路径信息,都存储在散列表中。

应用三:数据校验

P2P 分块下载的文件,我们通过哈希算法,对 100 个文件块分别取哈希值,并且保存在种子文件中,当文件块下载完成之后,通过相同的哈希算法对下载好的文件块逐一求哈希值,然后跟种子文件中保存的哈希值比对,不相同则说明这个文件块不完整或被篡改,需要重新下载。原理在于哈希算法对数据很敏感,只要文件内容有一丁点改变,哈希值就会完全不同。

应用四:散列函数

散列函数也是哈希算法的一种应用。只不过,相对哈希算法的其他应用,散列函数对于散列算法冲突的要求低很多。即便出现个别散列冲突,只要不是过于严重,我们都可以通过开放寻址法或者链表法解决。不仅如此,散列函数对于散列算法计算得到的值,是否能反向解密也并不关心。散列函数中用到的散列算法,更加关注散列后的值是否能平均分布,也就是,一组数据是否能均匀地散列在各个槽中。除此之外,散列函数执行的快慢,也会影响散列表的性能,所以,散列函数用的散列算法一般都比较简单,比较追求效率。

开篇解答

如何防止数据库中的用户信息被脱库?


我们可以通过哈希算法,对用户密码进行加密之后再存储,不过最好选择相对安全的加密算法,比如 SHA 等(因为 MD5 已经号称被破解了)。

针对字典攻击,我们可以引入一个盐(salt),跟用户的密码组合在一起,增加密码的复杂度。我们拿组合之后的字符串来做哈希算法加密,将它存储到数据库中,进一步增加破解的难度。

不过这里多说一句,安全和攻击是一种博弈关系,不存在绝对的安全。所有的安全措施,只是增加攻击的成本而已。

课后思考

现在,区块链是一个很火的领域,它被很多人神秘化,不过其底层的实现原理并不复杂。其中,哈希算法就是它的一个非常重要的理论基础。你能讲一讲区块链使用的是哪种哈希算法吗?是为了解决什么问题而使用的呢?


区块链是一块块区块组成的,每个区块分为两部分:区块头和区块体。

区块头保存着 自己区块体 和 上一个区块头 的哈希值。

因为这种链式关系和哈希值的唯一性,只要区块链上任意一个区块被修改过,后面所有区块保存的哈希值就不对了。

区块链使用的是 SHA256 哈希算法,计算哈希值非常耗时,如果要篡改一个区块,就必须重新计算该区块后面所有的区块的哈希值,短时间内几乎不可能做到。

你可能感兴趣的:(21-哈希算法(上):如何防止数据库中的用户信息被脱库?)