【问题标题】:password digest being stored in cleartext using rails4 and use_secure_password使用 rails4 和 use_secure_password 以明文形式存储密码摘要
【发布时间】:2015-09-15 22:20:00
【问题描述】:

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

user.rb

class User < ActiveRecord::Base
   has_secure_password

   validates :password_digest, length: { minimum: 6 }

end

我的用户db迁移文件如下:

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'

【问题讨论】:

  • 您的 Gemfile 中是否启用了 bcrypt gem?
  • 是 - gem 'bcrypt', '~> 3.1.7'

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


【解决方案1】:

这很奇怪,一切都应该工作。在您的 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_digest 的纯文本密码分配给user.password。由于has_secure_password 重新定义了password= 方法,您的纯文本密码应该有效地存储回password_digest 列,但现在作为散列。

更新所有用户:

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

【讨论】:

  • 我可以保存用户 - 我可以在数据库中看到他们。密码字段在数据库中是明文
  • 它会抛出错误,因为您的 password_digest 不是有效的 bcrypt 哈希。我有一种感觉,您在某处覆盖了 User#password= 方法。您在问题中显示的 User 模型是否完整?
  • 我没有密码字段,我将其命名为 password_digest
  • 有什么想法吗?该应用仍在数据库中以明文形式保存密码
【解决方案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 值。

【讨论】:

  • 为什么密码一开始就以明文形式保存?另外,我的用户数据库迁移文件中是否需要密码确认?
  • 只使用密码而不是密码摘要并没有给我一个错误
  • 没错。不要直接设置password_digest,你应该不会得到错误。您永远不需要直接读取/设置它。该数据库字段是has_secure_password 的实现细节,应该对我们的开发人员保持封装(隐藏)。 ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-15
  • 2010-11-03
  • 1970-01-01
  • 1970-01-01
  • 2013-07-03
  • 2010-09-07
  • 2011-09-08
相关资源
最近更新 更多