我在尝试使用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进行评估。
答案 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>