2012-05-14 4 views
7

Sto usando Hibernate/Java per mantenere un'entità in un database. L'entità ha un campo password che è una stringa . Quando si registra un utente nella mia applicazione, ho cancellato la password usando SHA-1 (riconosco che questo è un po 'debole). Questo produce un byte [] che ho poi convertire in String utilizzando new String(byte[] arr); Ogni volta che voglio per accedere un utente in, ho semplicemente recuperare l'hash della password dal database (come String) e confrontarla con il digest della password di ingresso al momento del login utilizzando hashedPasswordFromDatabase.equals(SHA1_HASH(inputPassword));Come mappare una proprietà byte [] con Hibernate?

Questo ha funzionato perfettamente sul mio sistema di sviluppo (Windows 7, JDK 1.6.0_23/JDK 1.7, MySQL 5.5, Tomcat 6.0.26), ma su di distribuirlo sul nostro server (eseguendo JDK 1.6 su Linux), il è uguale a metodo nev er valuta VERO anche per password uguali. Ho rapidamente installato un nuovo sistema di sviluppo (Ubuntu 12.04, MySQL 5.5, JDK 1.7.0_03, Tomcat 7.0.22) e non funziona anche lì.

Sono a conoscenza dei possibili problemi di codifica indicati nella documentazione dell'API Java per la classe String e anche indicato in diversi punti qui su SO. Ho provato un paio di codifiche suggerite su questo forum (ad esempio Base64, Latin-1) e ho finito con UnsupportedEncodingException. Penso che starò meglio evitando la conversione String. Quindi, come faccio a progettare il mio database in modo tale che la classe di entità generata da Hibernate restituisca byte [] per il campo password invece di String?

+1

+1, ottima domanda. Per inciso, che non è una risposta alla tua domanda, ho avuto molta fortuna ad usare alcune delle utility di Base64 di Commons che entravano e uscivano dal database. –

+2

Perché dovresti memorizzare una stringa che rappresenta un numero invece di memorizzare il numero stesso? – m0skit0

+0

Non utilizzare un round di hashing per proteggere le password. Usa qualcosa come PBKDF2 o bcrypt con decine di migliaia di round --- anche 100k non è irragionevole. Memorizzare direttamente un 'byte []' a lunghezza fissa dovrebbe essere facile per più database, ma è sempre possibile creare un 'BigInteger' da un array di byte e memorizzarlo come un tipo numerico. – erickson

risposta

5

Sì, il problema è più probabile nella conversione da byte[] a String. È necessario sapere che SHA produce una matrice di byte non elaborata e non vi è alcuna garanzia che l'arbitrario byte[] produca un valore valido String, indipendentemente dalla codifica. Quindi il tuo codice funzionava solo per per caso.

evitare il problema del tutto da:

  • memorizzazione grezzo byte[] nel BLOB - il modo più sicuro ed efficace di storage. In Hibernate usa la proprietà byte[] sul POJO.

  • codificare byte[] utilizzando (verificare Decode Base64 data in Java) e memorizzarlo come stringa.

BTW remember about salting!

+0

Grazie mille. Vuoi dire che BLOB renderà effettivamente Hibernate generare il campo nell'entità come 'byte []'? –

+0

@ SayoStealth-virusOladeji: se usi 'byte []', hbm2ddl dovrebbe generare BLOB. E viceversa - se hai un BLOB nel tuo database, puoi tranquillamente mapparlo a 'byte []'. –

+0

Ottimo! Sto attualmente esaminando la pagina Base64 che hai condiviso; vale la pena leggerlo. –

0

È possibile convertire il byte per una rappresentazione esadecimale come questo:

public String encryptPassword(String passwordInClear) { 
      // Salt all you want here. 
      MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); 
    byte[] digest = sha256.digest(passwordInClear.getBytes()); 
    return digestToString(digest); 
} 

private String digestToString(byte[] digest) { 
    StringBuilder hashString = new StringBuilder(); 
    for (int i = 0; i < digest.length; i++) { 
     String hex = Integer.toHexString(digest[i]); 
     if (hex.length() == 1) { 
      hashString.append('0'); 
      hashString.append(hex.charAt(hex.length() - 1)); 
     } else { 
      hashString.append(hex.substring(hex.length() - 2)); 
     } 
    } 
    return hashString.toString(); 
} 
+0

In che modo ciò influenza la forza della password con hash? Questo approccio lo indebolisce? –

+0

@ SayoStealth-virusOladeji No, non lo indebolisce o lo rafforza. Questa è una cosa semplice che mappa un byte sul suo valore di stringa "equivalente" rappresentando ogni byte per il suo valore numerico (0 diventa "00", 16 diventa "10", 255 diventa "FF", ecc ...). Passare dall'uno all'altro è bidirezionale, ma la vera "forza" o "debolezza" è nella digestione della password. –

+0

Ottimo! Molte grazie. Penso che utilizzerò questo approccio poiché non dovrò toccare il database e qualsiasi altra cosa vicina ad esso :) –

1

Nel mio caso, la progettazione di database cattivo spingere me di utilizzare un Blob in caso di Clob. La soluzione era Map in ibernare la proprietà con l'annotazione Lob e inserire un'altra proprietà in String.

In un altro livello del codice, quando richiamo get o set, uso la proprietà String e questo, ottiene o imposta il valore dell'array di byte.

@Entity 
@Table(name = "CMUN_TAGS") 
@SequenceGenerator(name = "idSeqTag", sequenceName = "SEQ_CMUN_TAGS") 
public class CmunTagsDO implements java.io.Serializable { 
    private BigDecimal lngIdTag; 
    private byte[] blobValTag; 
    private String strValTag; 

    @Id 
    @Column(name = "LNG_ID_TAG", unique = true, nullable = false, precision = 20, scale = 0) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idSeqTag") 
    public BigDecimal getLngIdTag() { 
    return this.lngIdTag; 
    } 

    public void setLngIdTag(BigDecimal lngIdTag) { 
    this.lngIdTag = lngIdTag; 
    } 

    @Column(name = "BLOB_VAL_TAG", nullable = false) 
    @Lob 
    public byte[] getBlobValTag() { 
    return this.blobValTag; 
    } 

    public void setBlobValTag(byte[] blobValTag) { 
    this.blobValorTag = blobValorTag; 
    } 

    @Transient 
    public String getStrValTag() { 
    strValTag = new String(getBlobValTag()); 
    return strValTag; 
    } 

    public void setStrValTag(String strValTag) { 
    setBlobValTag(strValTag.getBytes()); 
    this.strValTag = strValTag; 
    } 
}