使用Knock更新时需要密码

时间:2017-10-30 21:31:22

标签: ruby-on-rails ruby bcrypt

我在尝试使用Knock更新用户记录时要求用户使用当前密码。我认为我可以通过与创建password_digest相同的过程运行他们提交的密码,但每当我比较创建的哈希时,它们就不同了。在散列用户输入时我是否遗漏了某些内容?

这是我的更新方法

def update

  @user = current_user

  # hash current password
  @current_password = params[:current_password]
  cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
  @hashed_password = BCrypt::Password.create(@current_password, cost: cost)


  # return if no current password is given
  if @current_password != nil

    # compare and continue if they match
    if @hashed_password === current_user.password_digest

      # try to update record
      if @user.update_attributes(user_params)
        render json: @user
      else
        render json: @user.errors.full_messages
      end

    # otherwise return password error
    else
      render json: { message: "Your current password is incorrect" }
    end

  else
    render json: { message: "You must provide your current password" }
  end
end

修改:用户在用户模型中保存has_secure_password,如果我理解正确,则会在ActiveModel中触发this call。我使用byebug来停止执行并在赋值后比较变量,它们实际上是不同的。

编辑2:如果将来有人遇到此问题,并希望使用类似的策略,则需要将attr_accessor :current_password添加到您的用户模型中,以便它可以让您通过current_password param进行评估。

2 个答案:

答案 0 :(得分:1)

即使使用相同的输入,重复运行Bcrypt也不会产生相同的输出。相反,对于任何给定的组合,存在大量可能的输出,这使得暴力攻击成本更高。

使用BCrypt::Password#is_password?

检查输入的密码是否正确
BCrypt::Password.new(password_digest).is_password?(unencrypted_password)

由于您使用的是ActiveModel :: SecurePassword,因此可以使用@user.authenticate(password)检查密码。

def update
  @user = current_user
  unless @user.authenticate(params[:current_password])
    @user.errors.add(:current_password, "is incorrect")
  end 
  if @user.update(user_params)
    render json: @user
  else
    render json: @user.errors.full_messages, status: :unproccessable_entity
  end
end

答案 1 :(得分:0)

我认为你不能比较Bcrypt密码。 Bcrypt是一种散列算法,它会在unique salt使用的每个创建上生成hash_secret密钥。这使得哈希每次都不同。例如

irb(main):010:0> instance = BCrypt::Password.create('secret')
=> "$2a$10$FT8YdmzJIkOceKhZ/DwXluYNGm.lZj0Jfrx2nQqzxxM1IX767gNmG"
irb(main):011:0> instance_two = BCrypt::Password.create('secret')
=> "$2a$10$ECA8HoTSuxAvAbFbbg6jQ.g4uIcZqYbNCckfGIzLePfSTx2OM0zJS"
irb(main):012:0> instance == instance_two
=> false
irb(main):013:0>