grails - Bcrypt genera hashes diferentes para la misma entrada?
(2)
Jan es correcto: bcrypt por diseño no genera el mismo hash para cada cadena de entrada. Pero hay una manera de verificar que una contraseña hash sea válida y esté incorporada en el codificador de contraseña asociado. Así que agrega una inyección de dependencia para el bean passwordEncoder
en tu controlador ( def passwordEncoder
) y cambia la búsqueda a
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")
}
Tenga en cuenta que no codifica la contraseña para la llamada isPasswordValid
- pase en la contraseña presentada sin cifrado.
Además, sin relación alguna, es una mala idea almacenar al usuario en la sesión. El principal de autenticación está disponible y almacena la identificación del usuario para facilitar la recarga del usuario según sea necesario (por ejemplo, User.get(springSecurityService.principal.id)
. Almacenar objetos de Hibernate potencialmente grandes desconectados funciona muy bien en el modo dev cuando eres el único usuario de su servidor, pero puede ser una pérdida significativa de memoria y lo obliga a trabajar alrededor de los objetos que se desconectan (por ejemplo, tener que usar merge
, etc.).
Acabo de agregar una funcionalidad de registro a mi nuevo proyecto Grails. Para probarlo, me registré dando un correo electrónico y una contraseña. Estoy usando algoritmo bcrypt para hash la contraseña antes de guardarla en la base de datos.
Sin embargo, cuando intento iniciar sesión con el mismo correo electrónico y la misma contraseña que proporcioné durante el registro, el inicio de sesión falla. Depuré la aplicación y descubrí que el hash que se genera para la misma contraseña es diferente cuando trato de compararlo con el hash de la base de datos y, por lo tanto, el inicio de sesión está fallando ( Registration.findByEmailAndPassword (params.email, hashPassd) en LoginController .groovy devuelve nulo ).
Aquí está mi clase de dominio Registration.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)
}
}
Aquí está mi 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")
}
}
}
Aquí hay un fragmento de mi Config.groovy que le dice a Grails que use el algoritmo bcrypt para usar contraseñas hash y el número de rondas de codificación:
grails.plugins.springsecurity.password.algorithm = ''bcrypt''
grails.plugins.springsecurity.password.bcrypt.logrounds = 16
Un hash BCrypt incluye salt y, como resultado, este algoritmo devuelve hashes diferentes para la misma entrada. Permíteme demostrarlo en Ruby.
> require ''bcrypt''
> p = BCrypt::Password.create "foobar"
=> "$2a$10$DopJPvHidYqWVKq.Sdcy5eTF82MvG1btPO.81NUtb/4XjiZa7ctQS"
> r = BCrypt::Password.create "foobar"
=> "$2a$10$FTHN0Dechb/IiQuyeEwxaOCSdBss1KcC5fBKDKsj85adOYTLOPQf6"
> p == "foobar"
=> true
> r == "foobar"
=> true
En consecuencia, BCrypt no se puede utilizar para buscar usuarios de la manera que se muestra en su ejemplo. En su lugar, debería usarse un campo alternativo no ambiguo, por ejemplo, el nombre del usuario o la dirección de correo electrónico.