Time limited, or one time use, password reset tokens?
用户忘记了密码,而且(几乎)所有会员网站都需要一种帮助用户重新登录的方法。
我想实现常见的场景:
下面是我计划如何实现这一点(c/asp.net mvc):
我的问题是:保持这样(他们可以在任何时候、现在或将来使用该链接重置密码)或添加时间戳来限制他们必须重置密码的时间?
从用户体验的角度来看,随时准备好重置密码的能力是很好的,但是我要确保我不会忽略这可能会引起的一些安全问题。
你的计划实际上是可行的,但也有一些地方需要改进。但首先是你最初关于时限的问题:
让我们问一个相反的问题:为什么令牌应该保持有效的无穷大?
没有好处,当两年后可以点击重置链接时,要么用户在大约一小时内点击链接,要么他可能已经忘记了链接(如果需要,还可以请求一个新的链接)。另一方面,能够阅读电子邮件并不一定意味着攻击者必须侵入电子邮件帐户,例如办公室中打开的电子邮件客户端、丢失的手机、USB驱动器上的备份…
最重要的改进是,您应该只在数据库中存储令牌的散列值。有权访问数据库(SQL注入)的人可以要求为他喜欢的任何电子邮件地址重置密码,因为他可以看到新的令牌,所以他可以使用它来设置自己的密码。
然后我将这些重置信息存储在一个单独的表中。在那里,您可以存储用户ID、哈希标记、到期日期以及链接是否已被使用的信息。用户当时不处于特殊状态。
也许我误解了这一点,但是重置链接应该指向一个特殊的页面进行密码重置。当用户进入登录页面时,不应进行特殊处理,登录页面不应知道有一个挂起的密码重置。
重置令牌应该是不可预测的,这可以通过从操作系统的随机源读取真正的随机代码来实现。
所以,我在评论中试图回避的这种方法存在一些问题。当您将"确认令牌"存储在用户密码中时,您基本上已经销毁了他们的密码。
我,一个恶意的人,然后可以采取一个庞大的电子邮件地址列表和一个机器人网络,洪水与密码重置请求您的服务器和锁定您的用户从他们的帐户。当然,您的用户会收到一封电子邮件进行重置,但是如果我能够足够快地重置密码,可能会有电子邮件积压(或者,如果您同步执行,我可能会完成整个应用程序)。
我,你系统的一个普通用户,可能会尝试重置我的密码,但无法找出为什么我没有收到重置电子邮件,因为我甚至不知道一个垃圾邮件文件夹(或它从未到达)。幸运的是,我只记得密码是什么,但它不再工作,因为密码现在是一个不透明的guid,我基本上死在水里,直到我能找到重置电子邮件。
这是您应该使用的过程。
另外,为了防止这种情况已经发生,请确保您正在对用户密码进行哈希和加盐。当你用一个guid替换密码的时候,听起来不像是在做这个,所以你只需要重新检查一下。
我会提出以下建议:
理想情况下,您的用户界面不应提供任何反馈,以允许黑客确定其重置请求是否成功。你不希望他们在你的页面上搜索电子邮件地址或出生日期。然而,这是一个可用性权衡,因此,是否这样做取决于您真正需要多少安全性。
您可能还考虑需要一个验证码,这使得暴力和应用程序DoS攻击更加困难。
尽快使一次性令牌过期。我认为几个小时就够了。你不应该认为电子邮件是私有的——它不是私有的,除非你在基本协议的基础上使用了安全的电子邮件技术(如PGP)(大多数人不这么认为)。你最不想看到的是黑市开放,在那里你的吉他被买卖,这正是如果它们有无限的寿命可能发生的事情。
不要使用guid。它们不是密码随机的,是可以猜测的。我建议您使用加密随机数生成器并将其转换为base64。
用户还忘记重置密码(事情发生了)。出于对密码的偏执,我建议将链接寿命限制为24小时。这应该足够了。它不能解决恶意拦截的问题,但总比什么都没有好。