我正在处理一个必须具有身份验证(用户名和密码)的项目。
它还连接到一个数据库,所以我想我可以将用户名和密码存储在那里。然而,将密码作为数据库中表中的文本字段似乎不是一个好主意。
我正在使用C并连接到2008 Express服务器。有人能建议(尽可能多的例子)存储此类数据的最佳方法是什么?
另外,如果能提供一个好的理由,我愿意接受这样一种观点:这个信息不能存储在数据库中。
- 无论您做什么,如果您使用加密,不要像前面提到的海报那样将密钥存储在代码中。这只是一个糟糕的练习。
- "如何正确设置密码?"是一个至关重要的问题。这是一个棘手的问题,错误会带来严重后果(回想一下乐购和LinkedIn的遭遇)。我认为这个问题应该在programmers.stackexchange.com重新打开。
- 最好坚持标准——参见en.wikipedia.org/wiki/pbkdf2,你只需要找到用你的语言实现
- 这个问题在安全论坛得到了广泛的回答:security.stackexchange.com/questions/211/…
正确的做法是,在纯文本字段中存储密码是一个可怕的想法。然而,就位置而言,在大多数情况下(老实说,我想不出任何反例),在数据库中存储密码的表示是正确的做法。通过表示,我的意思是您希望使用salt(对于每个用户来说应该是不同的)和安全的单向算法散列密码,并存储它,从而丢弃原始密码。然后,当您想要验证密码时,可以散列该值(使用相同的散列算法和salt),并将其与数据库中的散列值进行比较。
所以,虽然你认为这是一个好问题,但这实际上是这些问题的一个副本(至少):
- 如何最好地存储用户信息和用户登录名和密码
- 存储数据库密码的最佳实践
- 加盐你的密码:最佳实践?
- 是否可以将密码以纯文本形式存储在PHP变量或PHP常量中?
为了进一步澄清盐渍位,简单地散列一个密码并存储的危险是,如果侵入者获得了你的数据库,他们仍然可以使用所谓的彩虹表能够"解密"密码(至少那些出现在彩虹表中的密码)。为了解决这一问题,开发人员在密码中添加了一个salt,当正确地完成后,彩虹攻击就变得不可行了。请注意,一个常见的误解是简单地向所有密码添加相同的唯一和长字符串;虽然这并不可怕,但最好向每个密码添加唯一的盐。了解更多信息。
- @paolo bergantino:"在数据库中存储密码是正确的做法"-我不同意这种说法。
- 我的意思是将密码存储在数据库中,而不是存储在其他地方。把这句话从上下文中去掉让我看起来像是在支持存储普通密码,如果你读了其余的,我显然不支持。
- @我完全理解你的意思。我没有断章取义。最佳实践不是存储甚至加密的密码,而是存储加密密码的一个盐散列。
- 不仅如此,我还把他引向了一大堆讨论盐分和其他问题的帖子…
- @你确定你的帖子里没有错别字吗?它说:"在大多数情况下,将密码存储在数据库中是正确的做法(我实在想不出任何反例)。"???似乎对你的评论有异议
- 保罗所说的直接矛盾。密码的加盐哈希不是密码。在数据库中存储密码的盐散列不是在数据库中存储密码。答案的正文是完全合适的,但其第一句话极易引起误解。
- @罗伯特:这离一个小语义学游戏越来越近了,但我还是会解决它的……
- owasp.org/index.php/password_storage_kiat_sheet是一个很好的关于散列/跳跃的参考。
背景你从不…真的?需要知道用户的密码。您只想验证传入用户是否知道帐户的密码。
散列它:通过强哈希函数存储经过哈希处理的用户密码(单向加密)。搜索"C加密密码"提供了大量示例。
有关哈希函数产生的内容,请参阅联机sha1 hash creator(但不要将sha1用作哈希函数,请使用更强大的函数,如sha256)。
现在,散列密码意味着您(以及数据库窃贼)不应该能够将散列恢复为原始密码。
如何使用它:但是,您会说,如何使用存储在数据库中的这个混合密码?
当用户登录时,他们会将用户名和密码(原始文本)交给您。您只需使用相同的散列代码散列输入的密码,以获得存储的版本。
因此,比较两个哈希密码(用户名的数据库哈希和键入的哈希密码)。通过比较哈希值,您可以判断"他们键入的内容"是否与原始用户输入的密码"匹配"。
额外学分:
问题:如果我有你的数据库,那我就不能像开膛手约翰那样拿个饼干开始做哈希,直到我找到与你存储的哈希密码匹配的密码吗?(因为用户总是选择简短的字典单词…应该很容易)
答:是的……是的,他们可以。
所以,你应该"盐"你的密码。参见维基百科关于盐的文章
参见"如何用salt散列数据"C示例
- 很好的帖子,除了一件事:MD5和SHA1都坏了。您可能应该使用更强大的算法,比如sha2家族。
- 谢谢保罗——你说得对。由于使用sha2和使用md5&sha1一样简单,请使用更强的哈希算法。
- SHA-1没有坏。但布鲁斯·施耐尔(BruceSchneier):步行,不要跑,去沙二。
- "所以,你应该‘盐’你的密码"…但是salt通常与密码一起存储在数据库中,那么这有什么帮助呢?攻击者只需将salt添加到他正在测试的字典攻击短语中。除了不显示重复的密码之外,这还有什么安全性?
- @乔伊:"你从来没有……真的?需要知道用户的密码"-这是一个非常短视的假设。在许多应用程序中,以可以检索的方式存储密码是真正必要的。例如,一个应用程序需要频繁地使用存储的凭证登录到另一个系统,该凭证由用户提供并更新。
- @Franciscozarabozo这两个系统的设计都不好,因为当我的系统被破坏时,现在你系统上的用户也是。OAuth之类的解决方案,但您需要"其他系统"来支持它。您不应该对用户密码进行可逆加密。
- @Thinkofanumber又一次说"你不应该"…告诉我,您如何存储凭据来访问API,如PayPal或TWILIO的REST API或为您提供用户和密钥(充当密码)的任何其他系统?如果您的系统不仅为您而且为多个客户机与这些API接口,该怎么办?您需要找到一种保护此类数据的方法,这种方法是存在的。双向加密方法是有目的的,它们并不是一个"坏选择"。错误的选择来自于您决定如何实现它。
- PrPaypal使用OAuth2作为Auth机制。如果PayPal允许你把我的Paypal PWD存储在一个第三方应用程序中,那将是一场灾难,因为他们对每个不相关的应用程序的安全性几乎没有控制。OAuth令牌可以绕过这个问题,而不是密码,所以可以以可逆加密的形式存储。我的PayPal PWD也没有提供给第三方系统,因为当我登录PayPal时,我在他们的网站上,而不是第三方。这就是您的系统应该如何与它们进行交互。这场讨论可能需要问一个问题,它是否"永远正常"!
- @Thinkofanumber:您应该看看pop和imap,然后以正确的方式回来验证这些服务。当他们在Gmail中存储这些凭证时(当您需要通过IMAP或POP访问邮件系统时),也会对谷歌进行ping。说真的-这么说只是表明你还没有研究过现实生活中的API。
- @哇,让我们保留这项技术,把我个人历史的猜测留给酒吧吧。我承认网络邮件是我从来没有想到过的一种情况,但是pop和imap可以追溯到80年代,那时安全是另一回事。仅仅因为你能做到这一点并不意味着你应该做到,但是,我曾经把我的流行邮件转发给Gmail,这样我就可以避免这种情况。PayPal会阻止你的系统访问他们,如果你这样做,原因很好。现代API开发人员应该通过提供OAuth和其他机制来确保不需要(或可能)存储密码。
作为一个加密的盐散列,使用安全算法,如sha-512。
- 在我看来,你应该总是使用慢速算法(比如河豚)来存储密码。这是一个更好的答案:security.stackexchange.com/questions/211/…。把它放在这里,因为这个页面在搜索结果中仍然显示得很高。
- 遵循这个密码存储的建议将是非常错误的。
最好的安全做法是根本不存储密码(甚至不加密),而是存储加密密码的盐散列(每个密码有一个唯一的盐散列)。
这样,检索纯文本密码几乎是不可能的。
- 韦恩,通过在计算散列值之前加盐,彩虹表被有效地击败,前提是盐的大小足够。
- @韦恩·哈特曼:不是。如果盐值暴露,则必须为该特定的盐值生成一个新的彩虹表。彩虹表的点是预先计算散列值。没有人会为他的盐准备一张彩虹桌。
我完全建议您阅读彩虹表中的文章:关于安全密码方案(死链接,在Internet存档中复制)以及如何安全存储密码,您需要了解什么。
很多编码人员,包括我自己,认为他们理解安全性和哈希。可悲的是,我们大多数人只是没有。
- 文章给出404。
- @Johan看起来链接已经断了,这很遗憾。这是一个备选的codahale.com/how-to-safety-store-a-password
我可能有点偏离主题,因为你提到了用户名和密码的需求,我对这个问题的理解显然不是最好的,但OpenID值得考虑吗?
如果您使用OpenID,那么如果我正确理解技术,并且用户可以使用他们已经拥有的凭证,那么您就不会最终存储任何凭证,从而避免了创建特定于您的应用程序的新标识的需要。
但是,如果所讨论的应用程序纯粹是供内部使用,则可能不适用。
RPX提供了一种将OpenID支持集成到应用程序中的简单方法。
- 我同意OpenID Rocks的用户会面临挑战,但对于这个应用程序来说,它是一个公司内部数据库,我怀疑他们是否希望任何老年人登录。另外,这个应用程序不需要Web访问才能正常工作,所以我不想要求它。
在您的场景中,您可以查看ASP.NET成员资格,最好将用户密码存储为数据库中的哈希字符串。您可以通过将哈希输入的密码与存储在数据库中的密码进行比较来对用户进行身份验证。
所有内容都是为此目的构建的,请查看ASP.NET成员身份
如果您不需要反向散列,我将md5/sha1密码。当用户登录时,您只需加密给定的密码并将其与散列进行比较。在这种情况下,哈希冲突几乎是不可能的,除非有人获得了对数据库的访问权,并且看到了已经有冲突的哈希。
- 我不会用MD5来散列-它基本上是断的mscs.dal.ca/~selinger/md5集合
- 实际上,它没有那么坏。他们可以为两个不同的文件找到相同的哈希值。他们不能做的是反转MD5并获得一个有效的密码。
- 好吧,那它不会也坏了吗?您只需输入生成相同哈希的另一个密码,就可以进入了。您不需要知道原始密码。解决这个问题的方法是,在散列之前盐化密码。
- @如果您在使用MD5之前在密码中添加了一个salt,那么冲突并不重要,因为您不能使用其他密码。