Estoy desarrollando una aplicación de Android con una base de datos MySQL para almacenar las credenciales de inicio de sesión del usuario. Estoy usando jBCrypt para las contraseñas de hashing antes de almacenarlas en la base de datos. En el registro, la contraseña se incluye en el lado del cliente de la siguiente manera:
String salt = BCrypt.gensalt();
String hash = BCrypt.hashpw("password", salt).split("\$")[3];
salt = salt.split("\$")[3];
hash = hash.substring(salt.length(), hash.length());
En este caso, BCrypt.hashpw()
me dará el hash
$2a$10$rrll.6qqZFLPe8.usJj.je0MayttjWiUuw/x3ubsHCivFsPIKsPgq
Luego elimino los parámetros ( $2a$10$
) y almaceno los primeros 22 caracteres como sal y los últimos 31 como hash en la base de datos:
------------------------------------------------------------------------
| uid | salt | hash |
------------------------------------------------------------------------
| 1 | rrll.6qqZFLPe8.usJj.je | 0MayttjWiUuw/x3ubsHCivFsPIKsPgq |
------------------------------------------------------------------------
Ahora, cuando un cliente desea iniciar sesión, ingresa su nombre de usuario y contraseña y solo se devuelve el salt de la base de datos. El cliente calcula su hash llamando a BCrypt.hashpw()
con su salt:
String salt = "$2a$10$" + returnedSalt;
String hash = BCrypt.hashpw(“password”, salt).split("\$")[3];
hash = hash.substring(salt.length(), hash.length());
dandome:
hash = "0MayttjWiUuw/x3ubsHCivFsPIKsPgq"
que es igual al hash almacenado en la base de datos. El cliente luego envía el nombre de usuario y el hash calculado al servidor. Si coinciden, el usuario inicia sesión.
Sé que puedo simplificar este proceso obteniendo directamente todo el hash de BCrypt y comparándolo con la contraseña dada con
if (BCrypt.checkpw(“password”, bCryptHash))
// match
pero se siente mal al enviar la contraseña completa al usuario para que realice la comprobación.
Entiendo que es preferible hash las contraseñas del lado del servidor, pero ¿hay algún problema con esta solución? ¿Me estoy perdiendo algo?
Diga que tengo una conexión HTTP sin cifrar entre el teléfono y el servidor. ¿Sería esta una solución segura?