繁体   English   中英

实现密码重置功能的问题(阻止用户使用旧密码) - MongoDB & NodeJS

[英]Problem implementing password reset functionality (stopping users from using old passwords) - MongoDB & NodeJS

我正在为 web 应用程序实现身份验证,并希望实现忘记/重置密码功能,并且用户在重置密码时不应输入旧密码。 我的具体问题是这样的:

我有 1 个 mongoose 用户 model 看起来像这样:

const UserSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true,
    unique: true,
  },
  password: {
    type: String,
    required: true,
    select: false,
  },
  passwordChangedAt: {
    type: Date,
    required: false,
    default: null,
  },
  role: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Role',
    required: true,
  },
  ...Base,
});

我还有一个密码重置model:

const PasswordResetSchema = new mongoose.Schema({
  user: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true,
  },
  token: {
    type: String,
    required: true,
  },
  isUsed: {
    type: Boolean,
    required: false,
    default: false,
  },
  expireDate: {
    type: Date,
    required: true,
  },
  oldPassword: {
    type: String,
    required: true,
  },
  newPassword: {
    type: String,
    required: false,
    default: null,
  },
  ...Base,
});

现在,在重置密码时,我想在密码重置表中查找,并检查之前是否已经使用过 oldPassword 或 newPassword,如果使用过,则会向用户显示他们曾经使用过该密码的错误。我使用 bcrypt 到 hash使用盐的密码,这意味着相同的密码在数据库中可以有不同的hash。 所以问题是在查询密码重置集合时,对于以前使用的相同密码,有没有办法在比较哈希和新的明文密码时查询密码以检查密码是否被使用。

  const hashedPassword = await bcrypt.hash(password, bcrypt.genSaltSync());
  // Here the hashedPassword is different, since the salt is different

  const usedSamePassPreviously = await PasswordReset.find({
    _id: { $nin: [passwordReset._id] },
    user: user._id,
    $or: [{ oldPassword: hashedPassword }, { newPassword: hashedPassword }],
    isUsed: true,
  });

我还尝试使用 mongo 中的 $where 子句进行查询,它允许我使用纯 JavaScript function,但我们无法访问 bcrypt.compare ZC1C425268E683854D1AB5074C17A。 我不想在后端加载所有数据,然后查找是否使用了密码,或者对所有密码使用相同的盐,因为这是一个安全问题。 我如何处理这个查询,是否可以在数据库端实现这一点。 提前致谢。

您需要遍历所有禁止密码的哈希值,并在每个密码上使用 bcrypt 的.compare()方法。 通过这种方式,您可以查看用户提供给您的新密码值是否应该作为重复而被拒绝。

在您的客户端代码中执行此操作。

确实,做.compare()需要时间。 这是一个设计特点。 这就是您应该在数据库服务器中执行此操作的原因:数据库是共享资源,您不想在那里执行 CPU 密集型长时间运行操作; 他们将占用为其他数据库客户端代码提供服务所需的 CPU。 在您的 nodejs 代码中执行这些操作。 如果性能确实有问题,请考虑使用工作线程。

并且,考虑信息安全含义:要在您的数据库中执行此操作,您必须将用户提供给您的秘密明文密码发送给它。 你应该避免在任何不是绝对需要的地方发送秘密。 数据库软件庞大而复杂,为网络爬虫提供了很大的攻击面。 因此,向它发送它不需要的秘密会使这些秘密变得更容易受到攻击。 即使您实际上并没有存储秘密也是如此。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM