第一次听说盐值加密的时候,总是感觉怪怪的。因为总会联想到咸,联想到密码是咸的。
其实这里所说的盐,简单的说,就是一组安全随机数。它会在特定的时候,加入到密码中(一般来说是加密后的密码)。从而使密码变得更有味道(从单一简单化到复杂化),更安全。
下面我们就通过安全威胁分析分别说说当前两种加盐的形式:
一、数据库泄露
众所周知,用户名和密码是被保存在数据库中。可是一旦数据库发生了泄露,用户名和密码就都遭到了泄露。攻击者可以轻松的获取用户名和密码,进行操作。更大的危害是,由于现在需要注册的网站、app越来越多。用户名和密码很多时候都是相同的。一旦某处发生了泄露,则后果会慢慢的扩散。这些危害大家可以查询下近些年发生的一些安全事故,如Sony数据库泄露、网易数据库泄露、CSDN数据库泄露等。
解决这个问题的通用方法是:
1、对密码进行加密存储
这样的好处是,即使数据库发生了泄露,攻击者也不会拿到明文密码,依然无法直接使用这些密码。
但是这样的存储方式也存在缺点:很多用户在注册时都是使用的弱密码。攻击者可以通过大量的注册用户,这些用户使用扩散的使用各种弱密码。当拿到数据库密文后,根据已知的用户名密码,就可以获取到相关的彩虹表。然后依据彩虹表依次匹配数据库中的密码。这样就可以得到其中使用弱(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )密码的用户了。同时app、web等软件由于用户体验等原因,也不可能让用户设置安全系数过高的密码。如8位以上、包含大小写、特殊字符、于最近三次的密码不能相同、于上次密码至少有三位不同、不能包含密码字典中涉及的简单密码等等。举个例子:如ATM、微信支付密码使用的是纯6位数字,这样就有了10^6种可能,攻击者只要拿到了全套的密码对应的彩虹表,就可以获取到所有用户的密码。这套彩虹表,攻击者可以通过使用大量的简单密码注册用户得到。然后从获取到的数据库中找到攻击者自己注册的这些用户数据,进而拿到彩虹表。那么该怎么解决呢?这就涉及到固定盐值加密。
2、对密码进行加密
如前文所说,这个盐是一个随机数。当用户注册一个简单密码时,系统会同时生成这样一个salt,于该用户对应,保存到数据库中。
这样当用户的密码是888888时,后台真实存储的密码时888888盐化以后的值。
操作步骤如下:
(1)注册、修改密码时,前台将 888888加密后的pwd1,传入后台
(2)后台拿到pwd1以后,生成一个相应的随机数 salt。将pwd1与salt拼接并再次加密,生成pwd2
(3)后台将pwd2和salt 一并存储到数据库中。
(1-)当用户每次输入用户名密码后,将密码加密生成pwd1‘后,传入后台。
(2-)后台拿到pwd1‘后,根据用户名id拿到对应的盐值。与盐值拼接加密后,生成pwd2‘。
(3-)然后判断pwd2‘与数据库中的pwd2是否一致即可。
这里有两点需要注意:
1、密码在前后台的加密方式可以采用不同的形式
2、盐值的拼接不一定非要拼接到最后,也可以放在前边、插在中间、甚至拆开或者倒序拼接。
3、(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
这样即使是简单密码也没关系。因为相同的密码在数据库中存储的值并不一样。攻击者无法构造有效的彩虹表进行破解。
(二)重放攻击
先抛开前边的固化盐值加密不说,我们再说说另外一种攻击方式:重放攻击(Replay Attacks)又叫重播攻击、回放攻击或新鲜性攻击(Freshness Attacks)。
这里举个简单的例子:当用户A进行登录后,前台会将加密后的密码,以数据包的形式发送到服务端。服务端会进行盐化等加密手段后,再进行安全校验。可是如果这个数据包被攻击者截获。并且分析出数据包的结构(如哪些字段代表用户名、哪些代表IP/会话ID),然后进行适当的修改,再次发送给服务端后,服务端依然会进行常规的校验,依然会验证通过。也就是说无论客户端,服务端的加密手段多么的复杂,一旦攻击者有能力截获和修改前后台通信的数据包,那么这些攻击都将不起作用。
那么如何防范呢?仔细想想重放攻击,攻击者利用的是每次发送的包(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )中用户名密码等部分不变的机理。
那么我们可以让他改变,怎么改变呢?
大致思路如下:
(1-)每次登陆时,我们可以生成一个随机数(一个动态生成的salt),这个salt在前后台各自保存一份。
(2-)当用户名输入完密码pwd后。前台会进行 f1(pwd)加密,然后与动态生成的salt拼接,然后再次加密。
也就是 pwd1=f2(f1(pwd)+salt)。之后前台就把这个pwd1发送到后台。(注意由于动态salt每次都会改变,所以pwd1每次也会改变)
(3-)后台拿到数据后,如果没有使用固化盐值加密的话,直接将数据库中的数据采用相同的方式与服务端保存的动态salt拼接加密然后再对比即可。
如果同时存在固化盐值加密的话,需要想办法剔除掉这个动态salt(即f2()使用可逆的机密算法),然后再拼接固化salt接着再次加密,最后与数据库对比即可。