前言
最近经常看到一种关于 MD5
的说法,比如某某系统的登录模块使用了 MD5
加密算法,保证了用户密码的安全。那么 MD5
究竟是不是一种加密算法呢?从概念上来说『加密』对应的是『解密』,我们把数据采用某种方式加密之后,可以在之后的某一时刻进行解密来获得原始数据,照此观点来说 MD5
并不是一种加密算法,它只能把原文加密成密文,而不能将密文解密成原文。但是 MD5
确实把明文变成了不容易被破解的密文,达到了 “加密” 的目的,好像说它可以用来加密勉强也可以。
更准确的说法,MD5
是一种哈希算法,又叫散列算法或者摘要算法,是一类把任意长度数据转换为定长数据的算法统称,它广泛应用于错误检查,经常通过计算 MD5
来检验下载到的文件的完整性,优秀的哈希算法通常需要具有低碰撞概率,MD5
就是其中的一种。
MD5的八卦
可用于处理密码,是不可逆的
刚刚前面已经提到它可以把原始数据变成定长的摘要信息,而不能把摘要信息再还原成原始数据。就比如 110+119=229
,通过原始信息 110 和 119 可以转化成摘要信息229,而已知229却无法知道它是由那两个数相加得到的,当然这个例子只是象征性的,它的碰撞率太高了。
既然不可逆,那么怎样才能判断密码信息呢?这可以利用比较hash值来判断,我们在注册时计算密码的 MD5
值入库,当玩家登录时再次使用玩家输入的明文密码再次计算 MD5 值,如果一致就验证成功,这就是为什么哈希算法要有低碰撞率了。
MD5现在不太安全了
因为MD5算法是确定,用一个字符串计算出来的哈希值也是固定的,所以出现了一些针对该算法的破解方法。
- 暴力枚举法:因为可以不断尝试,并且随着计算机硬件能力的快速提升,使得这种方法来破解短密码称为了可能
- 字典法:也就是撞库,黑客通过收集互联网已泄露的用户和密码信息,生成对应的字典表,通过撞库来完成破解
- 彩虹表:在字典法的基础上改进,以时间换空间,使用预计算的哈希链集来降低存储空间,是目前最常用的方法
MD5可以为自己代言(带盐)
对于固定的哈希算法,相同的输入会得到相同的输出,那么针对MD5算法只需要准备一个字典或者一个彩虹表就可以一直沿用,如果在原有的密码上加点料,那么即使两个用户使用相同的密码,因为盐不同,得到的输出值也就不同,那么破解难度大大提高了。
BCrypt加密
上面说过单独使用MD5加密不太安全,但是加盐以后可以大大提高破解的难度,为什么BCrypt加密火了起来,大有代替MD5的趋势~
BCrypt 是 Niels Provos 和 DavidMazières 基于 Blowfish 密码设计的,是 OpenBSD 的默认密码哈希算法。 目前有针对 C、C++、Python 、C# 、Java、JS、PHP 等多种编程语言的实现,使用起来非常方便。
它相对于MD5有哪些优势呢?
自己加盐
首先他不用自己来管理用户的“盐”,如果所有的用户使用相同的盐不太安全,每个人生成不同的盐,需要自己单独来存储使用,而BCrypt内部自己实现了随机加盐处理,可以实现每次加密后的密文是不一样的。
对于同一个密码,Bcrypt每次生成的哈希结果都不一样,那么它是如何进行校验的?
其实BCrypt算法将盐随机生成并混入最终加密后的密码之中,验证时会自动提取,无需单独提供“盐”信息,生成的Hash值通常格式如下:
1 | $2b$12$ABJPtagiuqTVhnIPvOLoB.hbIlZ3joRkpck3joDsX6xe3O2KShuty |
其中 $
为分隔符,2b
是bcrypt加密版本号,12
是工作负载,紧接着22位是盐,剩下的字符串就是密码的密文了。
看到这个密码仿佛就是明牌了跟对手打呀,如果你真的获得了加密后的密码,那你就知道了加密版本、工作负载,盐的信息,这样会不会很危险呢?是挺危险的,但是即使你使用MD5加密,那个盐也是要存储的,也会面临同样的问题,另外BCrypt还有其他的法宝。
工作负载
BCrypt的工作负载有时也称为加密轮数、成本因子等等(一提到工作负载就想到比特币,数字游戏而已),目的就是提高破解难度,带来的缺点就是速度慢。MD5的Hash值生成通常是微妙级别的,但是Bcrypt一个密码出来的时间比较长,Python环境使用默认12轮负载需要0.25秒生成一个密码(C++环境需要进一步测试)。
所以如果使用Bcrypt,需要考虑它的成本,负责做认证的服务器,可能在原基础上扩容几十倍或者几百倍,它是靠把计算成本提高多个数量级来换取安全的。
使用方便
目前在各大主流编程语言中都可以方便的使用BCrypt相关函数,下面以Python为例:
1 | #!/usr/bin/env python3 |
运行结果如下:
1 | [salt] b'$2b$12$lEsQ9dGnRe2vKfFDRUZYAO' |
总结
MD5
从严格意义上来说并不是一个加密算法,更准确的说法应该是单向散列算法,因为无法逆向进行解密- 通过
MD5
计算后的密码,可以使用的破解方法有暴力枚举、字典表、彩虹表等,其中《彩虹表》最常用 BCrypt
算法可以随机生成盐,并将盐信息混入最终加密后的密码之中,验证时会自动提取BCrypt
算法引入了工作负载机制,生成Hash值的时间大大延长,相应的破解难度也随之增加BCrypt
算法在Python环境下使用默认参数需0.25秒生成一个密码,选用这种方式需考虑时间成本
以史为鉴,理解今天,展望未来~
时刻准备着,这次的大团圆无需担心,可能某个清晨的早间新闻,你们已经回来了!2021-11-1 00:21:44