在数据库中(最好是SQL Server 2005)存储密码的首选方法/数据类型是什么。我在几个应用程序中所做的工作方式是,首先使用.NET加密库,然后将它们作为二进制文件(16)存储在数据库中。这是首选方法,还是我应该使用其他数据类型或分配比16多的空间?
Answers:
我将密码的加盐哈希值存储在数据库中,而不是密码本身,然后始终将哈希值与用户传入的值之一进行比较。
将文字密码数据存储在任何地方都太危险了。这样就无法恢复,但是当有人忘记或丢失密码时,您可以进行一些检查并创建新密码。
varchar
数据库列中。考虑他们的部分的最后一点是定义其哈希字符串的格式,其中盐包含在字符串中。
通过这些措施,您的用户密码将受到很好的保护,防止:
由于哈希函数的结果是一系列介于0到255之间(或-128到127,取决于8位数据类型的有符号性)的字节,因此将其存储为原始二进制字段是最有意义的,因为它是最紧凑的表示形式,并且不需要其他编码和解码步骤。
一些数据库或驱动程序对二进制数据类型没有很好的支持,或者有时开发人员对它们不熟悉,以至于感觉不舒服。在那种情况下,可以使用像Base-64或Base-85这样的二进制文本编码,并将结果文本存储在字符字段中。
必填字段的大小由您使用的哈希函数确定。MD5总是输出16个字节,SHA-1总是输出20个字节。一旦选择了散列函数,通常就会受其困扰,因为更改需要重置所有现有密码。因此,使用可变大小的字段不会为您带来任何好处。
关于执行散列的“最佳”方式,我尝试提供有关该主题的其他SO问题的许多答案:
我使用用户名的影子哈希,Web配置中的guid和密码(存储为varchar(40))。如果他们想暴力破解/词典,他们也需要破解Web服务器以获得GUID。如果用户名确实找到了密码,则无法在整个数据库中创建彩虹表。如果用户想更改其用户名,我只是在同一时间重设密码。
System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(
username.ToLower().Trim(),
ConfigurationManager.AppSettings("salt"),
password
);
通常,仅对密码进行简单的散列,甚至(盐+密码)都不够。
看到:
和
http://gom-jabbar.org/articles/2008/12/03/why-you-should-use-bcrypt-to-store-your-passwords
两者都推荐使用bcrypt算法。可以在线找到大多数流行语言的免费实现。
您可以在数据库中使用多个哈希,这只需要一点点额外的努力。这是非常值得的,但是如果您认为将来极少有机会需要支持其他格式。我会经常使用密码输入
{hashId} $ {salt} $ {已隐藏密码}
其中“ hashId”只是我内部用来识别的一些数字,例如,我使用具有特定哈希模式的SHA1;“ salt”是base64编码的随机盐;“哈希密码”是base64编码的哈希。如果您需要迁移哈希,则可以拦截使用旧密码格式的人员,并在他们下次登录时使他们更改密码。
正如其他人提到的那样,您要谨慎对待哈希,因为它很容易做一些并不真正安全的事情,例如,H(salt,password)比H(password,salt)弱得多,但是同时您想要平衡为此付出的努力与网站内容的价值。我经常会使用H(H(password,salt),password)。
最后,与能够使用期望文本数据的各种工具的好处相比,使用base64编码的密码的成本是适中的。是的,它们应该更加灵活,但是您准备好告诉老板他不能使用他喜欢的第三方工具,因为您想为每条记录节省一些字节吗?:-)
编辑后添加了另一条评论:如果我有意建议使用一种算法,该算法甚至烧掉每个密码的1/10秒散列值,我很幸运被老板办公室笑了。(不是很幸运吗?在我的下一次年度审查中,他会记下一些要讨论的内容。)如果您有数十个甚至数百个用户,那么花费时间并不是问题。如果您要推动10万个用户,通常会有多个人同时登录。您需要快速而强大的东西,而不是缓慢而强大的东西。“但是信用卡信息呢?” 充其量是不屑一顾的,因为存储的信用卡信息不应位于常规数据库附近,并且无论如何都将由应用程序而非个人用户进行加密。
如果使用ASP.Net,则可以使用内置的成员资格API。
它支持多种类型的存储选项,包括:一种方式是哈希,两种方式是加密,md5 + salt。http://www.asp.net/learn/security了解更多信息。
如果您不需要任何花哨的东西,那么这对网站来说很好。
如果您没有使用ASP.Net,那么这里是4guys和codeproject的几篇文章的很好的链接。
http://aspnet.4guysfromrolla.com/articles/081705-1.aspx http://aspnet.4guysfromrolla.com/articles/103002-1.aspx http://www.codeproject.com/KB/security/SimpleEncryption。 aspx
由于您的问题是关于存储方法和大小的,所以我会解决。
存储类型可以是二进制或文本表示形式(最常见的是base64)。Binary较小,但我发现使用文本更容易。如果要按用户加盐(每个密码加盐),则将salt + hash存储为单个组合字符串会更容易。
大小取决于哈希算法。MD5的输出始终为16个字节,SHA1始终为20个字节。SHA-256和SHA-512分别为32和64个字节。如果您使用文本编码,则根据编码方法,您将需要更多的存储空间。我倾向于使用Base64,因为存储相对便宜。Base64将需要大约33%的更大字段。
如果您为每个用户添加了盐,则还需要用于哈希的空间。将所有内容组合在一起以64位盐+ SHA1哈希(160位)base64编码需要40个字符,因此我将其存储为char(40)。
最后,如果您想正确执行操作,则不应该使用单个哈希,而应使用诸如RBKDF2之类的密钥派生函数。SHA1和MD5哈希非常快。即使是单线程应用程序,也可以每秒散列大约30K到50K密码,而在四核计算机上,则高达每秒200K密码。GPU每秒可以散列100倍至1000倍的密码,而像暴力破解这样的速度成为一种可以接受的入侵方法。RBKDF2允许您指定迭代次数,以微调散列的“速度”。关键是使系统瘫痪,但要选择许多迭代,以便限制哈希吞吐量的上限(例如每秒500个哈希)。一种未来的证明方法是在密码字段中包含迭代次数(迭代次数+盐+哈希值)。这将允许将来增加迭代次数,以与功能更强大的处理器保持同步。为了更加灵活,请使用varchar,以允许将来可能使用更大/替代的哈希值。
.Net实现为RFC2892DeriveBytes http://msdn.microsoft.com/zh-cn/library/system.security.cryptography.rfc2898derivebytes.aspx