关于安全性:“忘记密码”实施的最佳方式?

Best way for a 'forgot password' implementation?

我正在寻找实现"忘记密码"功能的最佳方法。

我提出了两个想法:

  • 当用户单击"忘记密码"时,用户需要输入用户名、电子邮件以及可能的出生日期或姓氏。然后一封带有临时密码的邮件将被发送到用户电子邮件帐户。用户使用临时密码登录并重置其密码。

  • 类似的,但是电子邮件中会包含一个链接,允许用户重置密码。

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


    更新:2013年5月修订为更好的方法

  • 用户输入用户名并点击"忘记密码"。我还建议输入电子邮件地址而不是用户名,因为用户名有时也会被忘记。
  • 系统有一个表password_change_requests和列IDTimeUserID组成。当新用户按下按钮时,将在表中创建一条记录。Time列包含用户按下"忘记密码"按钮的时间。ID是一个字符串。创建一个长的随机字符串(例如,一个guid),然后像密码一样散列(它本身是一个独立的主题)。然后将此哈希用作表中的"id"。
  • 系统向用户发送包含链接的电子邮件。链接还包含原始ID字符串(散列之前)。链接是这样的:http://www.mysite.com/forgotpassword.jsp?ID=01234567890ABCDEF。forgotpassword.jsp页面应该能够检索id参数。对不起,我不懂Java,所以我不能更具体。
  • 当用户单击电子邮件中的链接时,他将移动到您的页面。页面从URL中检索ID,再次对其进行哈希处理,并对照表进行检查。如果存在这样的记录,并且不超过24小时,则会提示用户输入新密码。
  • 用户输入一个新密码,点击OK,从此以后每个人都过着幸福的生活…直到下次!

  • 这完全取决于您的网站和您试图实现的安全级别,但是Web应用程序的基本过程如下所示:

  • 用户导航到"忘记我的密码"页面,输入他们的用户名或电子邮件(以唯一的为准)以请求密码重置。

  • 在此阶段,您可以选择通过询问其他信息来确认请求,例如预先定义的安全问题的答案或他们的出生日期等。此额外级别将阻止用户接收他们没有请求的电子邮件。

  • 查找用户的帐户。根据帐户记录保存临时密码(通常是一个guid)和时间戳。向用户发送包含临时密码的电子邮件。

  • 用户要么单击包含临时密码和电子邮件中用户标识符的链接,要么导航到"忘记我的密码"页面,然后复制并粘贴临时密码及其标识符。用户输入新密码并确认。

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

  • 这里的原则是向用户发送一个临时密码,让他们更改密码。最初存储的密码(应该散列!)不会更改为临时密码,以防用户记住它。

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

    注意:这个过程完全依赖于用户电子邮件帐户的安全性。所以这取决于你想要达到的安全级别。对于大多数网站/应用程序来说,这通常已经足够了。


    特洛伊·亨特在他的文章中提出了一些很好的观点,关于构建安全密码重置功能,你想知道的一切。最相关的摘录是:

    [T]here are two common approaches:

  • Generate a new password on the server and email it
  • Email a unique URL which will facilitate a reset process
  • Despite plenty of guidance to the contrary, the first point is really not where we want to be. The problem with doing this is that it means a persistent password – one you can go back with and use any time – has now been sent over an insecure channel and resides in your inbox.

    But there’s one more big problem with the first approach in that it makes the malicious lockout of an account dead simple. If I know the email address of someone who owns an account at a website then I can lock them out of it whenever I please simply by resetting their password; it’s denial of service attack served up on a silver platter! This is why a reset is something that should only happen after successfully verifying the right of the requestor to do so.

    When we talk about a reset URL, we’re talking about a website address which is unique to this specific instance of the reset process.

    What we want to do is create a unique token which can be sent in an email as part of the reset URL then matched back to a record on the server alongside the user’s account thus confirming the email account owner is indeed the one attempting to reset the password. For example, the token may be"3ce7854015cd38c862cb9e14a1ae552b" and is stored in a table alongside the ID of the user performing the reset and the time at which the token was generated (more on that in a moment). When the email is sent out, it contains a URL such as"Reset/?id=3ce7854015cd38c862cb9e14a1ae552b" and when the user loads this, the page checks for the existence of the token and consequently confirms the identity of the user and allows the password to be changed.

    The other thing we want to do with a reset URL is to time limit the token so that the reset process must be completed within a certain duration, say within an hour.

    Finally, we want to ensure that this is a one-time process. Once the reset process is complete, the token should be deleted so that the reset URL is no longer functional. As with the previous point, this is to ensure an attacker has a very limited window in which they can abuse the reset URL. Plus of course the token is no longer required if the reset process has completed successfully.

    他在避免信息泄漏、验证码、双因素身份验证以及密码散列等基本最佳实践方面提出了更多的建议。我认为重要的是要注意,我不同意特洛伊关于安全问题的有效性,而更倾向于布鲁斯施耐尔对这一做法的怀疑:

    The point of all these questions is the same: a backup password. If you forget your password, the secret question can verify your identity so you can choose another password or have the site e-mail your current password to you. It's a great idea from a customer service perspective -- a user is less likely to forget his first pet's name than some random password -- but terrible for security. The answer to the secret question is much easier to guess than a good password, and the information is much more public.


    我会去的:

  • 询问用户电子邮件,检查电子邮件是否已注册
  • 生成guid并发送到该电子邮件
  • 尚未重置密码
  • 用户单击链接,然后必须输入新密码
  • 只有当用户在您的站点中时才重置密码,并且在键入新密码后单击了重置按钮。
  • 使该guid在短时间内可过期,以使其更安全。

  • 当您通过电子邮件发送任何信息时,它将不安全。有太多的方法可以得到它。对于一个想要窃取你信息的熟练黑客来说,这是孩子的游戏。

    不要通过电子邮件发送任何个人信息,如密码和收入信息,因为如果这些信息被泄露或被盗,可能会让您和您的组织感到非常尴尬。认真考虑安全问题。所有的砖块只需一次事故就可以掉下来。

    至于密码检索,请仔细阅读忘记密码的最佳实践。

    The bottom line is that an application
    following best practices should allow
    a user to reset his own password.
    Personal security questions should be
    used. The application should not send
    email, display passwords, nor set any
    temporary passwords.

    编辑:更新的链接


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

    • 当确认用户身份(安全问题、电子邮件地址等)后,显示一半的临时密码,然后将另一半发送到电子邮件帐户。如果电子邮件帐户已被泄露,则同一个人也不太可能成功执行中间人攻击。(在英国政府门户网站上看到)

    • 通过电子邮件和其他媒介确认身份-例如通过文本发送到注册手机的代码。(见易趣网/贝宝)

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


    如果注册时包含电子邮件地址。"忘记密码"按钮向该电子邮件地址发送电子邮件。它确保将信息发送到受信任的电子邮件。

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


    以下是三个非常好的链接,提供有关密码重置的信息:

  • http://jtauber.com/blog/2006/03/20/account_management_模式/

  • (不要让用户使用GET确认):http://www.artima.com/forums/flat.jsp?论坛=106&thread=152805&start=15&msrange=15

  • http://fishbowl.pastiche.org/archives/docs/passwordrecovery.pdf

  • 希望有帮助。他们确实帮助我理解了这个问题。


    我会强制跨帐户使用唯一的电子邮件地址。

    然后,只需发送一个链接到一个允许用户更改密码的临时页面。(允许24小时或更短时间)

    在这种情况下,用户的电子邮件帐户是最薄弱的环节。


    不要将密码通过电子邮件发送给用户。即使它是自动生成的。最佳方法(建议并由SAN和其他人使用):

  • 在忘记密码页面上,询问电子邮件/用户ID和新密码来自用户。
  • 通过电子邮件发送存储电子邮件的链接对于激活的帐户链接。
  • 当用户单击该链接时,启用新密码。
  • 如果他在24小时左右没有单击链接,请禁用链接(这样它就不会再更改密码)。

    未经用户同意,不得更改密码。这意味着不要仅仅因为有人点击了忘记密码链接并算出了帐户名就发送新密码。