哈希算法是一个单向函数。它可以将任何大小的数据转化为定长的“指纹”,并且无法被反向计算。另外,即使数据源只改动了一丁点,哈希的结果也会完全不同
hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
这样的特性使得它非常适合用于保存密码,因为我们需要加密后的密码无法被解密,同时也能保证正确校验每个用户的密码。
常用户注册和认证的流程是这样的:
1.用户注册一个帐号.
2.密码经过哈希加密储存在数据库中。只要密码被写入磁盘,任何时候都不允许是明文
3.当用户登录的时候,从数据库取出已经加密的密码,和经过哈希的用户输入进行对比
4.如果哈希值相同,用户获得登入授权,否则,会被告知输入了无效的登录信息
第4步中,永远不要告诉用户到底是用户名错了,还是密码错了。只需要给出一个大概的提示,比如“无效的用户名或密码”。这可以防止攻击者在不知道密码的情况下,枚举出有效的用户名。
用于保护密码的哈希函数和你在数据结构中学到的哈希函数是不同的。比如用于实现哈希表这之类数据结构的哈希函数,它们的目标是快速查找,而不是高安全性。只有加密哈希函数才能用于保护密码
破解哈希加密最简单的办法,就是去猜,将每个猜测值哈希之后的结果和目标值比对,如果相同则破解成功。两种最常见的猜密码的办法是字典攻击和暴力攻击。
字典攻击需要使用一个字典文件,它包含单词、短语、常用密码以及其他可能用作密码的字符串。其中每个词都是进过哈希后储存的,用它们和密码哈希比对,如果相同,这个词就是密码。字典文件的构成是从大段文本中分解出的单词,甚至还包括一些数据库中真实的密码。然后还可以对字典文件进行更进一步的处理使它更有效,比如把单词中的字母替换为它们的“形近字”(hello变为h3110)。
• 暴力攻击会尝试每一个在给定长度下各种字符的组合。这种攻击会消耗大量的计算,也通常是破解哈希加密中效率最低的办法,但是它最终会找到正确的密码。因此密码需要足够长,以至于遍历所有可能的字符串组合将耗费太长时间,从而不值得去破解它。
加盐
可以在密码中混入一段“随机”的字符串再进行哈希加密,这个被字符串被称作盐值
,这使得同一个密码每次都被加密为完全不同的字符串。为了校验密码是否正确,我们需要储存盐值。通常和密码哈希值一起存放在账户数据库中,或者直接存为哈希字符串的一部分。
要求:用户创建账户或每次修改密码时,都应该重新生成新的盐值进行加密。为了使攻击者无法构造包含所有可能盐值的查询表,盐值必须足够长。一个好的做法是使用和哈希函数输出的字符串等长的盐值,比如SHA256算法的输出是256bits(32 bytes),那么盐值也至少应该是32个随机字节。
一个好的标准的是:盐值至少和哈希函数的输出一样长;盐值应该被储存和密码哈希一起储存在账户数据表中。
存储密码的步骤
使用CSPRNG生成一个长度足够的盐值
将盐值混入密码,并使用标准的加密哈希函数进行加密,如SHA256
把哈希值和盐值一起存入数据库中对应此用户的那条记录
校验密码的步骤
从数据库取出用户的密码哈希值和对应盐值
将盐值混入用户输入的密码,并且使用同样的哈希函数进行加密
比较上一步的结果和数据库储存的哈希值是否相同,如果相同那么密码正确,反之密码错误
当用户忘记密码的时候,怎样进行重置?
个人的观点是,当前所有广泛使用的密码重置机制都是不安全的。如果你对安全性有极高的要求,比如一个加密服务,那么不要允许用户重置密码。
大多数网站向那些忘记密码的用户发送电子邮件来进行身份认证。首先,需要随机生成一个一次性的令牌,它直接关联到用户的账户。然后将这个令牌混入一个重置密码的链接中,发送到用户的电子邮箱。最后当用户点击这个包含有效令牌的链接时,提示他们可以设置新的密码。要确保这个令牌只对一个账户有效,以防攻击者从邮箱获取到令牌后,用来重置其他用户的密码。
令牌必须在15分钟内使用,并且一旦被使用就立即失效。当用户重新请求令牌时,或用户登录成功时(说明他还记得密码),使原令牌失效也是一个好做法。如果一个令牌始终不过期,那么它一直可以用于入侵用户的帐号。电子邮件(SMTP)是一个纯文本协议,并且网络上有很多恶意路由在截取邮件信息。在用户修改密码后,那些包含重置密码链接的邮件在很长一段时间内依然缺乏保护。因此应该尽早使令牌过期,降低把用户信息暴露给攻击者的可能。
攻击者是可以篡改令牌的,所以不要把账户信息和失效时间存储在里面。这些信息应该以不可猜解的二进制形式存在,并且只用来识别数据库中某条用户的记录。
永远不要通过电子邮件向用户发送新密码,同时也记得在用户重置密码的时候随机生成一个新的盐值用于加密,不要重复使用之前密码的那个盐值。
原文章
https://www.cnblogs.com/makai/p/11130703.html