在数据库中存储密码的首选方法

在数据库中存储密码的首选方法/数据types是什么(最好是SQL Server 2005)。 在我们的几个应用程序中,我一直这样做的方式是首先使用.NETencryption库,然后将它们作为二进制(16)存储在数据库中。 这是首选的方法,或者我应该使用不同的数据types或分配更多的空间比16?

我将密码的盐渍哈希等价物存储在数据库中,而不是密码本身,然后将哈希值与生成的哈希值进行比较。

将文字密码数据存储在任何地方都太危险了。 这使得恢复成为不可能,但是当有人忘记或丢失密码时,可以通过一些检查并创build一个新的密码。

首选的方法:不要在您的数据库中存储密码。 只有它的哈希。 加盐调味。

我做了同样的事情,除了存储为string。 我Base64编码encryption的二进制值。 分配的空间量取决于encryptionalgorithm/密码强度。

我想你是对的(因为你使用的是盐 )。

由于哈希函数的结果是一系列0到255之间的字节(或-128到127,取决于您的8位数据types的符号),将其存储为原始二进制字段是最有意义的,因为它是最紧凑的表示,不需要额外的编码和解码步骤。

一些数据库或驱动程序对二进制数据types的支持不是很好,有时开发人员对它们不够熟悉。 在这种情况下,使用像Base-64或Base-85这样的二进制到文本编码,并将结果文本存储在字符域中是可以接受的。

所需字段的大小由您使用的散列函数决定。 MD5总是输出16个字节,SHA-1总是输出20个字节。 一旦你select了一个散列函数,你通常会坚持下去,因为改变需要重置所有现有的密码。 所以,使用可变大小的字段不会给你买东西。


关于执行哈希的“最佳”方法,我试图提供关于该主题的其他SO问题的许多答案:

  • encryption密码
  • encryption密码
  • 在.NET中encryption密码
  • 盐:秘密还是公开?
  • 哈希迭代
  1. 存储腌制密码的散列,如bcrypt(nounce + pwd)。 您可能更喜欢在SHA1或MD5上进行encryption,因为它可以调整为CPU密集型,因此可以使暴力攻击的方式更长。
  2. 几次login错误后,在login表单中添加一个validation码(以避免暴力攻击)
  3. 如果您的应用程序有一个“忘记我的密码”链接,请确保它没有通过电子邮件发送新密码,而是应该发送一个链接到一个(安全)页面,允许用户定义一个新的密码(可能只有在确认一些个人信息,例如用户的出生date)。 另外,如果您的应用程序允许用户定义新密码,请确保您要求用户确认当前密码。
  4. 显然,确保login表单(通常使用HTTPS)和服务器本身

通过这些措施,用户的密码将得到很好的保护,防止:

  1. =>离线字典攻击
  2. =>现场字典攻击
  3. =>拒绝服务攻击
  4. =>各种攻击!

一个简单的密码哈希,甚至(盐+密码)通常是不够的。

看到:

http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/

http://gom-jabbar.org/articles/2008/12/03/why-you-should-use-bcrypt-to-store-your-passwords

两者都推荐使用bcryptalgorithm。 免费的实现可以在网上find最stream行的语言。

我使用用户名的sha哈希,Webconfiguration中的guid,以及以varchar(40)forms存储的密码。 如果他们想要蛮力/字典,他们也需要破解networking服务器的GUID。 用户名如果​​find密码,就会在整个数据库中创build一个彩虹表。 如果用户想更改他们的用户名,我只需要同时重置密码。

System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile( username.ToLower().Trim(), ConfigurationManager.AppSettings("salt"), password ); 

你可以在你的数据库中使用多个哈希,只需要额外的努力。 如果您认为将来有可能需要支持更多的格式,那么这是非常值得的。 我会经常使用密码input

{hashId} $ {salt} $ {哈希密码}

其中“hashId”只是我在内部用来识别的一些数字,例如,我正在使用具有特定散列模式的SHA1; “盐”是一种碱基64编码的随机盐; 和“哈希密码”是一个base64编码的散列。 如果您需要迁移哈希值,则可以使用旧的密码格式拦截人员,并在下次login时更改密码。

正如其他人提到的,你要小心你的哈希,因为很容易做一些不太安全的事情,比如H(salt,password)比H(password,salt)弱得多,但是同时你想将投入的努力与网站内容的价值进行平衡。 我会经常使用H(H(密码,盐),密码)。

最后,与使用各种期望文本数据的工具的好处相比,使用base64编码密码的代价是适度的。 是的,他们应该更灵活,但是你准备告诉你的老板他不能使用他最喜欢的第三方工具,因为你想保存每个logging几个字节? 🙂

编辑添加一个其他的评论:如果我build议故意使用一种algorithm,即使是十分之一秒钟烧毁每个密码,我只能从我的老板的办公室里笑出来。 (没有那么幸运,他会在我的下一个年度审查中记下一些事情来讨论。)当你有几十个,甚至几百个用户的时候,烧那个时间不是问题。 如果你推动10万用户,你通常会有多个人同时login。 你需要快速而坚强的东西,而不是缓慢而坚强。 “但是信用卡信息怎么样?” 由于存储的信用卡信息不应该在常规数据库附近的任何地方,并且由应用程序encryption,而不是由个人用户encryption,所以最多是不诚实的。

如果您正在使用ASP.Net,则可以使用内置的成员资格API。

它支持多种types的存储选项,包括: 单向散列,双向encryption,md5 +盐。 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

由于你的问题是关于存储方法和大小,我会解决这个问题。

存储types可以是二进制或文本表示(base64是最常见的)。 二进制是较小,但我觉得工作更容易。 如果你正在做每个用户salting(每个密码不同的salt),那么把salt + hash作为一个单独的组合string存储起来会更容易。

大小是散列algorithm相关的。 MD5的输出总是16个字节,SHA1总是20个字节。 SHA-256和SHA-512分别是32和64字节。 如果您正在使用文本编码,则根据编码方法的不同,您将需要更多的存储空间。 我倾向于使用Base64,因为存储相对便宜。 Base64将需要大约33%的领域。

如果你有每个用户腌你还需要空间的哈希。 把它放在一起64位salt + SHA1哈希(160位)base64编码需要40个字符,所以我把它存储为char(40)。

最后,如果你想做正确的事情,你不应该使用一个单一的哈希,而是像RBKDF2这样的密钥派生函数。 SHA1和MD5哈希是非常快速的。 即使是一个单线程的应用程序,也可以在四核机器上每秒散列大约30K到50K的密码,每秒可以达到200K个密码。 graphics处理器可以散列100x到1000x每秒的密码数量。像蛮力攻击成为一种可接受的入侵方法。 RBKDF2允许你指定迭代次数来微调你的哈希是多么“缓慢”。 重点不在于让系统瘫痪,而是要挑选一些迭代,以便限制哈希吞吐量的上限(例如每秒500次哈希)。 未来的certificate方法是在密码字段中包含迭代次数(迭代+盐+散列)。 这将允许在未来增加迭代以跟上更强大的处理器。 为了更灵活地使用varchar来允许未来可能的更大/替代哈希值。

.Net实现是RFC2892DeriveBytes http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx