如何防止有人在重置密码链接中猜测令牌

信息安全 。网 asp.net-mvc
2021-08-15 18:24:41

目前我有以下设置来处理忘记密码的用户。

  1. 用户输入他/她的电子邮件地址并按下忘记密码按钮。
  2. 我查找属于该电子邮件地址的用户,并在数据库中存储了一个新的“忘记密码请求”。忘记密码请求项如下所示:

    Guid ForgotPasswordRequestId;
    Guid UserId;
    DateTime ValidUntil;
    
  3. 我通过将 ForgotPasswordRequest Guid 转换为 Base64 字符串来生成一个令牌来识别忘记密码的请求。Guid 是第 4 版 Guid(随机的,不是基于时间或 MAC 地址的)。检查此MSDN 链接以获取有关实施的说明。

  4. 我创建了一个链接www.example.com/account/ForgotPassword?token=TOKEN,通过电子邮件发送给用户。

  5. 每当有人在 24 小时内访问该链接时,他/她都可以为该帐户设置新密码。

我认为有人猜测令牌的机会很小,因为 Guid 是 122 位数字(128 位,版本信息减去 6 位)。(2^122 / 2)因此,黑客平均需要在 24 小时内尝试令牌才能成功。如果我的数学是正确的,那就是3 * 10^31每秒令牌,我确定我的服务器无法处理;)。此外,他们需要猜测的令牌与他们希望为其重置密码的用户没有任何关系。

但是,直接从生成的 Guid 生成令牌是否正确?无论如何,使用 Guid 而不是安全的随机数生成器使攻击可行吗?该方案中是否还有其他问题使其不安全?

我已经看到了这个问题,尽管它与它相关,但它并没有解释生成令牌的最佳实践。

3个回答

您应该为此创建一个加密随机令牌。您的绝对不够随机,并且可以比您提到的 (2^122 / 2) 猜得快得多。密码随机性的重要性已经在这个论坛上讨论过很多次,例如这里

当您提到您正在使用.net 时,请查看 ASP.Identity ,它可以使用 DataProtectorTokenProvider 为您生成令牌如果您不使用 ASP.Identity(或 Owin),您还可以考虑使用RNGCryptoServiceProvider生成安全随机令牌。我不是说你不能自己做,但这很难

编辑:如果您正在谈论 GUID(正如您所引用的那样),您可以阅读此答案

另一方面,要识别在线银行应用程序的用户(或者甚至可能是身份有价值的网站的密码重置功能),GUID 绝对是不够的。

您不仅可以在密码重置链接中包含代码,还可以包含用户标识符。例如:

www.example.com/account/forgot-password?user-id=a45sdf48kf345&token=TOKEN

每当有人访问该Forgot Password链接时,您不仅要验证令牌及其到期日期,还要在重置密码之前验证用户 ID。

在这个方案中,攻击者不仅要猜测令牌,还要猜测为其生成令牌的用户。

为了改进您的方法,您可以

  • 使用强伪随机噪声而不是 GUID
  • 限制某人尝试访问特定用户的重置链接的次数,例如 5 次。您需要添加userId到您发送的请求和数据库中的计数列
  • 在下一次尝试之前强制延迟,例如 1 秒、5 秒、60 秒
  • 如果尝试次数达到某个最大计数,则在一小段时间内阻止 IP 地址。这可能有助于小规模的 DOS 攻击。
  • 对您的请求使用 SSL,这样用户就不会明文发送新密码