【问题标题】:How can I provide password reset functionality in a secure way?如何以安全的方式提供密码重置功能?
【发布时间】:2013-08-20 01:38:51
【问题描述】:

我目前正在完成一个网站,用户需要创建一个个人帐户才能玩同一网站上托管的游戏。我目前难以弄清楚的是如何在忘记密码的情况下为用户实施安全密码重置功能。

这是当前的流程:

第 1 步:用户点击网站上的“忘记密码”链接。
第 2 步:用户进入表单并输入电子邮件地址两次,然后才进入已发送电子邮件。
第 3 步:电子邮件包含指向另一个表单的链接,用户可以在该表单中输入两次新密码以进行确认。进入第二种形式后,系统会在数据库中的 Recover_Password 表中插入一条新记录,其中包含“id”、“token”、“created_at”和“expires_at”列。

这是链接-> (mywebsitename).com/form?id=99999&token=
其中“id”是用户的id,“token”是从do_hash($id . date('Y-m-d'))生成的

第 4 步:用户完成表单并被带到登录页面。系统从数据库中清除令牌记录,并从用户表中更新用户当前密码。

我还想知道如果用户在第二个表单中尝试刷新浏览器页面该怎么办。我目前只允许在 get 参数中有 id 和 token 值并且它们都存在于数据库中的情况下访问该页面。

我正在为整个网站使用 Codeigniter,我需要知道这是否是一种安全的方法,以及我应该如何处理令牌和数据库。谢谢!!

【问题讨论】:

  • “在发送电子邮件之前两次。” --- 要求用户重复 4 次电子邮件将使解决方案更加安全
  • 这不是主要问题的答案,但这里没有理由使用散列。特别是如果它很容易被攻击者生成。您可以只使用一个非常长的随机字符串,因为无论如何您都在检查数据库。
  • 设置令牌过期时间,用户点击提交后删除令牌... $_GET attr 上有两个随机生成的字段,example.com/ChangePass.php?Token=&RefID=&UserID=? 并且只允许在 refID 和令牌匹配时更改密码存储的值。
  • @zerkms 离题,但我的问题得到了解决。它在第 4 次硬重置后随机开始工作。我很害怕我现在必须重新启动服务器 -.-
  • @hRdCoder:如果您需要随机的东西 - 生成纯随机的东西总是一个好主意,而不是从某些用户(可猜测的)数据派生。如果您知道用户的 id - 您可以轻松生成哈希

标签: php security passwords


【解决方案1】:

处理密码重置的安全方法如下所示:


密码重置请求:

  1. 用户打开密码重置申请表并输入邮箱地址(无需输入两次,只需进行语法验证即可)。

  2. 您的应用程序检查电子邮件是否存在于您的数据库中。如果它存在,它会创建一个令牌,该令牌应该是随机的,而不是源自用户 ID 或时间戳等信息。 令牌的散列将与用户 ID 和到期日期一起存储在数据库中的单独表中。通过电子邮件将带有令牌的链接发送给用户。

  3. 应用程序显示电子邮件已发送的确认信息。此页面可以包含电子邮件地址,因此用户可以检查他是否有拼写错误(毕竟没有信息是否该电子邮件在数据库中,因此攻击者无法测试其存在)。

密码重置:

  1. 用户单击链接并打开重置表单。在此表格上,他可以输入两次新密码。令牌必须作为隐藏的输入标签包含在表单中。

  2. 提交表单后,应用程序检查他的令牌。如果匹配且未过期,则可以更改密码并直接登录用户(您可以将登录表单留给他)。最后令牌应该被停用,我自己更喜欢保留条目,所以当他再次单击链接时,我可以通知用户令牌已被使用。

您会遇到的一个问题是,您必须在数据库中找到令牌的哈希值。存储令牌有两种可能的方式:

  • 您使用不带盐的 SHA512 等哈希算法对令牌进行哈希处理。如果令牌非常强(最小长度 20,0-9 a-z A-Z),这是安全的。从理论上讲,您必须在将此类哈希输入数据库之前检查它是否已经存在,实际上这可以忽略不计。我实现了一个可以处理此类令牌的password-reset class

  • 您使用 BCrypt 和 salt 对令牌进行哈希处理。这允许更短的令牌,但您无法在数据库中搜索散列令牌。相反,您必须在链接中包含 row-id 才能找到令牌。

【讨论】:

  • 感谢@martin 的出色和清晰的回复。不过,我确实有几个问题。 1. 在上述密码重置请求的第 2 步中,您建议不要从用户 ID 或时间戳派生令牌。如果令牌是日期到第二个,散列怎么办?这将使它根据一天中的时间而有所不同。 2.也许我应该在我原来的问题中包含这个,但是应该如何处理令牌的到期?我已经研究过了,它建议我使用 crontab(如果是 Linux)或在 MySQL 中为令牌安排一个事件。我该怎么做?
  • @hRdCoder - 对于你的第一个问题,问题是令牌变得可预测。如果您知道生成链接的大致时间,则可以严重缩小可能值的范围。对数据库具有读取访问权限(SQL 注入)的攻击者可以轻松地暴力破解令牌。第二个问题比你想象的要容易得多。只需将令牌创建的时间戳存储在数据库中,然后等到有人单击链接。当用户最终尝试更改密码时,检查令牌是否仍然有效。
  • 感谢您的意见。我会试一试,看看进展如何。谢谢。
  • 您对指示电子邮件帐户是否存在的安全性有何看法?
  • @jontsai - 提供有关电子邮件存在的反馈可以使攻击者更容易。 1)他知道这个账户存在,因此可以集中攻击这个账户。 2)他可以将准备好的链接发送给用户以尝试会话固定。 3) 根据您的站点,用户不希望被识别为成员。当然还有其他原因,所以我不会就帐户的存在提供任何反馈。
猜你喜欢
  • 2011-01-22
  • 2017-02-09
  • 2021-11-25
  • 1970-01-01
  • 2015-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
相关资源
最近更新 更多