目录
一. 数据库为什么不能明文存储密码
二. MD5到底是什么?
2.1 MD5概述
2.2 MD5为什么不是加密算法?
2.3 MD5主要特点MD5
2.4 MD5的性质
2.5 为什么用MD5存储密码不好
三. 给密码加盐再落库,增加破解成本
四. BCrypt算法加密解密
五. 不用摘要算法,加密存储行吗?
一. 数据库为什么不能明文存储密码
不仅仅是为了防止系统管理员或者DBA等公司人员获用户的密码,也是防止被黑客拖库产生更大的信息泄露。
如果黑客通过不法手段获取了服务的数据库存储信息,盗取里面的内容,从而直接获得明文密码,那么影响就会很大。
因为绝大部分人的所有账户密码都会设置成一样的,只要知道一个网站的明文密码后,基本上就等于搞定了这个用户其他网站的所有账号,也就是撞库。
所以,我们做网站的话不能直接明文存储密码,需要对用户的明文密码进行一个加密处理。
二. MD5到底是什么?
2.1 MD5概述
MD5,全称应该为Message Digest Algorithm 5(中文名为消息摘要算法第五版),属于Hash算法的一类。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要(32位的数字字母混合码)。
MD5是计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。该算法的文件号为RFC 1321(R.Rivest,MIT Laboratory for Computer Science and RSA Data Security Inc. April 1992)。
2.2 MD5为什么不是加密算法?
实际上,经常有人会说拿MD5加密,其实这样说是没有文艺的,但我们在心里要清楚,MD5压根不是加密算法,它其实就是个摘要算法。
- 加密算法指的是把一段数据加密后,可以解密;
- 很明显MD5无法解密,只能暴力穷举破解,所以它不算是加密算法;
2.3 MD5主要特点MD5
不可逆,相同数据的肯定一样,不同数据的MD5值肯定不一样(一个MD5理论上的确是可能对应无数多个原文的,因为MD5是有限多个的而原文可以是无数多个)
比如:主流使用的MD5将任意长度的“字节串映射为一个128bit的大整数。也就是一共有2^128种可能,大概是3.4*10^38,这个数字是有限多个的,而但是世界上可以被用来加密的原文则会有无数的可能性
2.4 MD5的性质
- 压缩性:任何长度的数据,算出的MD5值的长度都是固定的(相当于超损压缩);
- 容易计算:从原数据计算出MD5值很容易;
- 抗修改性:对原数据进行任何改动,哪怕只修改一个字节,所得到的MD5值都有很大区别;
- 弱抗碰撞:已知原数据和其MD5值,想找一个具有相同MD5值的数据(即伪造数据)是非常困难的;
- 强对抗性:想找到两个不同的数据,使它们具有相同的MD5,是非常困难的;
2.5 为什么用MD5存储密码不好
大部分人的密码会设置得比较简单,比如名字缩写加上个出生日期这种。
二黑客其实会针对常见的一些密码,生成彩虹表。
- 彩虹表:适用于加密散列函数逆运算的预先计算好的表,常用于破解加密过的密码散列,如下所示:
这样一来只要准备得足够充分,彩虹表足够大,那么直接对比彩虹表就能反推得出明文密码,所以直接简单用MD5也是不安全的。
三. 给密码加盐再落库,增加破解成本
其实彩虹表大部分能找到的只是常见的密码。
基于只一点,我们虽然不能强迫用户设置一些非常复杂的密码(因为这会是用户的记忆成本增高)。
但是我们可以手动给用户的密码拼接上一些犊砸的字符,然后经过哈希函数处理之后落库。
比如:
用户的初始密码为123456,我们给他的密码加点盐,盐其实就是一些复杂的字符数字,如下所示:
这样即使不法分子盗取到密码,预先准备的彩虹表也无用(因为密码变得不常用了),使得破解的成本变高。
这种盐叫做固态盐,不需要落库存储,一般是在代码或者配置中保存。一旦被不法分子试出了这个盐,那么继而就能通过这个盐实处别的密码。
所以推荐使用动态盐,即让每个账号下密码加的盐都是不一样的,这样一来,不法份子的破解成本就更高了。
动态盐需要分别为每个用户记录对应密码加的盐值,一般是落库存储,比如上图所示在用户表上加个 salt 字段。
又或者直接跟密码拼在一起中间用特殊符号切分等等,比如下图用 $ 来分割。(没错,动态盐是直接存储的,也就是说攻击者可以拿到每个账号的盐)。
其实加盐的操作还有其他各种方案,比如 不加字段也不用分隔符,把用户创建时间进行处理作为动态盐,等等……
加盐这种手段仅仅知识增加了攻击者的破解成本,因为攻击者这道盐值,从而就能反推出一个值,使得一个 MD5(值+盐)=MD5 (密码+盐):
因为不论这个值是否等于密码,反正只要最终 hash 的结果是一样的,就都能登录,所以攻击者要推是可以推出来的,只不过成本会更高些。
总而言之:
通过摘要算法来存储密码,不法分子是可以通过暴力、彩虹表、字典等方式来破解的。
如果我们仅仅是用MD5处理密码存储,那么这些破解其实成本也不是很大,毕竟目前网上已经有某些MD5破解网站,专门用来查询MD5。
曾经网上有一个结论:MD5来存储6位数长度的密码(仅仅包含小写和数字),只需要40秒,就可以穷举所有密码。
当然,只要你的盐足够长足够乱,得到的MD5码就更难查到。
四. BCrypt算法加密解密
为了进一步给黑客们增加破解成本,需要替换 MD5 这类 hash 快速的方法换成Bcrypt 这种算法。
MD5 计算只需要1微秒,而 BCrypt 需要 0.3 秒,速度就差了30万倍,毕竟 1 秒 = 1000000 微秒 !
因此,如果本来彩虹破解 MD5 需要40 秒就能破解的话,换成 Bcrypt 后就变成了138天才能破解!
这是因为 Bcrypt 是单向hash加密算法,一般用于密码加密,它有个迭代次数,可以使计算变慢。相对来说,Bcrypt 比 MD5 更安全,但 MD5 加密会更快速。
MD5是一种可反向破解的密码加密,如果你的密文被截获它就可以在 MD5 在线解密破解得到密码,然后就可以根据你的账户密码登录账号。而 Bcrypt 类似 Pdkdf2 算法,不可反向破解生成明文(不可逆加密),所以及时黑客截获到密文也无法转换成明文(Bcrypt不支持反运算,只支持密码校验)。
虽然不能转换成明文密码,但是它还是会被彩虹破解,只是相对于破解时间成本更大一些。
Bcrypt四个变量:
- saltRounds:正数,代表hash杂凑次数,数值越高越安全,默认10次;
- myPassword:明文密码字符串;
- salt::盐,一个128bits随机字符串,22字符;
- myHash:经过明文密码password和盐salt进行hash,个人的理解是默认10次下 ,循环加盐hash10次,得到myHash;
每次明文字符串myPassword过来,就通过10次循环加盐salt加密后得到myHash, 然后拼接BCrypt版本号+salt盐+myHash等到最终的bcrypt密码 ,存入数据库中。
这样同一个密码,每次登录都可以根据自省业务需要生成不同的myHash, myHash中包含了版本和salt,存入数据库。
五. 不用摘要算法,加密存储行吗?
我们一直说加密加密,其实我们还有一种防破解的方式,就是使用加密算法。比如采用对称加密 AES ,这样只要密钥不泄露,攻击者拖库拿到密码也完全破解不了!!!
但是反过来想,加入密钥被泄露了,那我们的加密就相当于无,白给了,比破解上述的hash(密码+盐)更轻松,连试错的机会都不需要了!
所以一旦使用加密存储的话,就得看你的密钥能不能保住不泄露了!!!