大家都知道,不管什么系统,只要有用户登录模块的,必然在系统数据库中会存有用户的用户名和密码。用户名明文存储完全没有问题,这里我们就谈谈如何正确地来存储用户的密码。
有些小伙伴可能就说管他怎么存储呢,直接明文存储也没关系。可是这事关我们的信息安全哦!试想一下,如果我们的QQ账号密码都是明文存储在数据库的,那么如果一旦QQ的数据库信息泄漏了。我们的账号和密码信息是不是也泄漏了。那么获得这些信息的人就随意登录我们的QQ号的,这该是一件多么可怕的事情。有童鞋又会说,腾讯的技术那么厉害,怎么可能出现数据库泄漏呢?好,那么我们就不说数据库泄漏,就来说说每个数据库都需要有一些管理维护人员,也就是我们经常听到的DBA。他们的工作也就给了他们权限可以查看一些数据信息,那么大家的QQ用户名和密码就会暴露给他们。不管怎么样,心里至少是有些担心的吧。
当然事实上,也是有公司用的明文存储的密码。时间相对比较早了,在零几年还是10年左右,两家相对还算大型的博客和论坛的数据库信息泄漏了——在这里就不点名了,让人大跌眼镜的是,用户密码竟然都是明文存储。
所以,说了这么多,正确的存储密码的姿势是什么呢?这在Sunny当年开始学后端编程的时候,老师强调过的,密码一定要经过哈希不可逆加密后存入数据库!也就是
密码在磁盘上必须是以加密后的形式存在
而随着经历过的项目越来越多,接触到的密码存储做法也比较多。有直接一个md5函数就放进数据库的,也有做一些特殊处理的,比如加盐。
这边我们还是以md5为例子,给大家展示一下。这里可以给大家推荐一个比较好用的在线md5加密的工具:站长工具。我们先生成一个sunny的md5结果看看,这里选择生成32位大写字母作为结果:
生成的密文是:
533C5BA8368075DB8F6EF201546BD71A
然后,我们生成Sunny的密文:
生成的密文是:
FFC76083445E28A7E4B314A07A8C3B6A
不了解哈希加密的童鞋从这次示例就能知道了,哈希加密的话,真的是“失之毫厘,差之千里”。这也是它的一个“魅力”所在吧。
另外说一点题外话,其实也不算是题外话,和哈希加密还是息息相关的。早在04年的时候,王小云教授就在一次密码学国际会议上提出了一种可以攻破md5的算法,当然破解的思路主要还是在于碰撞。碰撞简单解释一下,就是两个完全不同的明文得出了相同的哈希值。为什么会出现这种情况呢?拿我们刚才生成密文的情况作为例子,如果是32位的密文,那么密文的组合总数只有2^32这么多,但是如果明文的长度要大于32位或者明文的长度为32位但是包含大小写字母和特殊字符,这样明文的组合数就要大于密文的组合数量,所以必然存在多个明文映射到一个密文的情况。
为什么说这个是题外话呢?这样一来,md5不是已经不安全了吗?我们这里为什么还说md5。事实上,碰撞主要基于明文有较长的长度,至少要比密文要长,通常对文件进行哈希的时候(生成数字签名),需要考虑碰撞的问题,而用户密码通常长度较小,所以相对来说碰撞法较难破解。
ps 其实Sunny和王小云教授也算是校友。好了,啥也不说了,默默搬砖去咯。
言归正传,我们来说说如何加盐。
什么是盐
有些童鞋可能对这个名词还有些陌生,这个盐当然不是我们平时吃的盐,也不是化学中的盐,而是一段字符串,用于和明文串接在一起然后哈希得到密文。比如我的密码是sunny (这当然不是真的密码...),然后我的盐为abc,那么拼接在一起就可以是sunnyabc,然后以此哈希后存入数据库。当我再次登录的时候,再将我的密码加盐后哈希与数据库存储的密码比对。
为什么要加盐
我们从暴力破解说起,面对一个md5加密的密文,你会考虑这么破解。可以跑密码字典,也可以用查表法,包括反向查表,彩虹表之类的。其实本质都是暴力破解,只不过现场跑密码字典很慢,而用查表的话,特别是表的数据已经累计到一定程度之后,很可能一查一个准,就有点类似我们的缓存。所以我们需要加盐,即使通过一定的手段得到了明文,在不知道盐的情况下,也会增加一定的破解负担。
如何加盐
如何加盐其实主要指的是如何选择盐,通常盐的长度需要较长,短盐的效果可能不是那么好。其实通常各种资料里会建议用一个随机生成的盐。这样能确保每个密文的盐尽量不同,增加破解难度。
但是Sunny思考了一下,使用随机生成的盐也是有一定的弊端,较大的弊端就是,这个盐也必须存储,所以也是有机会获取的。所以,我在这里就提出一种思路,至于好不好大家可以讨论一下。
首先,考虑生成的盐是每个用户有所区别的。这一点很重要,作用类似于随机生成的盐。
然后,考虑这个盐不能进行存储,而是可以用现有的用户信息进行生成。这样其实已经很明显了,可以用某种算法利用当前用户的信息(必须是固定不会修改的信息),比如用户id、用户注册时间等。这个算法也可以是哈希加密算法,比如将用户的几个信息进行一定的排序处理之后利用哈希生成盐。