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

我正在寻找实现“忘记密码”特性的最佳方法。

我有两个想法:

  1. 当用户点击忘记密码,用户需要键入用户名,电子邮件,可能是生日或姓氏。然后一个带有临时密码的邮件将被发送到用户电子邮件帐户。用户使用临时密码登录并重置密码。

  2. 类似的,但电子邮件将包含一个链接,让用户重置他的密码。

或者有人能给我一个更好更安全的建议吗?我还在考虑发送临时密码或链接,强制用户在24小时内重置密码,否则临时密码或链接将无法使用。怎么做?

111157 次浏览

如果您在注册时附上电子邮件地址。“忘记密码”按钮将向该电子邮件地址发送电子邮件。它确保信息被发送到受信任的电子邮件。

(除非数据库被黑,否则没有什么是安全的)。

更新: 2013年5月修订,以便采取更好的办法

  1. 用户输入用户名并点击“忘记密码”。我还建议输入电子邮件地址而不是用户名,因为用户名有时也会被遗忘。
  2. 系统有一个 password_change_requests表,其中包含 IDTimeUserID列。当新用户按下按钮时,将在表中创建一条记录。Time列包含用户按下“忘记密码”按钮的时间。ID是一个字符串。创建一个长的随机字符串(比如 GUID) ,然后创建 像密码一样散列(它本身是一个单独的主题)。然后,这个散列用作表中的“ ID”。
  3. 系统向用户发送一封包含链接的电子邮件。该链接还包含原始 ID 字符串(在散列之前)。链接将是这样的: http://www.mysite.com/forgotpassword.jsp?ID=01234567890ABCDEF。Jsp 页面应该能够检索 ID 参数。抱歉,我不懂 Java 所以我不能说得更具体了。
  4. 当用户单击电子邮件中的链接时,他将移动到您的页面。该页面从 URL 中检索 ID,再次散列它,并对表进行检查。如果存在这样一个记录,并且不超过,比如说,24小时,用户 提示输入新密码
  5. 用户输入一个新的密码,点击确定,每个人都生活在很想和你在一起... 直到下一次!

这完全取决于你的网站和你想要达到的安全水平,但是一个 web 应用的基本过程是这样的:

  1. 用户导航到“忘记我的密码”页面,并输入他们的用户名或电子邮件(无论是唯一的) ,以请求密码重置。

  2. 在这个阶段,您可以通过询问额外信息来确认请求,例如预先定义的安全问题的答案或者他们的出生日期等。这个额外的级别阻止用户收到他们没有要求的电子邮件。

  3. 查查用户的账户。保存一个临时密码(通常是 GUID)并对帐户记录进行时间戳。向包含临时密码的用户发送电子邮件。

  4. 用户可以点击邮件中包含临时密码和用户标识符的链接,或者导航到“忘记我的密码”页面,复制并粘贴临时密码及其标识符。用户输入新密码并确认。

  5. 查找用户的记录,如果当前时间在步骤2中保存的时间戳的指定时限内(例如1小时) ,那么散列并保存新密码。(显然只有在临时密码匹配的情况下!).删除临时 GUID 和时间戳。

这里的原则是,用户通过电子邮件获得一个临时密码,让他们使用 改变密码。原始存储的密码(它应该是散列的!)永远不会更改为临时密码,以防用户记住它。

原始密码将永远不会显示给用户,因为它应该是哈希和未知的。

Note 此过程完全依赖于用户电子邮件帐户的安全性。因此,这取决于您希望实现的安全级别。对于大多数网站/应用程序来说,这通常已经足够了。

如前所述,这取决于所需的安全级别,然而,如果您需要更高级别,我看到的一些新颖的解决方案包括;

  • 显示一半的临时密码时,用户的身份已经确认(安全问题,电子邮件地址等) ,然后另一半被发送到电子邮件帐户。如果电子邮件帐户已经被入侵,那么同一个人也不太可能设法执行中间人攻击。(见英国政府网站)

  • 通过电子邮件和其他媒介确认身份——例如通过文本发送到注册手机的代码。(见 eBay/PayPal)

因为在这两个极端之间的某个地方,实现安全性问题可能是 DaveG 提到的方法。

当你通过电子邮件发送任何信息时,它都是不安全的。有太多的方法可以得到它。对于一个想要窃取你信息的熟练黑客来说,这简直是小菜一碟。

不要通过电子邮件发送任何个人信息,如密码和收入信息,因为如果这些信息被泄露或窃取,可能会让你和你的组织非常尴尬。认真考虑安全问题。只要发生一件事,所有的砖头都会倒下。

至于密码检索,彻底阅读 忘记密码最佳做法

底线是,一个应用程序 按照最佳做法应允许 用户重置自己的密码。 个人安全问题应该是 应用程序不应发送 电子邮件,显示密码,也没有设置任何 临时密码。

编辑: 更新链接

我会在所有帐户中强制执行唯一的电子邮件地址。

接下来就是发送一个临时页面的链接,允许用户更改密码。(容许24小时或以下)

在这个场景中,用户的电子邮件帐户是最薄弱的环节。

永远不要用电子邮件发送密码给用户。即使是自动生成的。最佳方法(由 SANS 和其他机构推荐和使用) :

  1. 在忘记密码的页面上,问 电邮/用户编号及新密码 从用户。
  2. 通过电子邮件发送到存储的电子邮件的链接 那个账户的激活 链接。
  3. 当用户单击该链接时, 启用新密码。

如果他没有在24小时左右点击链接,禁用该链接(这样它就不会再更改密码)。

未经用户同意,切勿更改密码。这意味着不要仅仅因为有人点击了被遗忘的密码链接并且找到了帐户名就给新的密码发电子邮件。

我觉得:

  1. 要求用户发送电子邮件,检查电子邮件已注册
  2. 生成 GUID,并发送到该电子邮件
  3. 还不要重设密码
  4. 用户单击链接,然后必须输入新的通行证
  5. 只有当用户在您的网站后才重置密码,并且在键入新密码后已单击重置按钮。
  6. 使 GUID 在短时间内过期,以使其更安全。

这里有三个非常好的链接,提供密码重置的信息:

  1. Http://jtauber.com/blog/2006/03/20/account_management_patterns/

  2. (不要让用户使用 GET 进行确认) : http://www.artima.com/forums/flat.jsp?forum=106&thread=152805&start=15&msRange=15

  3. Http://fishbowl.pastiche.org/archives/docs/passwordrecovery.pdf

希望能帮上忙,他们帮我理解了这个问题。

Troy Hunt 在他的文章 关于构建安全密码重置功能,您想知道的一切中提出了一些很好的观点:

[ T ]这里有两种常见的方法:

  1. 在服务器上生成一个新密码并将其发送到电子邮件
  2. 电子邮件一个唯一的网址,这将促进一个重置过程

尽管有很多相反的指导意见,但第一点确实不是我们想要的。这样做的问题在于,它意味着一个持久的密码——你可以随时回去使用——现在已经通过一个不安全的通道发送到你的收件箱中。

...

但是第一种方法还有一个更大的问题,它使恶意锁定帐户变得非常简单。如果我知道某人在某个网站上拥有一个帐户的电子邮件地址,那么我就可以随时通过重置他们的密码把他们锁在外面,这简直是分布式拒绝服务攻击攻击!这就是为什么只有在成功地验证了请求者的权利之后才会发生重置。

当我们谈论一个重置 URL 时,我们谈论的是一个网站地址,它对于这个特定的重置过程实例来说是独一无二的。

...

我们想要做的是创建一个唯一的令牌,可以作为重置 URL 的一部分在电子邮件中发送,然后与用户帐户旁边的服务器上的记录相匹配,从而确认电子邮件帐户所有者确实是试图重置密码的人。例如,令牌可能是“3ce7854015cd38c862cb9e14a1ae552b”,并与执行重置的用户的 ID 和令牌生成的时间(稍后详细介绍)一起存储在一个表中。当电子邮件发出时,它包含一个 URL,例如“ Reset/?Id = 3ce7854015cd38c862cb9e14a1ae552b”,当用户加载这个命令时,页面检查是否存在令牌,从而确认用户的身份并允许更改密码。

...

我们想对重置 URL 做的另一件事是限制令牌的时间,以便重置过程必须在一定的时间内完成,比如说一个小时内。

...

最后,我们希望确保这是一个一次性的过程。一旦重置过程完成,令牌应该被删除,以便重置 URL 不再起作用。与前一点一样,这是为了确保攻击者有一个非常有限的窗口,在这个窗口中他们可以滥用重置 URL。当然,如果复位过程已经成功完成,就不再需要令牌了。

他在避免信息泄露、验证身份验证、双因素身份验证以及密码哈希等基本最佳实践方面提出了更多有益的观点。我认为有必要指出,我不同意特洛伊关于安全问题的有用性,我更喜欢 布鲁斯 · 施奈尔对实践的怀疑:

所有这些问题的要点都是一样的: 一个备份密码。如果您忘记了密码,这个秘密问题可以验证您的身份,这样您就可以选择另一个密码,或者让网站将您当前的密码通过电子邮件发送给您。从客户服务的角度来看,这是一个好主意——用户忘记第一只宠物名字的可能性比忘记随机密码的可能性要小——但对安全性来说却很糟糕。这个秘密问题的答案比一个好的密码更容易猜测,而且信息也更加公开。