如何以安全的方式提供密码重置功能


How can I provide password reset functionality in a secure way?

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

这就是目前正在进行的过程:

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

这是链接->(mywebsitename).com/表单吗?id=99999&令牌=
其中"id"是用户的id,"token"是从do_hash($id . date('Y-m-d'))生成的

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

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

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

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


密码重置请求:

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

  2. 您的应用程序会检查该电子邮件是否存在于您的数据库中。如果它存在,它会创建一个令牌,该令牌应该是随机的,而不是从用户ID或时间戳等信息中获取的。标记的哈希将与用户ID和到期日期一起存储在数据库中的一个单独的表中。每个电子邮件都会向用户发送带有令牌的链接。

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

密码重置:

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

  2. 提交表格后,申请会检查令牌。如果匹配且未过期,则可以更改密码,用户可以直接登录(然后您可以省去登录表单)。最后,令牌应该被停用,我自己更喜欢保留条目,这样当用户再次单击链接时,我可以通知他令牌已经被使用。

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

  • 您可以使用类似SHA512的哈希算法对令牌进行无盐哈希。如果令牌非常强(最小长度为20,0-9 a-z a-z),则这是安全的。理论上,在将这样的散列输入数据库之前,必须检查它是否已经存在,而在实践中,这是可以忽略不计的。我实现了一个密码重置类,可以处理这样的令牌。

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