【问题标题】:Generate secret code for password reset生成密码重置密码
【发布时间】:2011-04-03 06:21:32
【问题描述】:

我正在做一个允许用户重置密码的模块。我注意到大多数网站如何提供一个确认链接,其中包含具有唯一哈希的查询字符串。

我的问题是:每次同一个用户请求忘记密码时,如何生成这个唯一的哈希?我应该将此哈希存储在数据库中并稍后将其用于验证吗?会安全吗?或者我应该创建某种生成一次性密码的算法?如何生成 OTP?

【问题讨论】:

  • 大家好,谢谢回复。我对响应速度感到惊讶。哇!! * 社区摇滚!!

标签: php hash one-time-password


【解决方案1】:

是的,你应该

  1. 生成随机重置令牌。参见例如this answer
  2. 将其存储在数据库中(可能有过期时间)
  3. 使用重置令牌向用户发送电子邮件。
  4. 用户使用查询字符串中的重置令牌访问重置密码页面。
  5. 检查数据库以查看与重置令牌关联的用户以及是否尚未超过到期时间。
  6. 如果一切正常,允许用户重置密码并从数据库中删除重置令牌。

对于重置令牌(或任何您想称呼它的名称)的生成似乎存在很多混淆。请阅读我链接到的答案,不要用散列和弱种子重新发明*。

【讨论】:

  • 附加建议:在存储到数据库之前始终对重置密码进行哈希处理,因为它也可以临时用作用户密码(我的意思是它可以像普通用户密码一样授予对用户帐户的访问权限)。
  • 在这个答案中你说“生成一个唯一的随机重置密码”。这要么是一种不正确的方法,要么是不正确的术语。如果我请求忘记密码 - 使用您的电子邮件地址 - 它应该会向您发送一封电子邮件,其中包含随机字符串(也称为 nonce 或令牌),但您现有的密码应该继续有效!这可以防止我仅仅通过知道您的用户名或帐户电子邮件来拒绝您的服务。所以不,永远不要为用户生成一个实际的随机密码,这不是一个好方法。只生成一个随机令牌。
  • @Kzqai“重置密码”并不意味着“已重置密码”,但我明白你的意思是,tokennonce 是更好的选择。我已经编辑了答案。
  • 我可以使用以前用户的密码 (经过哈希处理) 作为随机令牌吗? (第一步)?实际上,我需要将其作为该 reset-url 的参数传递。我可以这样做吗?
【解决方案2】:

只需使用一些带有用户 ID、用户加盐(你加盐用户密码,对吗?)和伪随机数据的哈希函数就可以了:

$pwd_reset_hash = hash ( 'sha256' , $user_id . $user_salt, uniqid("",true));

将其存储在数据库中(连同请求时间)作为该用户的重置键

 user_id  pwd_reset_hash  time_requested  
===========================================  
 123      ae12a45232...   2010-08-24 18:05

当用户尝试使用它时,检查哈希是否与用户匹配并且时间是最近的(例如“重置代码在 3 小时内有效”或类似的东西)

使用或过期时从数据库中删除

【讨论】:

  • 我建议不要这样做。它不像time()那么糟糕,但它仍然不安全。测量他和服务器之间的延迟的攻击者可能每 20-50 次至少猜出 1 个哈希值。
  • 至少用uniqid()代替microtime...
  • 大家好,我知道可以使用 microtime。但是让我们说如果我要做一个请求密码模块。用户提供他们的有效电子邮件,系统会发送一封带有确认链接的电子邮件,其中包含包含用户 ID 和哈希的查询字符串。当用户收到电子邮件并单击确认链接时,系统应该将他们带到相应的页面并验证哈希是否正确?要再次检查此哈希,如何使用微时间生成相同的哈希??
  • @Artefacto:已编辑。有了uniqid 和每个用户的哈希值,现在应该不会轻易猜到了吧?
  • @Artefacto:“猜测哈希”是什么意思?你的意思是通过知道用户ID、用户密码和盐来猜测重置密码哈希?你能详细说明一下吗?
【解决方案3】:

要走的路确实是生成某种随机的东西并将其存储在数据库中。更改密码后,您将立即从表中删除相关记录,以便无法再次使用该链接。

  • 将网址邮寄给用户,包括“令牌”。
  • 如果链接被访问,检查token是否存在,允许用户修改密码
  • 从数据库中删除令牌。

正如在其他回复中已经说过的,对用户 ID 执行 SHA1 或 MD5,结合微时间和一些盐字符串通常是安全的选择。

【讨论】:

  • 嗨 Blizz,我想存储在数据库中是一种方法。感谢暴雪
  • 1) 盐最好足够大,这样它就不能通过蛮力被几个哈希猜到 2) 每次都使用mt_rand 有那么难吗? PHP中有一个函数可以创建加密安全的随机数,你为什么要重新发明*,构建一个“自制”随机字符串生成器,其加密弱散列(如MD5)由microtime等弱种子播种...
  • 没有人说你不能将所有这些结合起来。我通常取 userId、2 个随机数、microtime 和一些随机字符串。
【解决方案4】:

1) 要生成唯一的哈希,混合当前时间、用户 ID 和一些盐(文本)。例如,如果您的网站是 mysite.com,则使用以下代码:

 $hash = md5(time() . $userid . 'mysite');

这将创建一个不错的哈希。

2) 是的,将其存储在数据库中。
3) 是的,只要在固定时间后使哈希过期,它就会是安全的。
4) 不,生成一次性密码通常会惹恼用户。

【讨论】:

  • 不,不会,因为它是可预测的。
  • 如果他大幅改变盐分,那将是不可预测的。不必完全使用“mysite”。
  • 大家好,感谢您的快速回复。我将继续使用数据库方法 =)