我不确定密码哈希的工作原理(稍后将实现它),但现在需要创建数据库模式。
我考虑将密码限制在4-20个字符内,但我了解到加密后的哈希字符串长度会有所不同。
那么,如何在数据库中存储这些密码呢?
我不确定密码哈希的工作原理(稍后将实现它),但现在需要创建数据库模式。
我考虑将密码限制在4-20个字符内,但我了解到加密后的哈希字符串长度会有所不同。
那么,如何在数据库中存储这些密码呢?
$hash = password_hash("rasmuslerdorf", PASSWORD_DEFAULT);
$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
CHAR(60)
来存储Bcrypt哈希的编码。请注意,该函数不会将其编码为十六进制数字字符串,因此我们不能像将其解码为二进制字符串那样容易地进行解码。UNHEX()
函数将十六进制数字字符串减半。
Argon2赢得了2015年的密码哈希竞赛。Scrypt, bcrypt和PBKDF2是较旧的算法,现在被认为不太受欢迎,但仍然基本上是可靠的,所以如果您的平台还不支持Argon2,现在使用其他算法也可以。
永远不要直接将密码存储在数据库中。也不要加密它:否则,如果您的网站被攻击,攻击者会获得解密密钥,从而可以获取所有密码。密码必须进行哈希处理。
一个密码哈希与哈希表哈希或加密哈希具有不同的属性。绝不要在密码上使用普通的加密哈希,例如MD5、SHA-256或SHA-512。密码哈希算法使用唯一的盐(不用于任何其他用户或任何其他数据库)。盐是必需的,以便攻击者不能预先计算常见密码的哈希值:有了盐,他们必须为每个帐户重新启动计算。密码哈希算法本质上是缓慢的——尽可能缓慢。缓慢会对攻击者造成更大的伤害,因为攻击者必须尝试许多不同的密码。有关更多信息,请参见如何安全地哈希密码。许多库包括一对函数,将此信息方便地打包为单个字符串:一个函数接受算法指示符、硬度指示符和密码,生成随机盐并返回完整的哈希字符串;另一个函数接受密码和完整哈希字符串作为输入,并返回一个布尔值,表示密码是否正确。没有通用标准,但常见编码是
$algorithm$parameters$salt$output
其中algorithm
是一个数字或短的包含算法选择信息的字母数字字符串,parameters
是可打印的字符串,salt
和output
以Base64编码,不包含终止符=
。
盐和输出需要16个字节足够了(参见例如Argon2的推荐)。以Base64编码,每个部分需要21个字符。另外两个部分取决于算法和参数,但通常为20-40个字符。总共大约82个ASCII字符(CHAR(82)
,不需要Unicode),如果您认为将来可能需要扩大字段,则应添加一些安全余量。
如果您以二进制格式编码哈希值,则可以将其缩小到1个字节的算法,1-4个字节的硬度(如果硬编码某些参数),以及16个字节的盐和输出,总共37个字节。说是40个字节(BINARY(40)
)以便至少有几个备用字节。请注意,这些是8位字节,而不是可打印字符,特别是该字段可以包含空字节。
请注意,哈希值的长度与密码的长度完全无关。
你实际上可以使用 CHAR
(哈希长度) 来定义 MySQL 中的数据类型,因为每个哈希算法始终会计算出相同数量的字符。例如,SHA1
始终返回一个由40个十六进制数字组成的字符串。
你可能会发现这篇关于盐值的维基百科文章有价值。其思想是添加一组数据来随机化哈希值,从而保护你的密码免受字典攻击,即使有人未经授权访问了密码哈希。
为了确保向前兼容性,您应该使用TEXT
(可存储无限数量的字符)。哈希算法随着时间的推移变得越来越强大,因此这个数据库字段需要随着时间的推移支持更多的字符。此外,根据您的迁移策略,您可能需要在同一字段中存储新旧哈希值,因此不建议将长度修复为一种类型的哈希值。
哈希是一系列位(128位、160位、256位等,取决于算法)。如果MySQL允许,则您的列应为二进制类型,而不是文本/字符类型(SQL Server数据类型为binary(n)
或varbinary(n)
)。您还应该对哈希进行盐处理。盐可以是文本或二进制,并且您需要相应的列。
这真的取决于你使用的哈希算法。密码的长度与哈希的长度关系不大,如果我没记错的话。查找你正在使用的哈希算法的规格,运行几个测试,并在上面截断。
我一直在测试加密字符串的最大长度,并将其设置为VARCHAR类型的字符长度。根据你将要拥有的记录数量,这可能会真正帮助减小数据库大小。
对于 MD5,VARCHAR(32) 是合适的。对于使用 AES 的用户最好使用 VARBINARY。