使用哈希密码的安全性问题

一、 哈希密码

哈希是一种散列函数,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。
在密码学当中,HASH主要用于信息安全领域中加密算法,它把一些不同长度的信息转化成杂乱的128位的编码里,叫做HASH值. 也可以说,hash就是找到一种数据内容和数据存放地址之间的映射关系。MD4和MD5是哈希密码的主要算法。

二、 哈希密码的安全隐患

哈希函数本来是不可逆的函数,也就是说知道了哈希值也不能使用算法把原文推算出来。但是由于常见字符串的哈希值,可以通过查表的方式找到原文,比如彩虹表等等。所以目前还是存在一些数据库可以查到简单字符串的哈希值的,这样就造成了用哈希函数加密的密文安全性不可靠。

三、 哈希盐值

盐值就是程序随机产生的随机字符串组合。
加盐后的散列值,可以极大的降低由于用户数据被盗而带来的密码泄漏风险,即使通过彩虹表寻找到了散列后的数值所对应的原始内容,但是由于经过了加盐,插入的字符串扰乱了真正的密码,使得获得真实密码的概率大大降低。那么它的原理是什么呢?
查表法和彩虹表只有在所有密码都以相同方式进行哈希加密时才有效。如果两个用户密码相同,那么他们密码的哈希值也是相同的。我们可以通过“随机化”哈希来阻止这类攻击,于是当相同的密码被哈希两次之后,得到的值就不相同了。为了校验密码是否正确,我们需要储存盐值。通常和密码哈希值一起存放在账户数据库中,或者直接存为哈希字符串的一部分。
加盐值的时候需要注意以下几点:
1、 盐值不能重复。两个相同的密码会得到相同的哈希值。攻击者可以使用反向查表法对每个值进行字典攻击,只需要把盐值应用到每个猜测的密码上再进行哈希即可。如果盐值被硬编码到某个流行的软件里,可以专门为这个软件制作查询表和彩虹表,那么破解它生成的哈希值就变得很简单了。用户创建账户或每次修改密码时,都应该重新生成新的盐值进行加密。
2、 盐值不能太短。如果盐值太短,攻击者可以构造一个查询表包含所有可能的盐值。以只有3个ASCII字符的盐值为例,一共有95x95x95=857,375种可能。同样地,用户名也不应该被用作盐值。尽管在一个网站中用户名是唯一的,但是它们是可预测的,并且经常重复用于其他服务中。攻击者可以针对常见用户名构建查询表,然后对用户名盐值哈希发起进攻。
为了使攻击者无法构造包含所有可能盐值的查询表,盐值必须足够长。一个好的做法是使用和哈希函数输出的字符串等长的盐值,比如SHA256算法的输出是256bits(32 bytes),那么盐值也至少应该是32个随机字节。
3、 不使用组合哈希。人们经常不由自主地认为将不同的哈希函数组合起来,结果会更加安全。实际上这样做几乎没有好处,仅仅造成了函数之间互相影响的问题,甚至有时候会变得更加不安全。

四、哈希加盐存储密码的步骤

存储密码的步骤
1. 使用CSPRNG(伪随机数生成器)生成一个长度足够的盐值
2. 将盐值混入密码,并使用标准的加密哈希函数进行加密,如MD5
3. 把哈希值和盐值一起存入数据库中对应此用户的那条记录
校验密码的步骤
1. 从数据库取出用户的密码哈希值和对应盐值
2. 将盐值混入用户输入的密码,并且使用同样的哈希函数进行加密
3. 比较上一步的结果和数据库储存的哈希值是否相同,如果相同那么密码正确,反之密码错误