2012-05-14 19 views
7

Estoy usando Hibernate/Java para persistir una entidad en una base de datos. La entidad tiene un campo de contraseña que es un Cadena. Al registrar un usuario en mi aplicación, calculo la contraseña usando SHA-1 (reconozco que esto es un poco débil). Esto produce un byte [] que luego convierto a cadena usando new String(byte[] arr); Siempre que quiero registrar un usuario en, simplemente recuperar el hash de la contraseña de la base de datos (como cadena) y compararlo con el digesto de la contraseña de entrada al iniciar la sesión utilizando hashedPasswordFromDatabase.equals(SHA1_HASH(inputPassword));¿Cómo mapear una propiedad de byte [] con Hibernate?

Esto funcionó perfectamente en mi sistema de desarrollo (Windows 7, JDK 1.6.0_23/JDK 1.7, MySQL 5.5, Tomcat 6.0.26) pero al desplegarlo en nuestro servidor (ejecutando JDK 1.6 en Linux), el es igual a método nev er evalúa VERDADERO incluso para contraseñas iguales. Rápidamente configuré un nuevo sistema de desarrollo (Ubuntu 12.04, MySQL 5.5, JDK 1.7.0_03, Tomcat 7.0.22) y no funciona allí también.

Conozco los posibles problemas de codificación indicados en la documentación de la API de Java para la clase String y también figuran en varios lugares aquí en SO. Probé un par de codificaciones sugeridas en este foro (por ejemplo, Base64, Latin-1) y terminé con UnsupportedEncodingException. Creo que será mejor que evite la conversión String. Entonces, ¿cómo puedo diseñar mi base de datos de modo que la clase de entidad generada por Hibernate aparezca con byte [] para el campo de contraseña campo en lugar de Cadena?

+1

+1, muy buena pregunta. Como un aparte que no es una respuesta a su pregunta, he tenido mucha suerte al utilizar algunas de las utilidades de Commons Base64 que entran y salen de la base de datos. –

+2

¿Por qué almacenaría una cadena que representa un número en lugar de almacenar el número en sí? – m0skit0

+0

No use una ronda de hash para proteger las contraseñas. Use algo como PBKDF2 o bcrypt con 10s de miles de rondas --- incluso 100k no es irrazonable. Almacenar un 'byte []' de longitud fija directamente debería ser más fácil para más base de datos, pero siempre puedes crear un 'BigInteger' desde una matriz de bytes y almacenar eso como un tipo numérico. – erickson

Respuesta

5

Sí, el problema es muy probable en byte[] a String conversión. Debe saber que SHA produce matrices en bruto byte y no hay garantía de que byte[] arbitrario produzca String válido, independientemente de la codificación. Por lo tanto, su código solo estaba funcionando por accidente.

evitar el problema por completo por:

  • almacenamiento de crudo en byte[] BLOB - la forma más segura y eficaz de almacenamiento. En Hibernate solo use la propiedad byte[] en su POJO.

  • codifica byte[] usando (mira Decode Base64 data in Java) y guárdalo como una cadena.

BTW remember about salting!

+0

Muchas gracias. ¿Quiere decir que BLOB realmente hará que Hibernate genere el campo en la entidad como 'byte []'? –

+0

@ SayoStealth-virusOladeji: Si usa 'byte []', hbm2ddl debe generar BLOB. Y viceversa: si tiene un BLOB en su base de datos, puede asignarlo de manera segura a 'byte []'. –

+0

¡Genial! Actualmente estoy revisando la página Base64 que compartiste; vale la pena leer. –

0

, pero puede cambiar de bytes a una representación hexadecimal de esta manera:

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

¿Cómo afecta esto la fuerza de la contraseña hash? ¿Este enfoque lo debilita? –

+0

@ SayoStealth-virusOladeji No, no lo debilita ni lo fortalece. Esto es una cosa simple que mapea un byte en su valor de cadena "equivalente" representando cada byte por su valor numérico (0 se convierte en "00", 16 se convierte en "10", 255 se convierte en "FF", etc ...). Pasar de uno al otro es bidireccional, pero la verdadera "fortaleza" o "debilidad" está en su digestión de la contraseña. –

+0

¡Genial! Muchas gracias. Creo que emplearé este enfoque ya que no tendré que tocar la base de datos ni ninguna otra cosa cercana :) –

1

En mi caso, el diseño de bases de datos mal empuje que yo use una gota en el caso de CLOB. La solución era Mapa en Hibernar la propiedad con la anotación Lob y poner otra propiedad en Tipo de cadena.

En otro nivel del código, cuando llamo al get o al set, uso la propiedad String y esta, obtengo o configuro el valor de la matriz de bytes.

@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; 
    } 
} 
Cuestiones relacionadas