将散列密码存储到Mysql


store hashed passwords to Mysql

我正在研究在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。

验证登录尝试的推荐工作流程:

  1. 用户提供用户名和密码。小心处理Unicode规范化和编码
  2. 散列后的密码是根据用户名从数据库中提取的
  3. 对散列后的密码进行解析以确定所使用的算法
  4. 调用正确的算法时,用户密码作为输入,散列密码作为salt
  5. 如果两个散列匹配,则用户会提供正确的密码

建议设置新密码的工作流程:

  1. 如果用户已经存在,请对其进行身份验证
  2. 从用户处获取新密码。注意处理Unicode规范化和编码。向用户反馈其密码的强度(但不要用愚蠢的要求(如禁止字符或限制最大长度)来挫败用户)
  3. 创建一个新的salt,它不能依赖于用户输入,如密码或用户名
  4. 选择一个强大的密码哈希函数,并使用新的salt对密码进行哈希
  5. 更新DB以存储新密码以及哈希函数的标识符

进一步评论:

  • 加密数据是二进制数据,不应存储为文本(请使用blob)
  • 哈希通常表示为纯文本,而不是二进制数据,因为文本更容易存储
  • 在许多场景中,您可以使用OpenID,而不是实现自己的身份验证。例如,Stack Exchange提供使用OpenID登录。因为我使用了这个选项,所以我从未向SE透露过密码
  • 我没有密码背景。信息安全经常出现了解更多情况的人

[1]这里,"明文"是指可打印的ASCII字符。它不是指密码的明文