“忘记密码”代码的最佳实现方式

8

对于我的.net网站,我想要实现忘记密码功能。我使用以下步骤:

  1. 表单包含登录ID和电子邮件ID以及验证码的输入框。
  2. 当用户输入详细信息并提交后,在验证后,新密码会在数据库中生成并替换旧密码。
  3. 新密码将通过电子邮件发送给用户。

请帮助我确定是否正确?

是否有其他安全的机制可以实现同样的功能?

[编辑]谢谢,我收到了您的回复。这确实是一种安全的机制。但是我还有一些疑问:

  1. 当用户在忘记密码页面输入登录ID和电子邮件地址时,应该显示什么消息?
  2. 无论是有效用户还是恶意用户,消息是否相同?
  3. 使用CSRF令牌的优点是什么?有任何帮助/链接吗?
  4. 当用户点击链接时,我应该怎么做;因为我猜测用户应该自动登录到他们的帐户-然后我有两个选择(第一)自动向用户发送新密码(第二)向用户显示新表单,用户将在其中输入旧密码和新密码两次?

请帮忙解答?

4个回答

13

我明白你为什么需要使用CAPTCHA,但我会采取不同的方法。

  1. 当请求重置密码时,请检查在过去的 X 分钟内是否已经对该帐户进行了重置。如果已经请求了,则忽略该重置请求。
  2. 检查请求密码重置的IP地址。 如果该IP在过去的 Y 分钟内已请求密码重置,请忽略该请求。
  3. 如果步骤1和2的检查都通过,请检查该帐户是否存在。 如果不存在,请忽略该请求。
  4. 如果到此为止,生成一个一次性令牌,并在 Z 分钟后过期,以及一个包含此令牌的密码重置URL。将其发送给注册的电子邮件地址。当加载URL时,提示输入新密码并进行重置。

对于那些认为应该告诉用户电子邮件发送到哪里的人,我强烈反对。这是“信息泄露”,即使你将其限制在域名上。例如,假设我在JeffAtwoodEatsBabies.com上注册为blowdart。如果Jeff为我请求重置密码并且您显示注册域名,则他将看到idunno.org。这是我的个人域名,因此Jeff将知道blowdart用户实际上是我。这是一件非常糟糕的事情。我不应该为了保护自己免受你的代码向所有人显示电子邮件域名而必须使用hotmail或gmail等注册。

另外,您不应该显示任何错误消息。无论发生什么情况,用户名实际上没有注册,或者已经进行了太多次请求,或者天空已经坍塌,您都应该告诉用户密码重置程序已经开始。通知用户帐户不存在是更多的信息泄露。

最后一件事,您可以做的是在重置请求页面添加CSRF令牌,以便无法从其他网站驱动它。

跟进

所以回答你的进一步问题。

  1. 显示的提示信息由您决定。"已向此账户注册的电子邮件发送重置密码说明"是一个想法,但实际上取决于您的受众。
  2. 如上所述已得到解决。
  3. 维基百科是一个很好的起点。如何执行取决于您的平台,这是完全不同的问题!对于ASP.NET,您可以查看我的codeplex项目,http://anticsrf.codeplex.com或查看ViewStateUserKey
  4. 当链接被点击时,我会首先验证URL中的令牌是否与用户名匹配,然后允许用户输入新密码,或生成一个新密码并通过电子邮件发送。您不能提示用户输入旧密码,因为整个意义在于用户忘记了它!

1
如果一个真正的用户输入了他们的信息,但不小心拼错了,怎么办?现在你告诉他们他们的流程已经开始了,他们可能没有注意到自己的错误,继续他们的业务,但永远不会收到电子邮件,并想知道为什么你的网站出了问题。 - Jason
你必须在安全性和用户不熟练度之间取得平衡。这只是网站管理员可以做出的选择,但通常我建议我的客户倾向于选择安全性。信息泄露位列OWASP十大风险清单,绝不能轻视。 - blowdart
谢谢,你解决了我的很多问题。是否有任何链接可以展示您所写步骤的演示? - Hemant Kothiyal
那个评论毫无意义 - 所以我猜测。 想象一下,通过电子邮件发送到注册的电子邮件地址的链接,如 http://showmethecodez.com/resetPassword/?token=0000-00&accountid=123456因此,重置密码页面根据账户ID获取账户,并检查令牌是否已发给该账户进行密码重置。它使令牌失效,以防止再次使用,并提示您为该账户设置新密码。您可以/应该对账户ID进行对称加密,或者使用间接对象引用,这只是说明了这个想法。 - blowdart
只是出于好奇,为什么用户请求和IP请求有不同的时间窗口?你认为哪一个应该更大,为什么? - Josh Anderson
显示剩余6条评论

6
有许多方法可以实现这一点。正如您所说,生成新密码并将其发送到注册的电子邮件地址是一种方法。我不建议您走这条路,因为每当有人尝试猜测我的密码时,我的密码就会被重置。
相反,迄今为止最好的方法是仅向注册的电子邮件发送一个链接,该链接将开始密码重置过程。您甚至可以通过显示注册时使用的电子邮件地址的掩码版本来让用户知道要检查哪个电子邮件地址:

已向 ********@hotmail.com 发送了一封电子邮件。请检查您的收件箱以继续。

请务必考虑那些可能会忘记注册的电子邮件地址的人-通常几个安全问题是使该信息可用的好方法。

1
+1 考虑到使用 foo@bar.com 注册的用户。在说“我们已向您使用的电子邮件地址发送了一个链接,以foo@开头”时是否存在任何安全问题?对此策略有何评论? - p.campbell
1
@pcampbell - 我非常喜欢这个想法,因为有时我想知道我注册的电子邮件是什么,但我认为更好的方法是提供域名而不是电子邮件地址(@hotmail.com、@yahoo.com、@gmail.com),因为我认为大多数人很可能拥有相同的电子邮件地址,只是在不同的提供商处。 - Omar
我喜欢看到我的电子邮件地址被掩盖的版本。我已经更新了我的帖子以反映这一点。 - Sampson
Hemant,不行。我会将电子邮件发送到与该特定用户名相关联的任何电子邮件地址。 - Sampson
显示域名会带来隐私问题,因为在某些情况下,仅凭域名就可以识别用户。 - RickNZ
显示剩余4条评论

4

我最近完成了这一项任务。当用户输入他们的用户名或电子邮件地址时,我们会生成一个唯一的令牌并将其作为链接的一部分发送给他们。在收到该电子邮件后,他们点击链接,然后自动登录,被带到我的账户页面,并提示重置密码。

当然,这完全依赖于电子邮件客户端的安全性,但从可用性的角度来看,很难有更好的方法。


这是一个很好的解决方案,只需记得仅存储密码的哈希值而不是明文密码。您应该删除验证码,因为它并不真正必要,因为您必须检查电子邮件和用户名之间的匹配。 - Hubert Perron
我有几个问题:
  1. 生成唯一令牌的优势是什么?
  2. 如果我将用户重定向到帐户页面,要求用户输入新密码,在这种情况下,如果我自动生成密码并发送电子邮件给用户,会发生什么?
我们为什么需要生成唯一令牌并向用户显示帐户表单以更改密码?
- Hemant Kothiyal
自动生成密码和让(经过身份验证的)用户输入密码之间的区别在于,他们会记住自己输入的密码。此外,它永远不会将密码保存在电子邮件中,以防稍后有人获得了保存的电子邮件,这将无法帮助他们破解密码。 - gahooa
1
好的,告诉我一个事情,如果用户点击唯一令牌的链接,那么自动登录用户是否是一个好主意,而不需要询问登录凭据? - Hemant Kothiyal
1
@Hemant:是的,只要您有令牌,就可以自动登录它们。您知道,令牌是通过“忘记密码”链接获得的(延迟)身份验证。它断言他们可以访问他们的电子邮件帐户。 - gahooa

0

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