2012-09-19 21 views
8

Utilizo shiro en la aplicación para la autentificación. Yo uso de contraseñas encriptado con una sal y las guardo en mi base de datos de la siguiente manera:Cómo almacenar y usar una sal de shiro desde la base de datos

private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){ 

    ByteSource salt = randomNumberGenerator.nextBytes(32); 

    byte[] byteTabSalt = salt.getBytes(); 

    String strSalt = byteArrayToHexString(byteTabSalt); 

    String hashedPasswordBase64 = new Sha256Hash(inPassword, salt, 1024).toBase64(); 

    return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt); 
} 

almaceno la sal con una cuerda en mi base de datos. Ahora en mi reino quiero recuperar mis datos de la base de datos, uso un servicio transaccional para esto. Pero mi sal es un fuerte, así que quiero que gire hacia atrás como tipo ByteSource con el método estático:

ByteSource byteSourceSalt = Util.bytes(salt); //where the salt is a String 

Pero cuando creo mi SaltedAuthenticationInfo que no AUTH.

Creo que mi problema es de mi método de conversión:

private String byteArrayToHexString(byte[] bArray){ 

     StringBuffer buffer = new StringBuffer(); 

     for(byte b : bArray) { 
      buffer.append(Integer.toHexString(b)); 
      buffer.append(" "); 
     } 

return buffer.toString().toUpperCase();  
} 

Gracias por su ayuda.

Respuesta

13

Como se mencionó en la excelente respuesta https://stackoverflow.com/a/20206115/603901, DefaultPasswordService de Shiro ya genera sales únicos para cada contraseña.

Sin embargo, no es necesario implementar un PasswordService personalizado para agregar una sal privada (a veces llamada "pimienta") a las sales por usuario. sal privada se puede configurar en shiro.ini:

[main] 
hashService = org.apache.shiro.crypto.hash.DefaultHashService 
hashService.hashIterations = 500000 
hashService.hashAlgorithmName = SHA-256 
hashService.generatePublicSalt = true 
# privateSalt needs to be base64-encoded in shiro.ini but not in the Java code 
hashService.privateSalt = myVERYSECRETBase64EncodedSalt 
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher 

passwordService = org.apache.shiro.authc.credential.DefaultPasswordService 
passwordService.hashService = $hashService 
passwordMatcher.passwordService = $passwordService 

código Java para generar un hash de la contraseña correspondiente:

DefaultHashService hashService = new DefaultHashService(); 
hashService.setHashIterations(HASH_ITERATIONS); // 500000 
hashService.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME); 
hashService.setPrivateSalt(new SimpleByteSource(PRIVATE_SALT)); // Same salt as in shiro.ini, but NOT base64-encoded. 
hashService.setGeneratePublicSalt(true); 

DefaultPasswordService passwordService = new DefaultPasswordService(); 
passwordService.setHashService(hashService); 
String encryptedPassword = passwordService.encryptPassword("PasswordForThisUser"); 

El hash resultante es la siguiente:

$shiro1$SHA-256$500000$An4HRyqMJlZ58utACtyGDQ==$nKbIY9Nd9vC89G4SjdnDfka49mZiesjWgDsO/4Ly4Qs= 

La sal privada no se almacena en la base de datos, lo que hace que sea más difícil descifrar las contraseñas si un adversario obtiene acceso a un volcado de la base de datos.

Este ejemplo se ha creado usando shiro-1.2.2

Gracias a https://github.com/Multifarious/shiro-jdbi-realm/blob/master/src/test/resources/shiro.ini para obtener ayuda con la sintaxis para shiro.ini

+1

cómo puedo obtener la sal pública auto generada por shiro para almacenarla en una columna separada en db – thoitbk

4

¿Ha mirado PasswordMatcher/PasswordService?

Esto ya tiene toda la lógica de codificación/decodificación/comparación incorporada. Para usarlo:

Almacenar contraseña en la base de datos:

PasswordService service = new DefaultPasswordService(); // or use injection or shiro.ini to populate this 

private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){ 

    String hashedPasswordBase64 = service.encryptPassword(inPassword); 

    return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt); 
} 

A continuación, puede utilizar PasswordMatcher como detector en su reino.

realm.setCredentialsMatcher(new PasswordMatcher()); 

o en shiro.ini:

matcher = org.apache.shiro.authc.credential.PasswordMatcher 
realm.credentialsMatcher = $matcher 
+4

Ok, gracias por su respuesta. Voy a intentar esto. Pero no entiendo dónde tengo que usar mi sal ahora y dónde está el enlace entre la contraseña y la sal. – Fred37b

1

de que cambie de tipo para el guardado de mi sal. Ahora estoy usando un byte [] en lugar de una cadena.

ByteSource salt = randomNumberGenerator.nextBytes(32); 

byte[] byteTabSalt = salt.getBytes(); 

Y yo almaceno el byteTabSalt en mi base de datos.

4

La implementación DefaultPasswordService agrega automáticamente un sal aleatorio a cada llamada encryptPassword. Esa sal "pública" se almacenará dentro de la "hashedPasswordBase64" que reciba de "encryptPassword".

Dado que la sal "pública" se genera individualmente para cada contraseña hash, no se puede "simplemente" generar una tabla de arco iris y aplicar fuerza bruta a todas sus contraseñas hash a la vez. Por cada contraseña hash, el atacante tendría que generar una tabla de arcoíris única y propia debido a la sal única "pública". Hasta ahora no es necesario poner una sal adicional en la base de datos.

Para hacer aún más seguras sus contraseñas hash almacenadas, puede agregar una sal "privada" que debe almacenarse en cualquier otro lugar, siempre que no esté en la base de datos. Al usar una sal "privada", podría proteger las contraseñas hash frente a un ataque de tabla-arco iris de fuerza bruta, porque el atacante no conoce la sal "privada" y no puede obtener la sal "privada" de las entradas de la base de datos.

Este es un ejemplo muy básico de cómo crear un PasswordService que utiliza una sal de "privado" proporcionado como una cadena constante y que funciona como CredentialsMatcher:

public class MyPrivateSaltingPasswortService extends DefaultPasswordService 
{ 
    public MyPrivateSaltingPasswortService() 
    { 
     super(); 
     HashService service = getHashService(); 
     if (service instanceof DefaultHashService) 
     { 
     ((DefaultHashService) service).setPrivateSalt(
      new SimpleByteSource("MySuperSecretPrivateSalt")); 
     } 
    } 
} 

, a continuación, puede utilizar su propia aplicación en shiro.ini:

[main] 
saltedService = com.mycompany.MyPrivateSaltingPasswortService 
matcher = org.apache.shiro.authc.credential.PasswordMatcher 
matcher.passwordService = $saltedService 
realm.credentialsMatcher = $matcher 

Este ejemplo se ha creado usando shiro-1.2.2

+0

Podría explicar: "La implementación DefaultPasswordService agrega automáticamente un sal aleatorio a cada llamada encryptPassword. Esa sal" pública "se almacenará dentro de la" hashedPasswordBase64 "que recibe de" encryptPassword "."? No entiendo, ¿esta sal pública se debe guardar en una columna separada (no en una columna de contraseña)? –

+0

Hasta ahora no necesita poner una sal adicional en la base de datos. - ¿Qué quisiste decir aquí? –

+1

Hola, Pasha, el token generado contiene varios bloques de información diferentes. uno de estos bloques es la sal pública, por lo que Shiro puede volver a codificar y probar nuevamente la contraseña ingresada por el usuario. siempre que almacene el token generado "tal cual" no necesita almacenar la sal pública, ni siquiera lo sabe porque Shiro se encarga de eso. Eche un vistazo a la respuesta de Mikael Falkvidd: hay un ejemplo de token generado y también una opción para definir una sal privada. – seafoxx

Cuestiones relacionadas