分享个人 Full-Stack JavaScript 项目开发经验
静态密码是指储存在服务器中的密码数据。我们应该考虑在数据库被攻破的最坏情况下,如何保障用户密码的安全性。本文主要介绍关于此问题的相关概念。
密码熵(密码中信息的比特数)用于衡量密码的不可预知程度。通常,至少36.86比特的密码才算是好密码。
对于随机选择的密码,广为接受的熵计算公式是 H = log(b^l)/log(2)。其中 H 为密码熵,b 为字符集的符号数量,l 为密码长度。使用 javaScript 表示即为:
let H = Math.log(Math.pow(b,l))/Math.log(2);
对于人为选择的密码熵计算方法不一(各有缺陷),下面介绍在NIST 特刊 800-63-2章节 User Selected Passwords 中计算人为选定的密码熵规则:
对于人为选择的密码,通常会简短、容易猜测。如果直接取其哈希值,会容易受到如字典攻击和彩虹表攻击等威胁。加盐就是为了计算密码哈希值时加强数据。
盐值是一种随机数据,它的长度一般应该与哈希函数输出长度一致。PBKDF2 标准建议至少使用8字节长度的盐值。加盐后,即使相同的密码也可以得出不同的哈希值。足够长的盐值可以确保哈希值是唯一的。
hash(salt + password) = password hash
通过使用合适长度而且唯一的盐值,并且哈希函数迭代适当的次数可以放慢破解速度。
与盐值不一样,胡椒值通常是一个字符串或者在一组字符串中随机选取一个。它不如哈希值一起存储,视为私钥使用。
hash(salt + pepper + password) = password hash
目前哈希算法不接受胡椒值为参数,所以这也是胡椒引人争议的原因之一。
为了防范暴力攻击等媒介,需要使用密钥延伸。它把弱密码变成特别复杂的长密码。而对于哈希函数来说,不断循环迭代,直到得到所需长度和复杂度的哈希值就是密钥延伸的体现。
如果密码哈希值被窃取后,我们希望攻击者破解的速度越慢越好。所以对于密码加密算法,应该选择慢速度的、耗费硬件资源的更为合适。PBKDF2、bcrypt 和 scrypt 就是比较合适的密码加密算法。下面简单介绍它们的特点。
PBKDF2
bcrypt
scrypt