实施密码恢复最佳实践

63

我希望在我的网站应用程序中实现密码恢复功能。

我不想使用密保问题。

虽然可以通过电子邮件发送密码,但我认为这样做存在风险。

也许我可以生成一个新的临时随机密码,并通过电子邮件发送它,但我认为这和上述方法一样有风险。

我是否可以通过电子邮件发送一个URL,例如http://example.com/token=xxxx, 其中xxxx是与用户关联的随机令牌。因此,当用户导航到该URL时,他/她可以重置密码。


1
可能是https://dev59.com/dHNA5IYBdhLWcg3wkuzO的重复问题,在现代Web应用程序中有效的密码检索技术。 - this. __curious_geek
1
当用户使用正确的令牌到达密码重置页面时,请继续使用该令牌(或另一个临时令牌)在表单提交时更新正确的记录以设置新密码。如果您使用类似于记录ID的东西(在找到正确的记录后),人们可以使用它来重置彼此的密码,而不是使用令牌...这只是我自己编写时发现的一些问题 :-) - MSpreij
请检查IT安全(StackExchange)上类似的问题:http://security.stackexchange.com/questions/1918/can-anyone-provide-references-for-implementing-web-application-self-password-res - Hardik Sondagar
12个回答

86

当我在空军服役时,我们的安全规则是:设置或重置密码时,请勿在同一封电子邮件中发送用户名和密码。这样,如果有人拦截电子邮件搜寻密码,他必须成功地拦截两封电子邮件,并能够将它们连接起来才能突破安全。

我看到很多网站使用“转到此URL以重置密码”的方式。也许我错过了什么——我不是安全专家——但我不认为这比发明新的临时密码并发送更安全。如果黑客拦截了电子邮件,为什么他不能单击该链接并像合法用户一样查看新密码?在我看来,这只会给用户带来额外的麻烦,而没有任何安全收益。

顺便说一句,恭喜你没有使用安全问题。我不理解这个设备的逻辑。自计算机安全诞生以来,我们一直告诉人们,“不要使用关于自己信息的密码,黑客可以发现或猜测,例如你的高中名称或你最喜欢的颜色。黑客可能能够查找你的高中名称,即使他们不认识你或对你一无所知,如果你住在你上学的附近,他们也可以通过尝试附近的学校来猜到。只有少数几种可能的喜欢的颜色,所以黑客可以猜到。等等。相反,密码应该是毫无意义的字母、数字和标点符号的组合。”但现在我们还告诉他们,“但是!如果你很难记住那个无意义的字母、数字和标点符号的组合,没问题!取一些你容易记住的关于自己的信息——比如你的高中名称或你最喜欢的颜色——你可以将其用作“安全问题”的答案,即替代密码。”

的确,安全问题比仅仅选择了一个糟糕的密码更容易让黑客攻击。如果您只是使用个人信息作为密码,黑客可能不知道您使用了哪个个人信息。您是否使用了您的宠物名字?您的出生日期?您最喜欢的冰淇淋口味?他们必须尝试所有这些信息。但是安全问题会告诉黑客您使用了哪个个人信息作为密码!

与其使用安全问题,为什么不直接告诉用户:“如果您忘记了密码,请在屏幕底部找到它,如果您试图入侵他人的帐户,绝对禁止向下滚动。” 它只会稍微不那么安全一点。

如果网站要求我提供我出生城市或第一辆汽车的制造商,我不会给出实际答案。我会提供一个毫无意义的密码。

</抱怨>


41
最有趣的关于安全问题为何不好的抱怨,点赞加一。 - Peter
7
我总是选择模糊的答案来回答那些可怕的“安全”问题。我曾经和我的无线服务提供商在电话中恢复密码时发生了尴尬的时刻。他们问我其中一个我设置的安全问题:“你最喜欢的食物是什么?”,我回答:“我自己”... “嗯,好的Murch先生非常感谢。” - Wesley Murch
2
@Wesley:情况本来可以更糟。你本可以说“Help Desk人员”。不过这也不是个坏主意。一个荒谬的答案容易记住,但别人猜到的可能性较小。只要你不选择一个显而易见的荒谬答案就行了。比如,问:“你在哪里上学?”回答:“Hard Knocks”。 - Jay
5
如果您发送一个新的密码给用户用于访问网站,该密码可能会在中途被拦截。如果用户在事件发生后仍未更改其密码,则原密码仍然有效。使用服务器端生成的令牌可以使您作为网站所有者更好地控制他们何时能够使用该入口点,即通过设置过期时间来实现。 - Aejay
20
请访问此网址以重置您的密码。在那里,请提供您的用户名(电子邮件中没有包含),令牌将在一小时内过期。这比临时密码更安全,因为如果您没有发出请求,它不会锁定您的帐户。黑客必须知道您的用户名和电子邮件地址,并在令牌有效期内访问后者。当然,这假设该网站没有使用您的电子邮件地址作为用户名... - Duncan
显示剩余12条评论

51

首先,不要存储用户密码的明文副本,甚至是加密版本。你只需要保留用户密码的哈希(hashed)副本。

关于找回密码的解决方案,根据我的经验,发送包含更改用户密码链接的恢复邮件是最好的解决方案。这可能对用户来说更加方便,从安全角度来看,与发送新的随机密码以在下次登录时更改密码基本相同。我仍然建议恢复链接在合理的短时间内过期,并且仅能使用一次。


1
我即将尝试第一次实现这个。正如你所说,我只保留散列密码,请您详细说明一下恢复链接的方法。我看到过类似这样的实现:http://site.com/reset-pass?e='+user.email+'&p='+user.pass,其中密码字段是哈希值,这是否安全?如果有人获取了您数据库中的哈希值,这是否意味着他们可以重置每个人的密码?您如何实现链接的过期? - Cory Gross
5
有几种方法可以解决这个问题,但是你绝对不希望链接以任何方式暴露电子邮件或密码/哈希。一个相当简单的选项是在你的数据库中添加一个额外的表,其中包含用户ID列(唯一)、请求数据列和随机生成的值(128位应该是安全值)。随机生成的值将嵌入到电子邮件中的链接中。重置密码页面将确保它收到的数字存在于数据库中并且日期在X天内。此时,您可以要求用户设置新密码。定期清理。 - Kitsune
“短时间”指的是多长时间?几个小时?几天?一周? - Joe
1
@Joe 分钟/小时可能不太实际(因为电子邮件提供商偶尔会非常缓慢地发送邮件,而且用户的情况也可能如此)。在一天和一周之间,可能存在一个“甜点”。如果您可以访问数据,您可以绘制出用户实际使用恢复链接所需的时间,并根据该数据进行调整,以尽量减少对用户的干扰,同时保护他们的安全性(您可能更倾向于某一方面)。遗憾的是,我没有听说过任何这样的研究,尽管它可能会产生有意义的结果。 - Kitsune
我在想我们(开发人员)是否应该为用户提供存储公钥的选项,以便他们可以接收加密电子邮件。这将降低恢复链接被嗅探的风险。(我猜只有0.01%的用户会使用它,但我只是在思考如何增加安全性) - nuala
显示剩余2条评论

20

很难说你应该做什么,因为几乎任何解决这个问题的方法都会削弱安全性。除非你想调查发送短信、回调验证、一次性密码生成器或其他将密码恢复到不同媒介的方案。

然而,你不应该做以下几件事情:

  • 发送密码-毕竟,正如已经提到的那样,你没有它。

  • 生成新的临时密码-这不仅与发送密码一样不安全,还会导致拒绝服务攻击的可能性。我可以进入网站,假装是你,请求一个新的密码,然后(如果你没有检查电子邮件)你无法登录,不知道原因,必须请求一个新的新密码......

令牌可能是最好的选择。收到通知表示忘记了密码请求,但在你确认之前不执行任何操作。你还可以将其设置为有相对较短的过期时间的一次性令牌,以限制风险。

当然,很多取决于应用程序。显然,保护财务和其他敏感信息比防止在mytwitteringfacetube.com上被黑客攻击更为重要,因为虽然这很麻烦,但如果有人想在社交网络网站上窃取某人的身份,他们可以直接开设自己的帐户并冒充窃取的信息。


10

显然,你不能通过电子邮件发送原始密码,因为你并未存储它(是吧?!)。从安全角度来看,发送临时密码(必须更改,因为它仅适用于一次登录)和重置密码链接是等效的。


我正在使用AES加密存储密码,以便我可以解密并发送它。 - Enrique
12
没有真正好的理由将密码以可逆格式存储,使用对称算法会增加一种错误的安全感,而几乎不会增加任何额外的安全性。应该使用适当的哈希算法,例如SHA系列、Whirlpool或其他现代算法,并加入盐来保证密码的远高于之前的安全性。 - Kitsune
11
使用加密方式存储密码确实有帮助,但仅此还不够——如果攻击者可以访问您的数据库,那么他很可能也能访问系统的其余部分(虽然 SQL 注入攻击不是这样,但对于许多其他类型的攻击却是如此)。而且,如果您的系统可以解密密码,那么他也可以。 - BlueRaja - Danny Pflughoeft
3
狐狸是正确的。如果你的数据库受到攻击,很可能你的AES密钥也会被盗取。你应该始终为密码使用单向加密哈希算法。 - Matthew Flaschen
4
即使外部攻击的可能性非常小,但内部恶意的可能性总是存在的。你的其中一个同事可能会解密密码,甚至出售它们。这就是为什么你应该只使用哈希值的原因。 - fish
显示剩余2条评论

5
我同意Andy的观点。安全问题通常与密码无关,它们有一个问题和答案,并且不涉及密码。这似乎是用来防止虚假的密码重置请求,并且确实有用处。
想象一下 - 有人可以去一个网站的“忘记密码”工具中输入大量的电子邮件地址 - 或只是想要惹恼的一个人。如果此时重置密码,则属于这些电子邮件地址的人将不得不在他们的电子邮件中注意到密码重置,并使用重置后的密码登录到下次访问该网站时。使用安全问题,对于某人来说并不容易做到这一点。
我看到亚马逊会向给定的电子邮件发送链接。他们还要求您输入验证码以防止DOS攻击。因为它是一个链接,所以我想这意味着他们没有立即重置密码,而是在用户单击链接后才会重置密码。在上述情况下,用户将只看到电子邮件并注意到“不,我没有那样做”,然后继续他们的业务,而无需不必要地更改密码。安全问题可能已经在开始时阻止了尝试,从而使合法用户首先不会收到电子邮件。
这里有一份白皮书: http://appsecnotes.blogspot.com/2010/09/latest-forgot-password-best-practices.html 这份白皮书实际上建议将秘密问题作为身份验证过程的重要组成部分。通过电子邮件发送认证代码并请求它只是您可以选择包括的附加层。

1
安全问题是密码的一种较弱形式。它们也是不必要的,因为“忘记密码”实用程序不应该重置密码,所以所有那些亿万电子邮件地址都将收到一个可以忽略(或报告)但不会影响任何人的密码重置链接。是的,这可能会减少发送虚假电子邮件的数量,但它也通过提供额外的跳过步骤来使合法用户感到恼火。并非所有网站都使用电子邮件地址(理所当然),因此猜测用户名可能比猜测第一个宠物的名称更困难。 - Duncan

5
我不理解对于密保问题的态度。这并不意味着我会将我的密码设置为“BlueHouse”,然后将我的安全问题设置为“你最喜欢的两件事是什么?”,答案是“蓝色和房子”。安全问题并不是获取实际密码的魔法钥匙。通常它只是重置密码并发送到文件中的电子邮件地址的一种方式。我不知道你们如何操作,但听起来好像你们会做以下两种情况之一。
1)用户点击“忘记密码”按钮,新密码被发送给用户。
2)用户点击“忘记密码”按钮,然后在获取新密码之前需要回答一个安全问题。
看起来第二种选项更加安全。
为什么发送令牌比发送密码更加安全?如果电子邮件帐户已经被黑客攻击,那么无论是重置密码链接、令牌还是新密码都无济于事。不要忘记,大多数网站都不会说“我们已向以下电子邮件地址发送了新密码供您入侵”。黑客需要猜测需要被入侵的电子邮件地址。

2
在我看来,选项2更安全...是的,但只是微不足道的安全性提升,而且会让用户感到烦恼并忘记答案。 - Mark
秘密问题方法的问题在于问题通常是像“母亲的婚前姓氏”或“你在哪里上学”的东西,这些东西通常可以从社交媒体资料中获得;如果用户被允许输入自己的秘密问题,那么它通常会更弱。同意如果电子邮件帐户已被黑客攻击,则所有赌注都无效,尽管请记住,很多网站将秘密问题作为使用密码重置链接的替代方案,即回答正确的秘密问题,您就可以直接进行密码重置。 - Duncan
1
发送令牌与发送新密码相比,如果您发送新密码,无论是直接发送还是在回答安全问题后发送,都需要重置密码,这将锁定用户的帐户,如果他们没有请求新密码(并且没有检查电子邮件)。这是一种DOS攻击,如果黑客无法进入用户的帐户,则用户也无法进入。相反,令牌仅是更改密码的身份验证。如果用户没有请求它,或者如果他们记得自己的旧密码,则可以忽略它,它将过期或应该过期。 - Duncan

4
这实际上取决于您需要多少安全性。在极端的一端,密码重置过程涉及联系并证明您是所声称的人,例如通过id,因为您的邮箱也可能被攻击。实际上,由于人们倾向于在所有地方使用相同的密码,这很可能发生。在另一端,有一个标准方法,只需发送一封带有新随机密码的电子邮件。
“秘密”问题和答案只是另一种用户名和密码形式,其致命缺陷通常非常容易猜测,因此最好不要使用它们。
至于令牌,我认为它对整体安全性没有太大影响。无论您发送允许用户更改密码的令牌还是立即发送随机密码都没有太大区别。
只需确保令牌仅可使用一次,最好仅在有限时间内使用,例如请求后+24小时。
正如先前的答案所指出的那样,永远不要存储明文密码。将它们哈希。最好添加{{link1:salt}}。

令牌和随机密码在安全性上的区别并不大,但它们可能会导致拒绝服务攻击。除非用户明确要求更改密码,否则不要更改其密码。 - Duncan

3
这是我如何解决它的方法:
我在我的“用户”表中添加了“retrieve_token”和“retrieve_expiration”字段。
用户通过提供他们的电子邮件并填写验证码来请求密码重置。为其“retrieve_token”字段生成一个随机哈希值-例如“md5($user_id.time())”,而“retrieve_expiration”将设置为45分钟内过期的日期时间。向用户发送一封电子邮件,其中包含以下链接:
https://example.com/reset-password?retrieve_token=912ec803b2ce49e4a541068d495ab570
当需要验证身份时,SSL应该是强制性的。您还可以添加一个表来记录重置请求,其中存储电子邮件和IP地址。这有助于跟踪可能的暴力攻击,并在必要时阻止攻击者的IP地址。
您可以实现安全问题以请求密码重置,但我认为验证码足以阻止任何人多次重复请求。

2
@Jay. 你需要前往一个URL重置密码,而不是只发送新的临时密码,原因不仅仅是为了安全。如果没有像URL加上一个token这样的东西,一个人就可以重置另一个人的密码。这并不需要访问电子邮件。如果有人对其他人有意见,他们可以一直发起新的密码重置。然后可怜的目标用户不得不一遍又一遍地登录并更改密码。
通过发送token,用户的密码不会在他们使用它并确认它之前更改。可以忽略重置电子邮件的垃圾邮件。使用GUID生成token与生成新密码一样容易(如果不更容易),对于开发人员来说并不需要额外麻烦。
此外,由于GUID是唯一的(生成的密码可能不是),token可以与用户名绑定。如果网址上给出了错误的用户名,则可以取消token(即当其他人启动它并拦截时...假设用户名不同于电子邮件)。

1

@Jay。安全问题的正确使用是用于启动密码重置电子邮件,而不是实际重置密码。如果没有像安全问题这样的机制,那么就可以启动密码重置。尽管看起来不太重要,但重置电子邮件可能会发送到一个可能不再属于原始所有者的电子邮件地址。这并不罕见。例如,当员工离开公司时,通常这些邮件会转发给另一名员工。安全问题为该场景添加了低级别的混淆。它还减少了一个人在错误的帐户上不断启动密码重置引起一些可怜的家伙意外收到垃圾邮件的问题。安全问题确实不是真正安全的,它们只是旨在减少这些情况。任何使用安全问题来实际重置密码的人都是错误的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接