关于安全性:没有数据库表的电子邮件重置密码

Password reset by email without a database table

通过邮件重置用户密码的正常流程是:

  • 生成随机字符串并将其存储在数据库表中
  • 向用户发送电子邮件字符串
  • 用户单击包含字符串的链接
  • 根据数据库验证字符串;如果匹配,则重置用户的pw
  • 然而,维护一个表和过期的旧字符串等似乎有点不必要的麻烦。这种替代方法有什么明显的缺陷吗?

  • 生成用户现有密码的MD5哈希
  • 向用户发送哈希字符串
  • 用户单击包含字符串的链接
  • 通过再次散列现有的pw来验证字符串;如果匹配,则重置用户的pw。
  • 请注意,用户的密码已经以哈希和盐格式存储,我只是再次对其进行哈希处理,以获得唯一但可重复的字符串。

    是的,有一个明显的"缺陷":这样生成的重置链接在用户更改密码(点击链接)之前不会过期。我真的不明白为什么这会是一个问题——如果邮箱被破坏了,那么用户就完蛋了。而且没有重用的风险,因为一旦用户的密码被更改,重置链接将不再匹配。


    要修复obvious flaw,请将当前日期(如果一天太长,则添加更多表示当前一天分数的时间相关信息)添加到要散列的内容中,以生成神秘字符串并检查它——这会使字符串"过期"(如果需要更长的"到期时间",则可以检查前一个日期以及当前日期或分数)。所以在我看来你的计划是可行的。


    如果有人使用密码散列访问您的数据库,他们将不知道实际的密码。如果您实现了这个系统,那么他们就可以生成重置链接并自己重置密码。有了随机字符串和妥协的知识,您就可以使所有的随机字符串失效,并且即使不知道访问权限,只有在重置密码过程中的用户才会受到损害。不太可能,但考虑到随机字符串的名义开销,这可能是值得考虑的。


    实际上,在再次考虑这个问题之后,您的方法可能比"正常流"的安全性要低。

    如果您只发送回HASH(HASH(user's original password)),我可以看到这样的场景,攻击者可以利用:

    情景1:

  • Jim在您的站点注册为[email protected]
  • Jim请求密码重置,但不使用。重置的电子邮件永远放在他的收件箱里。
  • Jim更改了他在你网站上的电子邮件地址。
  • [email protected]受到Bob的影响。
  • Bob现在通过他的分布式GPGPU服务器场进行一次野蛮攻击,并恢复Jim的密码。
  • 情景2:

  • Jim使用密码jimjonesupinthisma!作为他的银行账户。
  • Jim在您的站点注册为[email protected][email protected]Jim的银行账户没有任何关联。
  • [email protected]受到Bob的影响。
  • Bob现在请求复位,他现在有HASH(HASH(jim's password))了。
  • Bob现在通过他的分布式GPGPU服务器场进行了一次野蛮攻击,并恢复了Jim的密码,然后他使用该密码访问Jim的银行帐户。
  • 情景3:

    (您的站点使用TLS,用户通过TLS注册。)

  • Jim在您的站点注册为[email protected]
  • Bob请求在Jim的帐户上重置密码。
  • Bob在641a房间为NSA工作。
  • Bob使用他的全球互联网嗅探器,并获得HASH(HASH(jim's password)),因为它以明文形式发送给[email protected]
  • Bob现在通过他的分布式GPGPU服务器场进行一次野蛮攻击,并恢复Jim的密码。
  • 场景1和场景2的变体一直在发生(取决于哈希和密码的强度),我不太确定3。关键是,您的方法会窃取不必要的信息,这确实可以利用攻击者攻击您的用户。

    我建议您使用随机生成的令牌,这些令牌与用户的密码无关。


    刚刚通过这个问题,有一个想法:

    1)发布一个包含用户帐户信息的JWT(JSON Web令牌)。令牌已过期,例如1小时。

    2)通过电子邮件/链接将令牌发送给用户

    3)用户点击链接,令牌被发送到服务器端点,令牌被验证。如果有效,则解包令牌并更新用户帐户

    这种方法有缺陷吗?不接触数据库(必要时,新用户密码除外)


    假设在一个非常罕见的情况下,您的两个用户拥有相同的哈希密码,即使在将随机salt连接到它之后,仍然存在问题,对吗?我想,如果你在重置密码链接中添加用户ID的email或hashid,不会有什么影响。