Bcrypt генерирует разные хэши для одного и того же ввода?
Я только что добавил функциональность регистрации в свой новый проект grails. Для тестирования я зарегистрировался, предоставив электронное письмо и пароль. Я использую алгоритм bcrypt для хэширования пароля перед сохранением его в базе данных.
однако, когда я пытаюсь войти в систему с тем же электронной почтой и паролем, который я дал при регистрации, логин не удается. Я отладил приложение и обнаружил, что хэш, созданный для одного и того же пароля, отличается, когда я пытаюсь сравнить с уже хэшируется один из базы данных и, следовательно, логин не работает (Регистрация.findByEmailAndPassword (params.email, hashPassd) в LoginController.groovy возвращает null).
вот моя регистрация доменного класса.groovy:
class Registration {
transient springSecurityService
String fullName
String password
String email
static constraints = {
fullName(blank:false)
password(blank:false, password:true)
email(blank:false, email:true, unique:true)
}
def beforeInsert = {
encodePassword()
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
вот мой LoginController.groovy:
class LoginController {
/**
* Dependency injection for the springSecurityService.
*/
def springSecurityService
def index = {
if (springSecurityService.isLoggedIn()) {
render(view: "../homepage")
}
else {
render(view: "../index")
}
}
/**
* Show the login page.
*/
def handleLogin = {
if (springSecurityService.isLoggedIn()) {
render(view: "../homepage")
return
}
def hashPassd = springSecurityService.encodePassword(params.password)
// Find the username
def user = Registration.findByEmailAndPassword(params.email,hashPassd)
if (!user) {
flash.message = "User not found for email: ${params.email}"
render(view: "../index")
return
} else {
session.user = user
render(view: "../homepage")
}
}
}
вот фрагмент из моей конфигурации.groovy говорит grails использовать алгоритм bcrypt для хэширования паролей и количества раундов манипуляции:
grails.plugins.springsecurity.password.algorithm = 'bcrypt'
grails.plugins.springsecurity.password.bcrypt.logrounds = 16
2 ответов
Jan правильно-bcrypt по дизайну не генерирует один и тот же хэш для каждой входной строки. Но есть способ проверить, что хэшированный пароль действителен, и он включен в связанный кодировщик паролей. Поэтому добавьте инъекцию зависимостей для passwordEncoder
bean в вашем контроллере (def passwordEncoder
) и измените поиск на
def handleLogin = {
if (springSecurityService.isLoggedIn()) {
render(view: "../homepage")
return
}
def user = Registration.findByEmail(params.email)
if (user && !passwordEncoder.isPasswordValid(user.password, params.password, null)) {
user = null
}
if (!user) {
flash.message = "User not found for email: ${params.email}"
render(view: "../index")
return
}
session.user = user
render(view: "../homepage")
}
обратите внимание, что вы не кодировать пароль isPasswordValid
call-pass в открытом тексте представлен пароль.
также - полностью несвязанный-это плохая идея, чтобы сохранить пользователя в сеансе. Принципал auth легко доступен и сохраняет идентификатор пользователя, чтобы упростить перезагрузку пользователя по мере необходимости (например,User.get(springSecurityService.principal.id)
. Хранение отключенных потенциально больших объектов Hibernate отлично работает в режиме dev, когда вы единственный пользователь вашего сервера, но может быть значительной тратой памяти и заставляет вас работать вокруг отключаемых объектов (например, использовать merge
, etc.).
хэш BCrypt включает в себя соль и в результате этот алгоритм возвращает разные хэши для одного и того же входа. Позвольте мне продемонстрировать это в Ruby.
> require 'bcrypt'
> p = BCrypt::Password.create "foobar"
=> "a$DopJPvHidYqWVKq.Sdcy5eTF82MvG1btPO.81NUtb/4XjiZa7ctQS"
> r = BCrypt::Password.create "foobar"
=> "a$FTHN0Dechb/IiQuyeEwxaOCSdBss1KcC5fBKDKsj85adOYTLOPQf6"
> p == "foobar"
=> true
> r == "foobar"
=> true
следовательно, BCrypt нельзя использовать для поиска пользователей способом, представленным в вашем примере. Вместо этого следует использовать альтернативное однозначное поле, например имя пользователя или адрес электронной почты.