entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

2votos

Login con hash

Buenas estaba intentando empezar a poner hash a las contraseñas estoy usando la funcion PASSWORD_BCRYPT todo va bien pero aun no se como consultar la contraseña el sistema de inicio de sesion revisa si la contraseña introducida es igual a la de la base de datos pero como tiene hash no se como leerla para que permita entrar al sistema

    <?php
    include 'password.php';
        $password = $_POST['password'];
        $hash = password_hash($password, PASSWORD_BCRYPT);
        if (password_verify($password, $hash)) {
          echo "SUCCESS!";
         /* El query valida si el usuario ingresado existe en la base de datos. Se utiliza la función 
         htmlentities para evitar inyecciones SQL. */
         $myusuario = mysql_query("select idusuario from usuarios 
                                     where idusuario =  '" . $_POST["usuario"] . "'",$link);
         $nmyusuario = mysql_num_rows($myusuario);

         //Si existe el usuario, validamos también la contraseña ingresada y el estado del usuario...
        if($nmyusuario != 0){
              $sql = "select idusuario
                   from usuarios
                   where estado = 1
                   and idusuario = '". $_POST['usuario'] ."' 
                   and password = '". password_verify($password, $hash) ."'";
              $myclave = mysql_query($sql,$link);
              $nmyclave = mysql_num_rows($myclave);
              //Si el usuario y clave ingresado son correctos (y el usuario está activo en la BD), creamos la sesión del mismo.
              if($nmyclave != 0){
                   session_start();
                   //Guardamos dos variables de sesión que nos auxiliará para saber si se está o no "logueado" un usuario
                   $_SESSION["autentica"] = "SIP";
                   $_SESSION["usuarioactual"] = mysql_result($myclave,0,0);
                   //Direccionamos a nuestra página principal del sistema.
              }
              else{
                   echo"<script>alert('La contraseña del usuario no es correcta.');
                   window.location.href=\"index.php\"</script>"; 
              }
         }
         else{
              echo"<script>alert('El usuario no existe.');window.location.href=\"index.php\"</script>";
         }
         //Condicional if para utilizar _session y mostrar el nombre de el usuario
         if ($nmyusuario != 0){
               $sql = "select nombre
                    from usuarios
                   where estado = 1
                    and idusuario = '". $_POST['usuario'] ."' 
                    and password = '" . $hash ."'";
              $myclave = mysql_query($sql,$link);
              $nmyclave = mysql_num_rows($myclave);
              if($nmyclave != 0){
                   session_start();
                   $_SESSION["autentica"] = "SIP";
                   $_SESSION["nombre"] = mysql_result($myclave,0,0);
                   header("Location: app.php");
              }

         }
         //Condicional if para utilizar _session y mostrar el nombre de el usuario
         if ($nmyusuario != 0){
               $sql = "select apellidos
                    from usuarios
                   where estado = 1
                    and idusuario = '". $_POST['usuario']."' 
                    and password = '". $hash ."'";
              $myclave = mysql_query($sql,$link);
              $nmyclave = mysql_num_rows($myclave);
              if($nmyclave != 0){
                   session_start();
                   $_SESSION["autentica"] = "SIP";
                   $_SESSION["apellidos"] = mysql_result($myclave,0,0);
                   header("Location: app.php");
              }

         }
       }
         mysql_close($link);
?>

1 Respuesta

5votos

magarzon Puntos30650

Buenas.

Te comento sobre tu código, para que veas cómo se hace y lo que estabas haciendo mal:

Para empezar (líneas 3 y 4) estás creando un hash de la password que te envía el usuario, y luego estás comprobando ese mismo hash. ¡Eso siempre va a ser cierto! Es decir, esa comprobación no tiene sentido, estás comprobando el funcionamiento de la función de php mismo, y ya te aseguro yo que funciona ;)

Después, aunque dices que utilizas htmlentities para "escapar" el código, la query que realizas no tiene htmlentities por ningún lado, pero de todas formas el uso de htmlentities no te evita del todo que te puedan hacer SQL Injection, es mejor que utilices mysqli_real_escape_string. Pero bueno, uses lo que uses, ¡usalo!

Después haces 3 queries que no tienen sentido, por varias razones.

La primera: porque te puedes traer todos los datos de una sola query. ¿Por qué haces una query para obtener el id, otra para obtener el nombre y otra para obtener el apellido, si con una sola puedes obtener todo?

La segunda: en la primera query estás pasando como valor del password el resultado de la función password_verify, que como ya hemos visto, tal y como la estás usando, va a ser siempre true. Es por eso que esta parte nunca te va a dar acceso, porque estás verificando que la password=true, y esto nunca va a suceder tampoco.

La tercera: En la segunda y tercera query sí que utilizas el valor de hash en lugar del valor de password_verify, pero, además de que a esas queries nunca se van a ejecutar porque como hemos visto la primera query nunca va a dar resultado, tampoco te van a dar nunca resultado porque ese hash que has calculado sobre la entrada del usuario nunca (o vamos a dejarlo en casi nunca) va a coincidir con el que se generó cuando el usuario se dio de alta y generaste un hash de la clave que metió en ese momento y guardaste en la base de datos.

¿POR QUÉ? Porque la función password_hash, si no se le pasa opciones, va a utilizar para generar el hash un salt automático.

Si no sabes lo que es el salt, es como la semilla del algoritmo de cifrado. Imagina que el algoritmo fuera tan fácil como una multiplicación S x P, donde S fuera el salt y P la password (una password solo numérica, para este ejemplo). Si la password P es 5, por ejemplo, y el salt automático es 2, el hash sería 10.

Por tanto, cuando generas el hash cuando el usuario se registra y lo guardas en la base de datos, se generará un salt, y a partir de ahí el hash. Pero cuando repites la operación a la hora de hacer login, se genera un salt diferente, y por tanto el hash que genera el algoritmo es diferente, aunque haya partido de la misma cadena (el password en claro). En el ejemplo anterior, sería como si hubieras generado el 2x5=10 en el registro, pero en el login el salt automático es 3, y entonces el hash sería 3x5=15, y claro, 15 no es igual a 10.

¿QUÉ SOLUCIONES HAY? Básicamente puedes hacer dos cosas:

1) En el registro generas el hash y lo guardas en la base de datos. Luego, cuando el usuario haga login, recuperas (con una sola consulta, no con tres), todos los datos que necesitas del usuario para tu web: username, nombre, apellidos,... y el hash. Y utilizas la función password_verify con el password que ha metido el usuario $_POST['password'], y el hash que has recuperado de la base de datos. Como la función password_hash anexa al principio del hash la salt que ha generado automáticamente, sabe cómo verificar si el password que has pasado genera el mismo hash.

2) Hacer lo mismo que en 1, pero más "a mano", que es como se haría si no tienes PHP 5.5 (password_hash solo está disponible a partir de esa versión, habría que utilizar crypt, o algo más seguro): En el registro, además del hash, generas un salt (puedes utilizar la misma función password_hash (si estás con PHP 5.5) para generarlo, de hecho es lo que hace la propia password_hash para generar el salt automático). Ese salt se lo pasas a la función password_hash así: password_hash($password, PASSWORD_BCRYPT, ['salt'=>$salt]). Y en la base de datos, guardas tanto el hash como el salt. Cuando el usuario hace login, lo que tienes que hacer es recuperar de la base de datos los datos del usuario, junto con el hash y el salt que has almacenado en el registro. Con el salt, haces un password_hash de la password que te han pasado, utilizando el salt, y como esta vez SÍ estás usando el mismo salt, el hash generado debe coincidir con el que tenías guardado en la BD, solo tienes que hacer una comprobación $hashGenerado = $hashGuardado.

Pero vamos, que si usas PHP 5.5, utiliza la opción 1.

Espero que te haya quedado claro, si no, ya sabes, repregunta.

Saludos.

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta