我正在研究在PHP.NET上对数据库进行哈希和存储密码。这个网站说:
例如,如果您将数据存储在MySQL数据库中,请记住varchar字段在插入过程中会自动删除尾部空格。由于加密的数据可能以空格(ASCII 32)结尾,因此数据将因删除而损坏。将数据存储在tinyblob/tinytext(或更大)字段中。
这些建议中哪一个更好?或者我可能不得不问:他们中的一个更好吗?如果答案是肯定的,哪个?最后,我应该如何使用PDO将密码存储到数据库。我想我可以像文件一样将信息写入blob行,但如果我从输入中获得值,则必须使用哪个方法或函数?请你解释一下好吗?
当存储散列密码时,删除空白是不成问题的:
- 您从不存储密码本身,而是存储哈希函数的输出
- 此哈希函数产生固定大小的输出(或者您可能使用可逆加密算法)
- 大多数散列函数的输出已经是固定大小的明文[1],不包括任何空格。否则,您可能使用了一个不用于密码哈希的哈希函数
- 固定大小的salt与哈希输出一起存储(知道salting的密码哈希函数通常使用哈希密码输出salt)
- 如果你想变得灵活,并能够在未来升级到更好的哈希函数,你还必须记住使用了哪个哈希函数。建议对此信息使用明文[1],这使得完整记录的长度可变。RFC 2307描述了这样一种可能的明文[1]存储方案
密码应该使用现代且经过验证的密钥拉伸算法进行散列,但不能使用SHA-256或MD5等加密散列函数。合适的算法包括PBKDF2、bcrypt或scrypt。
例如,散列字符串";通行短语";使用bcrypt和一种新的盐可以产生
$2a$12$PuYHvYwgKeD.hQ1Dv6nLQuxUkv5zP3lYLPHqdMOzgwPVaGGSAs07u
`-----'`-----------······· ·········-------'
algorithm random salt password hash
parameters
整个字符串可以用作salt,因为实际的密码哈希将被截断,而不能用作salt。
验证登录尝试的推荐工作流程:
- 用户提供用户名和密码。小心处理Unicode规范化和编码
- 散列后的密码是根据用户名从数据库中提取的
- 对散列后的密码进行解析以确定所使用的算法
- 调用正确的算法时,用户密码作为输入,散列密码作为salt
- 如果两个散列匹配,则用户会提供正确的密码
建议设置新密码的工作流程:
- 如果用户已经存在,请对其进行身份验证
- 从用户处获取新密码。注意处理Unicode规范化和编码。向用户反馈其密码的强度(但不要用愚蠢的要求(如禁止字符或限制最大长度)来挫败用户)
- 创建一个新的salt,它不能依赖于用户输入,如密码或用户名
- 选择一个强大的密码哈希函数,并使用新的salt对密码进行哈希
- 更新DB以存储新密码以及哈希函数的标识符
进一步评论:
- 加密数据是二进制数据,不应存储为文本(请使用blob)
- 哈希通常表示为纯文本,而不是二进制数据,因为文本更容易存储
- 在许多场景中,您可以使用OpenID,而不是实现自己的身份验证。例如,Stack Exchange提供使用OpenID登录。因为我使用了这个选项,所以我从未向SE透露过密码
- 我没有密码背景。信息安全经常出现了解更多情况的人
[1]这里,"明文"是指可打印的ASCII字符。它不是指密码的明文