这是来自github页面:
require 'bcrypt'
class User < ActiveRecord::Base
# users.password_hash in the database is a :string
include BCrypt
def password
@password ||= Password.new(password_hash)
end
def password=(new_password)
@password = Password.create(new_password)
self.password_hash = @password
end
end
要访问密码方法,您需要将其作为创建方法中的属性调用:
@user.password = user_params[:password]
@user.save
好......好?但现在储存的盐在哪里?我根本就没有得到它,这又如何远程安全?
要检索哈希密码,您需要以下方法:
def password
@password ||= Password.new(password_hash)
end
并将其称为属性:
if @user.password == params[:password]
give_token
else
false
end
所以看来一切都在没有盐的情况下......它是如何做到的?
这意味着我现在只需要在我的数据库中使用一列来处理密码,对吧?password
或password_hash
而不是password_salt | password_hash
?
那么为什么github页面会这样说:
但即使这有弱点 - 攻击者可以只运行列表 可能的密码通过相同的算法,将结果存储在一个 大数据库,然后通过哈希查找密码:
PrecomputedPassword.find_by_hash(<unique gibberish>).password #=> "secret1" Salts
然后这就是我真正得到的:
The solution to this is to add a small chunk of random data -- called a salt -- to the password before it's hashed:
如果bcrypt自动处理所有内容,他们为什么要解释所有这些?
hash(salt + p) #=> <really unique gibberish> The salt is then stored along with the hash in the database, and used to check potentially valid passwords: <really unique gibberish> =? hash(salt + just_entered_password) bcrypt-ruby automatically handles the storage and generation of these salts for you.
有人可以解释bcrypt如何存储和生成这些盐吗?为什么它说它为我处理这一切然后继续告诉我如何生成盐?我是否需要在我的模型中运行类似的内容:self.password_hash = hash(salt + p)
请问有人请举例说明如何使用新版本的bcrypt生成salt和hash,以及如何进行身份验证?
答案 0 :(得分:12)
好的,has_secure_password
非常酷。您不再需要担心盐和哈希值,盐和哈希值将作为一个属性(password_digest
)存储在数据库中。
它以这样的方式保存,即bcrypt知道password_digest
字符串的哪一部分是盐,以及什么是哈希。
如果您从头开始设置身份验证,则需要执行以下操作:
1)添加bcrypt rails gem:
gem bcrypt-rails
2)将has_secure_password
方法添加到负责处理用户记录的模型中:
class User < ActiveRecord::Base
has_secure_password
end
3)确保您的用户表格中包含password_digest
列:
class CreateUser < ActiveRecord::Migration
create_table :users do |t|
t.username
t.password_digest
end
end
4)创建一个new
方法,为要使用的表单创建一个新的空用户实例:
class UsersController < ApplicationController
def new
@user = User.new
end
end
5)在new
视图中,创建一个表单,用于填充params散列':password
和:username
条目:
<% form_for( @user ) do |f| %>
<%= f.text_field :username %>
<%= f.password_field :password %>
<% end %>
6)返回我们的控制器,使用强参数允许用户名和密码。强大的params背后的全部原因是为了防止一些厚颜无耻的chappy使用开发工具创建自己的html表单字段(例如与id相关的字段)并用恶意数据填充数据库:
class UsersController < ApplicationController
def new
@user = User.new
end
private
def user_params
params.require(:user).permit(:username, :password)
end
end
7)让我们创建一个create方法,该方法将使用这些允许的条目来创建一个新用户,由表单填充:
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(user_params)
@user.save
redirect_to root_path
end
private
def user_params
params.require(:user).permit(:username, :password)
end
end
根据您的需要设置路线,就是这样!用户记录的password_digest
列将自动填充一个字符串,该字符串包含附加密码哈希值的salt。十分优雅。
您需要记住的所有内容:password
- &gt; password_digest
。
为了授权用户并注销用户,使用create方法和destroy方法创建会话控制器:
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to admin_root_path, :notice => "Welcome back, #{user.username}"
else
flash.now.alert = "Invalid email or password"
redirect_to root_path
end
end
def destroy
reset_session
flash[:info] = "Signed out successfully!"
redirect_to root_path
end
希望这有助于某人!
答案 1 :(得分:3)
bcrypt为你准备了一切。您的密码摘要包含几种类型的信息,bcrypt算法类型,成本,盐和校验和。
例如:
my_password = BCrypt::Password.create("my password")
#=> "$2a$10$.kyRS8M3OICtvjBpdDd1seUtlvPKO5CmYz1VM49JL7cJWZDaoYWT."
第一部分:$2a$
是算法的变体,请参阅:Where 2x prefix are used in BCrypt?
第二部分10
是成本参数,您可以通过提供哈希{cost: 12}
作为create
的第二个参数来增加它以减慢进程(对数值)。 / p>
现在,如果您致电my_password.salt
,则会获得"$2a$10$.kyRS8M3OICtvjBpdDd1se"
,其中标识了用作创建校验和的关键部分。
最后,您的校验和为"UtlvPKO5CmYz1VM49JL7cJWZDaoYWT."
。这就是为什么你第二次调用create
时字符串不同,因为将使用另一个盐。
但正如我之前提到的,你不需要做任何额外的事情,因为所有这些都是为你照顾的。