一、最近在项目登录部分牵涉到密码安全问题,本人在各技术社区寻找更好的解决方案。方案主要从两个方面考虑
1:hash或者加密出来的值保证安全,能够预防一些常见的数据泄露场景。比如被拖库或者被网络前端后端互发数据
被人抓包导致密码泄露
2:加密效率问题,在网络安全领域始终按照道高一尺魔高一丈的定律发展,任何个密码只要是给足够的时间都是能够
破解出来,但是时间、财力成本已经超过本身价值,就没有意义了。不然干脆直接上格密码,抵抗量子的加密。。。
二、项目最初前端传到后端是明文传输,后端接收到的Password是明文。
1、使用MD5直接Hash得到密码摘要,但是MD5已经有彩虹表能够爆破目前MD5的Hash值,比如王小云教授就破解出来了MD5Hash。所以只是一个MD5在存储敏感信息的时候是不可行的。
2、使用MD5加盐的操作,假如说密码是"123456",salt盐值是"999"。假如做多个密码MD5再Hash后,他们被爆破出来的密码都能够找出相同规律提取到密码。123456999、354213999、123155999。
3、理论来说加盐的保证安全必须要盐是足够的复杂或者随机,防止被爆破出密码。但是固定的盐值如2已经说了。如果是盐值随机,那么需要把随机的盐值保存下来,在验证的时候进行提供,这样就相当于
在数据库中暴露了盐值也是不安全的。
在目前来看比较稳定的hash算法:
4、可以双重hash,本人在各彩虹表网站上试了一下,双重Hash后的hash值很难被爆破。
5、项目最终采用的是前端->后端:双重MD5+盐值(组合),后端->数据库采用Spring Security的BCryptPasswordEncord,进行随机加盐值。
二、Spring Security的BCryptPasswordEncord原理:
BCryptPasswordEncord底层使用的不是MD5进行Hash消息,使用的是BCrypt加密算法,而底层又是使用的Blowfish加密算法,BCrypt会使用一个随机加盐的流程防御彩虹表的攻击。
性能上比较:BCrypt计算出一个加密数据需要0.3秒,而MD5只需要1us。但是假如一个40秒可以穷举出来的MD5值,BCrypt需要12年。
BCrypt加密后的格式为:
例子:$2a$10$fYHeYm0vODg9vA9ttHfsKO77VLW.caCs.nH9/Si6xeOqtUbPZNLpO
固定位$2a:
$1$: MD5-based crypt (‘md5crypt’)
$2$: Blowfish-based crypt (‘bcrypt’)
$sha1$: SHA-1-based crypt (‘sha1crypt’)
$5$: SHA-256-based crypt (‘sha256crypt’)
$6$: SHA-512-based crypt (‘sha512crypt’)
固定位$10:
10次循环加盐默认是10,数值越大生成字符串复杂度越高。
固定位fYHeYm0vODg9vA9ttHfsKO(22位):
真正的盐值是接下来的22位。
固定位77VLW.caCs.nH9/Si6xeOqtUbPZNLpO:
明文密码与盐值通过Blowfish-based crypt后的值。
加密过程:假如我的密码是123456,两次加密后的hash值分别是:
$2a$10$nvSGdRLljr00HkZm1f9xVuq7V6VZ0cT6xisPyilg0NvhpFFB6hIKq
$2a$10$fYHeYm0vODg9vA9ttHfsKO77VLW.caCs.nH9/Si6xeOqtUbPZNLpO
如何验证呢?
1、从这个hash值是无法拿到我的真实密码的,爆破穷举出来的时间也非常的长,并且随机加了盐值。
验证的过程:
1、取到22位盐值,拿到当前的明文password,用盐值加上数据库冲存储的fYHeYm0vODg9vA9ttHfsKO(例子),用原文密码给它一起混合再使用Blowfish-based crypt进行验证是否相同。
相同即成功。