密码摘要使用rails4和use_secure_password以明文形式存储

时间:2015-09-15 22:20:01

标签: ruby-on-rails ruby ruby-on-rails-4

我发现密码摘要在我的rails 4应用程序中无法正常工作 - 密码摘要以明文形式存储在数据库中。

user.rb

class User < ActiveRecord::Base
   has_secure_password

   validates :password_digest, length: { minimum: 6 }

end

我的用户数据库迁移文件如下:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :full_name
      t.string :email
      t.string :password_digest

      t.timestamps null: false
    end
  end
end

任何想法我做错了什么?

修改 我在Gemfile中启用了bcrypt(我运行了bundle install)

 gem 'bcrypt', '~> 3.1.7'

当我尝试在rails控制台中测试时,我收到一个无效的哈希错误:

2.2.1 :011 >   user = User.new(full_name: 'abcd', email: 'abc@abc.com', password_digest: 'abcdef')
 => #<User id: nil, full_name: "abcd", email: "abc@abc.com", password_digest: "abcdef", created_at: nil, updated_at: nil>
2.2.1 :012 > User.find_by(full_name: 'david').try(:authenticate, 'abcdef')
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."full_name" = ? LIMIT 1  [["full_name", "david"]]
BCrypt::Errors::InvalidHash: invalid hash
        from /usr/local/rvm/gems/ruby-2.2.1/gems/bcrypt-3.1.10/lib/bcrypt/password.rb:60:in `initialize'
        from /usr/local/rvm/gems/ruby-2.2.1/gems/activemodel-4.2.4/lib/active_model/secure_password.rb:102:in `new'
        from /usr/local/rvm/gems/ruby-2.2.1/gems/activemodel-4.2.4/lib/active_model/secure_password.rb:102:in `authenticate'

2 个答案:

答案 0 :(得分:2)

这很奇怪,一切都应该有效。尝试使用rails控制台中的文档中的一些示例:

user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
user.save                                                       # => false, password required
user.password = 'mUc3m00RsqyRe'
user.save                                                       # => false, confirmation doesn't match
user.password_confirmation = 'mUc3m00RsqyRe'
user.save                                                       # => true
user.authenticate('notright')                                   # => false
user.authenticate('mUc3m00RsqyRe')                              # => user
User.find_by(name: 'david').try(:authenticate, 'notright')      # => false
User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user

如果user.save返回false,您可能会查看user.errors验证消息失败。

编辑:@madcow最终排序正确。现在,您需要将存储在password_digest中的纯文本密码转换为bcrypt哈希值。

注意:您将无法使用此代码恢复纯文本密码!如果您需要纯文本密码,请务必事先备份您的表格。

为单个用户试用此代码,如果一切正常,请将此技术应用于其他用户:

user = User.find_by(name: 'david')
user.password = user.password_confirmation = user.password_digest
user.save!

我们从user.password分配user.password_digest您的纯文本密码。由于has_secure_password重新定义了password=方法,因此您的纯文本密码应该有效地存储回password_digest列,但现在作为哈希。

更新所有用户:

User.find_each do |user| 
  user.password = user.password_confirmation = user.password_digest
  user.save!
end

答案 1 :(得分:2)

您无意中直接在密码摘要字段中保存明文密码,至少在您的控制台示例中是这样。这就是为什么密码存储为明文而不是哈希。

而不是在控制台中输入:

user = User.new(full_name: 'abcd', email: 'abc@abc.com', password_digest: 'abcdef')

输入:

user = User.new(full_name: 'abcd', email: 'abc@abc.com', password: 'abcdef', password_confirmation: 'abcdef')
user.save

然后找到用户:

User.find_by(full_name: 'abcd').try(:authenticate, 'abcdef')

切勿直接设置:password_digest。始终通过:password:password_confirmation字段进行设置。

顺便说一句,你得到的是无效的哈希错误,因为它试图解密你的明文(不是有效的哈希):password_digest值。