我不确定密码哈希是如何工作的(将在以后实现),但现在需要创建数据库模式。
我正在考虑将密码限制为4-20个字符,但据我所知,加密后的哈希字符串将具有不同的长度。
那么,如何将这些密码存储在数据库中?
更新:仅使用哈希函数不足以存储密码。您应该阅读the answer from Gilles on this thread以获得更详细的解释。
对于密码,请使用密钥加强哈希算法,如Bcrypt或Argon2i。例如,在PHP中,使用password_hash() function,默认情况下使用Bcrypt。
$hash = password_hash("rasmuslerdorf", PASSWORD_DEFAULT);
结果是一个类似于下面的60个字符的字符串(但数字会有所不同,因为它会产生一个独特的盐)。
$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
使用SQL数据类型CHAR(60)
存储Bcrypt哈希的此编码。请注意,此函数不会编码为十六进制数字的字符串,因此我们不能轻易地将其解析为以二进制形式存储。
其他哈希函数仍然有用,但不能用于存储密码,所以我将保留下面的原始答案,写于2008年。
这取决于您使用的散列算法。无论输入如何,散列总是产生相同长度的结果。通常将文本中的二进制哈希结果表示为一系列十六进制数字。或者您可以使用UNHEX()
函数将十六进制数字字符串减少一半。
截至2015年,NIST recommends using SHA-256 or higher用于需要互操作性的散列函数的任何应用程序。但NIST不建议使用这些简单的哈希函数来安全地存储密码。
较小的散列算法有其用途(如应用程序的内部,而不是交换),但它们是known to be crackable。
对于md5 vARCHAR(32)是合适的。对于那些使用AES更好的人来说使用varbinary。
实际上,您可以使用CHAR(哈希长度)来定义MySQL的数据类型,因为每个哈希算法总是会计算出相同数量的字符。例如,SHA1始终返回40个字符的十六进制数。
你可能会发现这篇关于盐渍worthwhile的维基百科文章。我们的想法是添加一组数据来随机化您的哈希值;如果有人未经授权访问密码哈希,这将保护您的密码免受字典攻击。
作为固定长度的字符串(VARCHAR(n)或MySQL调用它)。散列总是固定长度,例如12个字符(取决于您使用的散列算法)。因此,20个字符的密码将减少为12个字符的哈希值,而4个字符的密码也会产生12个字符的哈希值。
Argon2赢得了2015年密码哈希竞赛。 Scrypt,bcrypt和PBKDF2是较旧的算法,现在被认为不太受欢迎,但仍然基本上是合理的,所以如果你的平台还不支持Argon2,那么现在可以使用另一种算法。
切勿直接在数据库中存储密码。也不要加密它:否则,如果您的站点被破坏,攻击者将获得解密密钥,因此可以获取所有密码。密码必须经过哈希处理。
密码散列具有与散列表散列或加密散列不同的属性。切勿在密码上使用普通的加密哈希,如MD5,SHA-256或SHA-512。密码散列算法使用salt,它是唯一的(不用于任何其他用户或任何其他人的数据库)。盐是必要的,以便攻击者不能只预先计算常见密码的哈希值:使用盐,他们必须重新开始每个帐户的计算。密码散列算法本质上很慢 - 尽可能慢。缓慢伤害攻击者比你更多,因为攻击者必须尝试许多不同的密码。有关更多信息,请参阅How to securely hash passwords。
密码哈希对四条信息进行编码:
许多库包含一对函数,可以方便地将此信息打包为单个字符串:一个获取算法指示符,硬度指示符和密码,生成随机盐并返回完整的哈希字符串;并将一个密码和完整的哈希字符串作为输入,并返回一个指示密码是否正确的布尔值。没有通用标准,但常见的编码是
$algorithm$parameters$salt$output
其中algorithm
是编码算法选择的数字或短字母数字字符串,parameters
是可打印的字符串,salt
和output
在Base64中编码而不终止=
。
对于salt和输出,16个字节就足够了。 (参见例如recommendations for Argon2。)在Base64中编码,每个21个字符。另外两个部分取决于算法和参数,但典型的是20-40个字符。这总共大约有82个ASCII字符(CHAR(82)
,并且不需要Unicode),如果您认为以后难以扩大字段,则应添加安全边距。
如果以二进制格式对哈希进行编码,则可以将算法降低到1个字节,硬度为1-4个字节(如果对某些参数进行硬编码),对于盐和输出分别为16个字节,总共37个字节。说40个字节(BINARY(40)
)至少有几个备用字节。请注意,这些是8位字节,不是可打印字符,特别是该字段可以包含空字节。
请注意,哈希的长度与密码的长度完全无关。
这实际上取决于您正在使用的散列算法。如果我没记错的话,密码的长度与哈希的长度关系不大。查看您正在使用的散列算法的规范,运行一些测试,并在其上方截断。
散列是一系列位(128位,160位,256位等,具体取决于算法)。如果MySQL允许,您的列应该是二进制类型,而不是文本/字符类型(SQL Server数据类型是binary(n)
或varbinary(n)
)。你也应该给哈希加盐。盐可以是文本或二进制,您需要一个相应的列。
为了向前兼容,您应该使用TEXT
(存储无限数量的字符)。哈希算法(需要)随着时间的推移变得越来越强大,因此这个数据库领域需要随着时间的推移支持更多的字符。此外,根据您的迁移策略,您可能需要在同一字段中存储新旧哈希,因此不建议将长度固定为一种类型的哈希。
我总是测试找到加密字符串的MAX字符串长度,并将其设置为VARCHAR类型的字符长度。根据您将拥有的记录数量,它可以真正帮助数据库大小。