2011-12-11 14 views
25

Ho appena aggiunto una funzionalità di registrazione al mio nuovo progetto Grails. Per testarlo, mi sono registrato fornendo un'e-mail e una password. Sto usando l'algoritmo di bcrypt per hashing della password prima di salvarlo nel database.Bcrypt genera hash diversi per lo stesso input?

Tuttavia, quando provo ad accedere con la stessa e-mail e password che ho fornito durante la registrazione, l'accesso non riesce. Ho eseguito il debug dell'applicazione e ho scoperto che l'hash generato per la stessa password è diverso quando provo a confrontarlo con quello già estratto dal database e quindi l'accesso non riesce (Registration.findByEmailAndPassword (params.email, hashPassd) in LoginController.groovy restituisce null).

Ecco la mia classe di 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) 
    } 
} 

Ecco la mia 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") 
     } 
    } 
} 

Ecco un frammento del mio Config.groovy dire graal di utilizzare bcrypt algoritmo di hash password e il numero di giri di calettamento:

grails.plugins.springsecurity.password.algorithm = 'bcrypt' 
grails.plugins.springsecurity.password.bcrypt.logrounds = 16 

risposta

32

Jan è corretto - bcrypt by design non genera lo stesso hash per ogni stringa di input. Ma c'è un modo per verificare che una password hash sia valida e che sia incorporata nel codificatore di password associato. Quindi aggiungere un'iniezione di dipendenza per la passwordEncoder fagiolo nel vostro controller (def passwordEncoder) e cambiare la ricerca per

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") 
} 

Nota che non codificano la password per la chiamata isPasswordValid - pass nel cleartext presentata password.

Inoltre, completamente non correlato, è una cattiva idea archiviare l'utente nella sessione. L'entità di autenticazione è prontamente disponibile e memorizza l'id utente per semplificare il ricaricamento dell'utente secondo necessità (ad esempio User.get(springSecurityService.principal.id). La memorizzazione di oggetti Hibernate potenzialmente grandi e disconnessi funziona alla grande in modalità dev quando sei l'unico utente del server, ma può essere un notevole spreco di memoria e costringe a lavorare attorno agli oggetti che vengono disconnessi (es. dovendo usare merge, ecc.)

+0

Grazie Burt. Ha funzionato e davvero grazie per il suggerimento riguardante la memorizzazione di un utente nella sessione .Sono nuovo ai graal e lo sto usando per sviluppare un social sito di networking. Sarei davvero grato se puoi dare suggerimenti sulle migliori pratiche ecc. o qualsiasi cosa che aiuti .... potrebbe essere un link a un post sul tuo blog (un esercito di solipsisti ..... lo adoro) – adit

13

Un bcrypt hash include salt e, di conseguenza, questo algoritmo restituisce hash diversi per lo stesso input. Permettimi di dimostrarlo in 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 

Di conseguenza, bcrypt non può essere utilizzato per la ricerca di utenti nel modo presentato nel tuo esempio. Invece, dovrebbe essere usato un campo alternativo univoco, ad es. nome utente o indirizzo e-mail.

+0

Se volessi eseguirlo localmente, qual è il nome della gemma? –

+0

Rispondere alla mia stessa domanda il nome della gemma è 'bcrypt-ruby' –

+0

Ottima risposta, apprezzatelo – gdgr

Problemi correlati