使用用户 ID 而不是电子邮件发送密码恢复令牌是否安全?

Is safe to send password recover token by using User Id instead email?

我有一个 Rails + Nuxt 项目,带有帐户恢复流程。

一种情况是用户忘记了他的注册邮箱和密码。 用户可以通过提交他的帐户 ID 来记住他的电子邮件。 Rails 然后用用户的 ID 和电子邮件的混淆版本回复。

此时,用户已经知道他的邮箱,但不知道他的密码。于是他点击了“记住密码”按钮。

默认情况下,Devise(auth lib)期望完整的电子邮件提交(不是混淆)以生成并发送恢复 link 给用户。但是此时只有混淆后的邮箱可用,我不想麻烦用户填写完整的邮箱,因为我已经知道他是谁了(从账户id)。

也就是说,我想知道覆盖下面的 Devise 方法以便使用用户 ID 而不是电子邮件发送恢复令牌是否存在一些安全问题?

# Attempt to find a user by its email. If a record is found, send new
# password instructions to it. If user is not found, returns a new user
# with an email not found error.
# Attributes must contain the user's email
def send_reset_password_instructions(attributes = {})
  recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
  recoverable.send_reset_password_instructions if recoverable.persisted?
  recoverable
end

https://github.com/heartcombo/devise/blob/main/lib/devise/models/recoverable.rb

如果最终您将重置密码发送到与数据库中存在的用户相关的电子邮件地址,我认为提供电子邮件或任何其他用户 ID 在安全性上没有区别

这里存在像 username enumeration 这样的漏洞的中等风险。帐户 ID 往往比电子邮件地址更容易预测,因此随着用户群的增长,有人滥用它来枚举帐户的风险会增加。

您可以通过使用 reCAPTCHA 或要求已知信息的另一个因素,或两者同时使用来减轻一些风险。

指出此功能与传统重置功能之间的区别也很重要。重置功能可以通过对有效和无效电子邮件做出完全相同的响应来防止收集攻击。例如:

If the email you provided is valid, a password reset link has been sent.

这个恢复功能没有那个能力。