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

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

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

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

Bounty的其他信息

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

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

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

谢谢大家

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

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

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


当前回答

另一个你可能没有考虑到的选择是允许通过电子邮件进行操作。这有点麻烦,但我为一个客户端实现了这个功能,该客户端需要系统“外部”的用户来查看(只读)系统的某些部分。例如:

一旦用户注册,他们就拥有完全的访问权限(就像普通用户一样) 网站)。注册必须包括电子邮件。 如果需要数据或操作,而用户不需要 记住他们的密码,他们仍然可以通过 点击一个特殊的“给我发邮件以获得许可”按钮,就在常规的“提交”按钮旁边。 然后,请求以超链接发送到电子邮件,询问他们是否希望执行该操作。这类似于密码重置电子邮件链接,但它不是重置密码,而是执行一次性操作。 然后用户点击“Yes”,它确认应该显示数据,或者应该执行操作,显示数据等等。

正如你在评论中提到的,如果电子邮件被泄露,这将不起作用,但它确实解决了@joachim关于不想重置密码的评论。最终,他们将不得不使用密码重置,但他们可以在更方便的时候这样做,或者根据需要在管理员或朋友的帮助下这样做。

该解决方案的另一种方法是将操作请求发送给第三方可信管理员。这对于老年人、智障人士、非常年轻或其他困惑的用户来说效果最好。当然,这需要一个可信的管理员来支持这些人的行动。

其他回答

Michael Brooks一直对cwe257直言不讳——事实上,无论您使用什么方法,您(管理员)仍然可以恢复密码。那么下面这些选项怎么样:

使用其他人的公钥(一些外部授权机构)加密密码。这样,您就不能亲自重建密码,用户必须去外部权威机构要求恢复他们的密码。 使用从第二个口令短语生成的密钥加密密码。在客户端进行加密,绝不将其明文传输到服务器。然后,为了恢复,通过从他们的输入重新生成密钥,再次在客户端解密。不可否认,这种方法基本上是使用第二个密码,但您总是可以告诉他们把它写下来,或者使用旧的安全问题方法。

我认为1。是更好的选择,因为它允许您在客户的公司内指定某人持有私钥。确保他们自己生成密钥,并将其与指示一起存储在保险箱等。您甚至可以通过选择只加密密码并向内部第三方提供密码中的某些字符来增加安全性,这样他们就必须破解密码才能猜测它。将这些字符提供给用户,他们可能会记住它是什么!

在回答这个问题时,已经有很多关于用户安全问题的讨论,但我想再提一下好处。到目前为止,我还没有看到在系统中存储可恢复密码的合法好处。考虑一下:

通过电子邮件发送密码对用户有好处吗?不。他们从一次性密码重置链接中获益更多,这有望让他们选择一个他们能记住的密码。 在屏幕上显示密码对用户有好处吗?不,原因和上面一样;他们应该选择一个新密码。 让技术支持人员告诉用户密码对用户有好处吗?没有;同样,如果支持人员认为用户的密码请求已经过正确验证,那么为用户提供新密码和更改密码的机会对用户更有利。此外,电话支持比自动密码重置更昂贵,所以该公司也没有受益。

从可恢复的密码中获益的似乎只有那些怀有恶意的人,或者那些需要第三方密码交换的糟糕api的支持者(请永远不要使用这些api !)也许你可以通过如实向客户陈述公司存储可恢复密码没有获得任何好处,只会承担责任来赢得争论。

从这类请求的字里行间,您会发现客户端可能根本不理解,甚至根本不关心密码是如何管理的。他们真正想要的是一个对用户来说并不难的认证系统。所以,除了告诉他们其实他们并不想要可恢复的密码之外,你还应该为他们提供一些让认证过程不那么痛苦的方法,尤其是如果你不需要像银行这样的高安全级别:

允许用户使用他们的电子邮件地址作为用户名。我见过无数用户忘记自己的用户名,但很少有人忘记自己的电子邮件地址。 提供OpenID,让第三方支付用户遗忘的成本。 放宽密码限制。我敢肯定,当一些网站因为“不能使用特殊字符”或“您的密码太长”或“您的密码必须以字母开头”之类无用的要求而不允许您使用首选密码时,我们都非常恼火。此外,如果易用性比密码强度更重要,您甚至可以通过允许更短的密码或不要求混合字符类来放松不愚蠢的要求。随着限制的放松,用户将更有可能使用他们不会忘记的密码。 不要让密码过期。 允许用户重新使用旧密码。 允许用户选择自己的密码重置问题。

但如果你出于某种原因(请告诉我们原因)真的,真的,真的需要一个可恢复的密码,你可以通过给他们一个非密码认证系统来保护用户,以免他们的其他在线帐户受到潜在的威胁。因为人们已经熟悉用户名/密码系统,这是一个行之有效的解决方案,这将是最后的手段,但肯定有很多创造性的替代密码的方法:

让用户选择一个数字引脚,最好不要是4位,最好只在防止暴力尝试的情况下。 让用户选择一个只有他们自己知道的简短答案的问题,这个问题永远不会改变,他们会一直记住,而且他们不介意其他人发现。 让用户输入一个用户名,然后画一个容易记住的形状,并有足够的排列来防止猜测(看看这张G1如何解锁手机的漂亮照片)。 对于一个儿童网站,你可以根据用户名(有点像身份)自动生成一个模糊的生物,并要求用户给这个生物一个秘密的名字。然后他们会被提示输入该生物的秘密名称来登录。

从我对这个主题的了解来看,我相信如果你正在构建一个有登录/密码的网站,那么你甚至不应该在你的服务器上看到明文密码。在密码离开客户端之前,应该对其进行散列处理,可能还需要加盐。

如果您从未看到明文密码,那么就不会出现检索问题。

此外,我(从网上)收集到(据称)一些算法,如MD5不再被认为是安全的。我自己没有办法判断,但这是值得考虑的。

我认为你真正应该问自己的问题是:“我怎样才能更好地说服别人?”

我以实现多因素身份验证系统为生,所以对我来说,很自然地认为可以重置或重构密码,同时暂时少使用一个因素来验证用户,仅用于重置/重新创建工作流。特别是使用otp(一次性密码)作为一些额外的因素,如果建议的工作流的时间窗口很短,则可以降低很大程度的风险。我们为智能手机(大多数用户已经随身携带了一整天)实现了软件OTP生成器,并取得了巨大的成功。在对商业插头的抱怨出现之前,我想说的是,当密码不是用于验证用户身份的唯一因素时,我们可以降低密码易于检索或重置的固有风险。我承认,在网站场景之间的密码重用情况仍然不太好,因为用户会坚持拥有原始密码,因为他/她也想打开其他网站,但你可以尝试以最安全的方式(htpps和谨慎的html外观)提供重建的密码。