前两天准备登录某网站的时候,在尝试了几回经常使用密码失败后,我点击了“忘记密码”,娴熟地填入手机号码,随即就收到了一条来自陌生号码的短信,里面包含着一个六个数字串,我将这个数字串填入网站提供的输入框,就进入了密码重置流程。
程序员
这里有一点细节,值得咱们注意,为何我忘记了密码,你不直接把原密码返回给我?而是给我一个不相关的口令来重置密码?算法
前段时间,华住(某大型连锁酒店)再次发生脱库事件。因为内部程序员失误,将数据库密码公开于Github上,让人拿走了数亿用户的开户记录和他们的登录信息(包括密码)。假如这些密码用明文存储,那不法分子盗取数据库后,拿到明文密码,就能够垂手可得的拿邮箱和密码去尝试登录你的各类社交网站,甚至各类金融账户。要知道有不少人其实对帐户安全不够重视,金融帐户和社交帐号都使用同一个密码。在如此数量级下(上亿)的账户密码泄露,对于互联网安全将是一场巨大的浩劫。shell
如此看来,服务器是不会明文存储你的用户密码的。这也就能解释,为何不干脆直接将原密码返回给你了。由于就连他们也不知道。数据库
那么问题来了,在数据库存储的究竟是什么?它应该是被某种算法加密过的密文,而且没法进行反向破解,保证了被***拿到了也能保证数据的相对安全。而这个算法,就是咱们接下来要介绍对哈希算法。安全
哈希(Hash)算法,因为其不可反向破解的特性被普遍用于私密信息的保护和校验。服务器
哈希算法是一个比较泛的概念,他的具体实现有许多种,你们所熟知的有 MD5,SHA256等。微信
如今拿 MD5来举例,MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被普遍使用的密码散列函数,能够产生出一个128位(16字节)的散列值(hash value)。网络
可是人类实在看不惯二进制,因此128位的二进制一般会表示成32位的十六进制(由0-9,a-f组成),他们是等价的。ide
说了那么多,这个散列值到底长啥样呢。函数
在 Python 中
import hashlib
m1 = hashlib.md5()
m1.update("hello")
print(m1.hexdigest())
# 5d41402abc4b2a76b9719d911017c592
用 shell 就更简单了
echo -n hello | md5sum
# 5d41402abc4b2a76b9719d911017c592 -
有很多人会将 哈希(Hash) 和 加密(Encrypt)混淆起来,其实它们是不同的:
哈希:将目标文本转换成具备相同长度的、不可逆的字符串,也叫消息摘要,是一对多的映射关系(即多个明文可能对应同一个哈希值)。
加密:将目标文本转换成具备不一样长度的、可逆的密文,是一对一的映射关系(即一个密文只能对应一个明文)
因为哈希算法是一对多的映射,因此不一样的输入是有可能获得了同一个哈希值,这时候就发生了"哈希碰撞"(collision)。
哈希碰撞虽然发生几率小,可是一旦发生,就会产生严重的安全问题:
案例一
不少网络服务会使用哈希函数,产生一个 token 用于标识用户的身份和权限。
若是两个不一样的用户,获得了一样的 token,就发生了哈希碰撞。服务器将把这两个用户视为同一我的,这意味着,用户 B 能够读取和更改用户 A 的信息,这无疑带来了很大的安全隐患。
案例二
咱们都用过网络支付工具,假如我如今从 A 账户转给账户 B 1000块钱,交易信息在网络中进行传输,有可能被***给截持并篡改咱们的数据,将目标账户改为***本身的账户。如此一来,咱们的金钱就被窃取了。
若是使用哈希算法,就能够在客户端处,将转帐的信息进行处理,处理方法是,将要加密的数据加上一个约定好的字符串一块儿进行哈希,生成一个信息摘要。
假如在网络传输过程当中不幸被***修改了目标账户和转账金额,等到了支付平台的服务器端,会将传输过来的信息和以前约定好的字符串再次进行哈希。而后和以前那个哈希进行比对,因为以前的数据已经被篡改了,因此验证不经过,转账失败。从而保证了咱们的资金安全。
前面讲到了许多哈希在实际生活中的应用,能够发现,哈希被普遍的应用在安全领域。那哈希真的没有办法破解吗?
固然有,这里举三个常见的例子。
暴力穷举法,就是简单粗暴的枚举出全部的原文,并计算其哈希值,而后将计算结果与目标哈希值一一比对。因为原文的可能性有无数多种,因此这种方法时间复杂度高得离奇,极不可取。须要大量的计算,所以破解速度很是慢,以14位字母和数字的组合密码为例,共有1.24×10^25种可能,即便电脑每秒钟能进行10亿次运算,也须要4亿年才能破解。
就算有一天,真找到一个和目标哈希值相等的原文,这个原文也不必定是答案,由于哈希冲突的存在,多个原文是有可能有着同一个哈希值。
反思暴力枚举法,它其实作了太多无用的计算。通常人的密码都会取一些有特殊意义的字符,好比生日,名字缩写等。有人就会把这些经常使用的高频率的密码组合,试先计算并存储起来。等到要用的时候,直接到数据库里查询对应的哈希值就好了。
若是说暴力枚举法,是时间换空间,那字典法就是空间换时间。
须要海量的磁盘空间来储存数据,仍以14位字母和数字的组合密码为例,生成的密码32位哈希串的对照表将占用2.64 * 10^14 TB
的存储空间。如何增长密码长度或添加符号,须要的时间或磁盘空间将更加不可思议,显然这两种方法是难以让人满意的。
(62^14*192)/8/1024/1024/1024/1024=2.64 * 10^14 (GB)
暴力枚举和字典法,都只适用于长度较短,组合简单的密码。
接下来为你们介绍一种高效的密码***方法:彩虹表。它能够用于复杂一点的密码。
彩虹表实质上仍是属于字典破解的一种,不过再也不是简单的明文—密码的对应,为了节省字典存储空间,彩虹表省去了能经过计算得出的数据,达到这点的关键在于设计出一个函数族Rk(k=一、二、三、4……)将hash密文空间映射回明文的字符空间。
具体内容可点击查看:漫画:如何破解MD5算法?
彩虹表的存储空间是字典法的 k 分之一,代价是运算次数至少是原来的 k 倍。
彩虹表确实像它的名字同样美好,至少***眼里是这样。下表是7位之内密码在不一样字符集下构造出的彩虹表的状况,彩虹表中哈希链的长度和个数随着字符集的增加而增加,彩虹表的大小和生成时间也随之成倍增长。7位数字组合在彩虹表面前简直就是秒破,即便最复杂的7位密码不到一个小时就能破解,若是采用普通的暴力***,破解时间可能须要三周。
这篇文章,写得比较通俗易懂,其中借鉴了网上一些不错的文章,算是一篇科普文,想要深刻了解,你还须要本身作更多的研究与思考。若是有写得不对的地方欢迎你们微信我指正!
另,感谢阅读,若是文章对你有帮助,但愿你能够分享至朋友圈,让更多的人看到。