当我继续建立越来越多的网站和网络应用程序时,我经常被要求存储用户的密码,如果/当用户有问题时,它们可以被检索(要么通过电子邮件发送一个忘记密码的链接,通过电话等),当我可以与这种做法作斗争时,我做了大量的“额外”编程,使密码重置和管理协助成为可能,而不存储他们的实际密码。

当我无法对抗它(或无法获胜)时,我总是以某种方式对密码进行编码,这样至少它不会以明文形式存储在数据库中——尽管我知道如果我的数据库被黑客攻击,罪犯不需要花费太多时间就能破解密码,所以这让我感到不舒服。

在一个完美的世界里,人们会经常更新密码,而不会在许多不同的网站上重复密码——不幸的是,我知道很多人都有相同的工作/家庭/电子邮件/银行密码,甚至在他们需要帮助的时候免费给我。如果我的数据库安全程序因为某种原因失败了,我不想成为他们财务崩溃的罪魁祸首。

从道德和伦理上讲,我觉得我有责任保护一些用户的生活,即使他们对他们的生活不那么尊重。 我确信有许多方法和论点可以用于盐散列和不同的编码选项,但当您必须存储它们时,是否存在单一的“最佳实践”?在几乎所有的情况下,我使用PHP和MySQL,如果这使任何不同的方式,我应该处理的细节。

Bounty的其他信息

我想澄清的是,我知道这不是你想要做的事情,在大多数情况下,拒绝这样做是最好的。然而,我并不是在寻求关于采用这种方法的优点的说教,我是在寻找如果你确实采用这种方法,应该采取的最佳步骤。

在下面的注释中,我指出了主要面向老年人、智障人士或非常年轻的人的网站,当他们被要求执行安全密码恢复程序时,他们会感到困惑。尽管在这些情况下,我们可能会发现这很简单,但有些用户需要额外的帮助,要么让服务技术人员帮助他们进入系统,要么通过电子邮件/直接显示给他们。

在这样的系统中,如果用户没有得到这种级别的访问帮助,来自这些人口统计数据的流失率可能会阻碍应用程序,所以请在回答时考虑到这样的设置。

谢谢大家

这是一个有趣的问题,有很多争论,我很喜欢。最后,我选择了一个答案,它既保留了密码安全性(我不必保留纯文本或可恢复的密码),又使我指定的用户群能够登录到一个系统,而不存在我在正常密码恢复中发现的主要缺陷。

像往常一样,由于不同的原因,大约有5个答案我想标记为正确,但我必须选择最好的一个——其余的都是+1。谢谢大家!

同时,感谢Stack社区中为这个问题投票和/或将其标记为最喜欢的人。我把获得100票作为一种赞美,希望这个讨论能帮助到和我有同样担忧的人。


当前回答

根据我对这个问题所作的评论: 有一点几乎被所有人都忽略了。我最初的反应和@Michael Brooks非常相似,直到我意识到,像@stefanw一样,这里的问题是破坏了需求,但事实就是这样。 但后来,我突然想到,事实可能并非如此!这里缺少的一点是应用程序资产的不言而喻的价值。简单地说,对于一个低价值的系统,一个完全安全的身份验证机制,包括所有涉及的过程,将是过度的,是错误的安全选择。 显然,对于银行来说,“最佳实践”是必须的,在道德上不可能违反CWE-257。但是很容易想到低价值的系统是不值得的(但仍然需要一个简单的密码)。

重要的是要记住,真正的安全专业知识是找到适当的权衡,而不是教条地宣扬任何人都可以在网上阅读的“最佳实践”。

因此,我建议另一种解决方案: 这取决于系统的价值,并且只有当系统是适当的低价值,没有“昂贵”资产(包括身份本身),并且存在有效的业务需求,使得适当的处理不可能(或足够困难/昂贵),并且客户知道所有的警告…… 那么,简单地允许可逆加密是合适的,没有特殊的障碍。 我只是说根本不需要加密,因为它实现起来非常简单/便宜(甚至考虑到可通过的密钥管理),并且它确实提供了一些保护(超过实现它的成本)。此外,值得考虑的是如何向用户提供原始密码,无论是通过电子邮件,还是显示在屏幕上,等等。 由于这里的假设是被盗密码的值(甚至是总值)非常低,因此这些解决方案中的任何一种都可能有效。


因为有一个活跃的讨论正在进行,实际上是几个活跃的讨论,在不同的帖子和单独的评论线程中,我将补充一些澄清,并回应在这里其他地方提出的一些非常好的观点。

首先,我认为这里的每个人都很清楚,允许用户的原始密码被检索,是不好的做法,通常不是一个好主意。这一点毫无争议。 此外,我要强调的是,在许多情况下,不,大多数情况下,这是错误的,甚至是肮脏的,肮脏的,丑陋的。

然而,问题的关键在于原则,是否存在任何情况下可能没有必要禁止这种行为,如果有,如何以最适合这种情况的正确方式禁止这种行为。

现在,正如@Thomas, @sfussenegger和其他几个人提到的,回答这个问题的唯一正确方法是对任何给定的(或假设的)情况进行彻底的风险分析,以了解什么是利害攸关的,值得保护的程度,以及有哪些其他缓解措施可以提供保护。 不,这不是一个流行语,这是一个基本的,最重要的工具,一个真实的安全专业人士。最佳实践在一定程度上是好的(通常是为没有经验的人和黑客提供的指导),在这之后,经过深思熟虑的风险分析就会起作用。

你知道,这很有趣——我一直认为自己是一个安全狂热者,但不知怎的,我却站在那些所谓的“安全专家”的对立面……好吧,事实是——因为我是一个狂热分子,也是一个现实生活中的安全专家——我不相信在没有非常重要的风险分析的情况下宣扬“最佳实践”教条(或CWEs)。 “当心那些安全狂热者,他们很快就会使出浑身解数,而不知道他们要防御的实际问题是什么。更多的安全并不一定等于更好的安全。” 风险分析和真正的安全狂热者会指出一个更聪明的、基于价值/风险的权衡,基于风险、潜在损失、可能的威胁、互补的缓解措施等。任何“安全专家”不能指出健全的风险分析作为他们的建议的基础,或支持逻辑权衡,而是宁愿在不了解如何执行风险分析的情况下抛出教条和CWEs,只是安全黑客,他们的专业知识不值他们打印的厕纸。

事实上,这就是我们如何得到荒谬的机场安检。

但在我们讨论这种情况下的适当权衡之前,让我们看看明显的风险(明显的,因为我们没有这种情况的所有背景信息,我们都在假设——因为问题是假设的情况会有什么……) 让我们假设一个LOW-VALUE系统,但它不是那么微不足道,以至于它是公共访问-系统所有者想要防止随意的模仿,然而“高”安全性并不像易用性那么重要。(是的,这是一个合理的权衡,接受任何精通脚本的孩子都可以入侵网站的风险……等等,APT现在不是很流行吗?) 举个例子,假设我正在为一个大型家庭聚会安排一个简单的地点,让每个人都能头脑风暴一下今年我们想去哪里露营。我不太担心某个匿名黑客,甚至不太担心弗雷德表哥再三建议我回到旺塔纳马纳比奇利奇湖,因为我担心厄尔玛姨妈在需要登录时无法登录。厄玛姨妈是一位核物理学家,她不太擅长记密码,甚至根本不会使用电脑……所以我想为她消除所有的摩擦。再说一次,我不担心黑客,我只是不想犯错误登录的愚蠢错误-我想知道谁来了,他们想要什么。

无论如何。 那么,如果我们对称加密密码,而不是使用单向哈希,我们的主要风险是什么?

冒充用户?不,我已经接受了这个风险,没什么意思。 邪恶的管理员吗?好吧,也许……但同样,我不关心是否有人可以模仿另一个用户,内部或没有…不管怎样,一个恶意的管理员无论如何都会得到你的密码——如果你的管理员坏了,它的游戏就结束了。 另一个被提出的问题是,标识实际上是在几个系统之间共享的。啊!这是一个非常有趣的风险,需要仔细观察。 让我先声明一下,这并不是共享的实际身份,而是证明或认证凭证。好吧,因为共享密码将有效地允许我进入另一个系统(例如,我的银行帐户或gmail),这实际上是相同的身份,所以这只是语义…但事实并非如此。在这种情况下,标识由每个系统单独管理(尽管可能存在第三方标识系统,例如OAuth—但它仍然与该系统中的标识分离—稍后将对此进行详细介绍)。 因此,这里的核心风险点是,用户将自愿将他的(相同的)密码输入到几个不同的系统-现在,我(管理员)或我的网站的任何其他黑客将有权限访问Erma阿姨的核导弹网站的密码。

嗯。

你觉得这里有什么不对劲吗?

它应该。

让我们从保护核导弹系统不是我的责任开始,我只是在为我的家人建造一个该死的家庭郊游地点。那么是谁的责任呢?嗯……那么核导弹系统呢?咄。 其次,如果我想窃取某人的密码(一个在安全网站和不太安全的网站之间反复使用相同密码的人)——我为什么要费心入侵你的网站呢?或者与对称加密作斗争?我可以建一个自己的简单网站,让用户注册来接收他们想要的任何重要新闻…噗噗,我“偷”了他们的密码。

是的,用户教育总是回来咬我们的屁股,不是吗? 对此你无能为力…即使你要在你的网站上散列他们的密码,并做TSA能想到的所有事情,如果他们继续乱把密码贴在他们碰到的每个网站上,你也不会一分不清楚地为他们的密码添加保护。不要费心去尝试。

换句话说,你不拥有他们的密码,所以不要试图表现得好像你拥有一样。

所以,我亲爱的安全专家们,就像一位老妇人曾经问Wendy's的那样,“风险在哪里?”

针对以上提出的一些问题,再提出几点意见:

CWE不是法律、法规,甚至不是标准。它是一个共同弱点的集合,即“最佳实践”的反面。 共享身份的问题是一个实际的问题,但这里的反对者误解了(或歪曲了)。这是一个共享身份本身的问题(!),而不是在低价值系统上破解密码。如果您在低值系统和高值系统之间共享密码,那么问题已经存在了! 顺便说一下,前面的观点实际上是反对在这些低价值系统和高价值银行系统中使用OAuth之类的东西。 我知道这只是一个例子,但(可悲的是)FBI的系统并不是最安全的。不太像你家猫的博客服务器,但也没有超过一些更安全的银行。 加密密钥的分离知识或双重控制不仅仅发生在军事领域,事实上PCI-DSS现在要求基本上所有商家都这样做,所以它真的不再那么遥远了(如果价值证明它是合理的)。 对于那些抱怨这样的问题使开发人员职业看起来如此糟糕的人来说:正是这样的答案使安全职业看起来更加糟糕。同样,以业务为中心的风险分析是必需的,否则您将使自己毫无用处。除了犯错之外。 我想这就是为什么仅仅让一个普通的开发人员承担更多的安全责任并不是一个好主意,而没有训练他以不同的方式思考,并寻找正确的权衡。无意冒犯,对在座的各位,我完全赞成——但更多的训练是必要的。

唷。好长的帖子…… 但是回答你最初的问题,@Shane:

向客户解释正确的做事方式。 如果他还坚持,那就多解释,坚持,争辩。如果需要,可以发脾气。 向他解释商业风险。细节很好,图表更好,现场演示通常是最好的。 如果他仍然坚持,并且提出了有效的商业理由——是时候让你做一个判断了: 这个网站是低价值还是没有价值?这真的是一个有效的商业案例吗?对你来说够好了吗?您是否没有其他可以考虑的风险,这些风险会超过有效的商业原因?(当然,客户端不是恶意网站,但这是废话)。 如果是的话,请继续。花费精力、摩擦和损失使用(在这种假设的情况下)来设置必要的流程是不值得的。任何其他决定(同样,在这种情况下)都是糟糕的权衡。

所以,底线和一个实际的答案——用简单的对称算法加密它,用强acl保护加密密钥,最好是DPAPI或类似的东西,记录它并让客户端(足够高级的人做出决定)签字。

其他回答

将用户安全问题的答案作为加密密钥的一部分,并且不要将安全问题答案存储为纯文本(而是散列)

不要放弃。你可以用来说服你的客户的武器是不可否认性。如果你可以通过任何机制重建用户密码,你就给了他们的客户一个合法的不可抵赖机制,他们可以拒绝任何依赖于该密码的交易,因为供应商无法证明他们没有重建密码并自己完成交易。如果密码被正确地存储为摘要而不是密文,这是不可能的,因此最终客户要么自己执行交易,要么违反了他对密码的注意义务。无论哪种情况,责任完全落在他身上。我处理过的案件中,金额高达数亿美元。不是你想出错的事。

我也有同样的问题。同样的,我总是认为有人入侵我的系统不是“如果”的问题,而是“什么时候”的问题。

所以,当我必须做一个网站,需要存储一个可恢复的机密信息,如信用卡或密码,我所做的是:

使用openssl_encrypt(字符串$data,字符串$method,字符串$password)进行加密 PHP手册。 数据参数: 敏感资料(例如用户密码) 如果需要,序列化,例如,如果信息是一个数据数组,如多个敏感信息 密码arg:使用一个只有用户知道的信息,比如: 用户牌照 社会保险号码 用户电话 用户母名 在注册时通过电子邮件和/或短信发送的随机字符串 方法参数: 选择一种密码方法,如“aes-256-cbc” 永远不要将password参数中使用的信息存储在数据库(或系统中的任何地方)

当需要检索此数据时,只需使用“openssl_decrypt()”函数并向用户询问答案。例如:“要收到你的密码,请回答这个问题:你的手机号码是多少?”

PS 1:永远不要将存储在数据库中的数据用作密码。如果您需要存储用户的手机号码,那么永远不要使用此信息来编码数据。总是使用只有用户知道的信息,或者非亲属很难知道的信息。

PS 2:信用卡信息,比如“一键购买”,我所做的就是使用登录密码。这个密码在数据库中哈希(sha1, md5等),但在登录时,我将明文密码存储在会话或非持久性(即在内存中)安全cookie中。这个简单的密码永远不会留在数据库中,实际上它总是留在内存中,在节结束时销毁。当用户点击“一键购买”按钮时,系统使用此密码。如果用户使用facebook, twitter等服务登录,那么我会在购买时再次提示密码(好吧,这不是完全的“点击”),然后使用用户曾经登录的服务的一些数据(如facebook id)。

用户是否真的需要恢复(例如被告知)他们忘记的密码是什么,或者他们只是需要能够进入系统?如果他们真正想要的是登录密码,为什么不设置一个程序,简单地将旧密码(不管是什么)更改为支持人员可以提供给丢失密码的人的新密码?

我曾经使用过这样的系统。支持人员无法知道当前密码是什么,但可以将其重置为新值。当然,所有这些重置都应该记录在某个地方,最好的做法是生成一封电子邮件给用户,告诉他密码已被重置。

另一种可能是使用两个同时的密码来访问一个帐户。一个是用户管理的“正常”密码,另一个就像一个骨架/主密钥,只有支持人员知道,对所有用户都是一样的。这样,当用户有问题时,技术支持人员可以用万能钥匙登录到帐户,并帮助用户更改密码。不用说,所有使用主密钥的登录都应该由系统记录。作为一种额外的措施,无论何时使用主密钥,您都可以验证支持人员凭据。

- edit -回应关于没有主密钥的评论:我同意这是不好的,就像我认为允许用户以外的任何人访问用户的帐户是不好的一样。如果你看一下这个问题,整个前提是客户要求一个高度妥协的安全环境。

万能钥匙不需要像乍看之下那么糟糕。我曾在一家国防工厂工作,他们认为主机操作员在某些场合需要有“特殊访问权限”。他们只是把特殊的密码放在一个密封的信封里,并把它贴在操作员的桌子上。要使用密码(接线员不知道),他必须打开信封。每次换班时,值班员的一项工作就是查看信封是否被打开,如果打开了,立即(由其他部门)更改密码,新密码放入新信封,然后重新开始这个过程。操作员将被问及他为什么打开它,这一事件将被记录在案。

虽然这不是我设计的程序,但它确实有效,并提供了良好的问责制。每件事都被记录和审查过,加上所有的操作员都有国防部的秘密许可我们从未有过任何滥用。

由于审查和监督,所有操作员都知道,如果他们滥用打开信封的特权,他们将立即被解雇,并可能受到刑事起诉。

所以我想真正的答案是,如果一个人想把事情做好,就雇佣他们可以信任的人,进行背景调查,并行使适当的管理监督和问责制。

但话说回来,如果这个可怜的家伙的客户有良好的管理,他们就不会在第一时间要求这样一个安全折衷的解决方案,不是吗?

保护凭证不是一个二进制操作:安全/不安全。安全是关于风险评估的,是在连续统上衡量的。安全狂热分子讨厌这样想,但丑陋的事实是,没有什么是完全安全的。具有严格的密码要求、DNA样本和视网膜扫描的散列密码更安全,但以开发和用户体验为代价。明文密码的安全性要低得多,但实现起来成本更低(但应该避免使用)。在一天结束的时候,它归结为一个漏洞的成本/收益分析。您可以根据所保护的数据的值及其时间值来实现安全性。

一个人的密码泄露到野外的代价是什么?给定系统中模拟的成本是多少?对于联邦调查局的电脑来说,代价可能是巨大的。对于Bob的一次性5页网站来说,成本可以忽略不计。专业人员为客户提供选项,并在涉及到安全性时列出任何实现的优势和风险。如果客户要求的某些东西可能会使他们处于风险之中,因为他们未能遵守行业标准,那么情况就会加倍。如果客户明确要求双向加密,我将确保您记录您的反对意见,但这不应该阻止您以您所知道的最佳方式实现。说到底,这是客户的钱。是的,你应该推动使用单向哈希,但说这绝对是唯一的选择,其他任何东西都是不道德的,这完全是无稽之谈。

如果您使用双向加密存储密码,安全性就归结于密钥管理。Windows提供了一些机制来限制对管理帐户和密码的证书、私钥的访问。如果你在其他平台上托管,你需要看看你在那些平台上有什么可用的选项。正如其他人建议的那样,您可以使用非对称加密。

据我所知,没有法律(包括英国的数据保护法案)明确规定密码必须使用单向哈希存储。这些法律中唯一的要求就是采取合理的措施保证安全。如果对数据库的访问受到限制,那么在这种限制下,即使是明文密码也可以合法地使用。

然而,这确实揭示了另一个方面:法律优先权。如果法律优先级建议您必须根据构建系统的行业使用单向散列,那么情况就完全不同了。这是你用来说服你的客户的弹药。除此之外,最好的建议是提供合理的风险评估,记录您的反对意见,并以您可以满足客户要求的最安全的方式实施系统。