Foro de elhacker.net

Programación => PHP => Mensaje iniciado por: danny920825 en 4 Enero 2017, 17:59 pm



Título: [Resuelto]Login solo en PHP
Publicado por: danny920825 en 4 Enero 2017, 17:59 pm
Hola a todos nuevamente. Me gustaría traerles un pequeño login que hice en PHP sin JQuery ni nada de eso. Solo PHP y HTML. Quisiera que me digan qué les parece el código y si hay formas de que usando solo PHP, no salga en el código fuente de la página la contraseña o que me digan cómo darle más seguridad al formulario y esas cosas. Sin dilatarnos más, veamos los 2 archivos:

Login.php
Código
  1. <?php
  2. if (isset($_SESSION['userid']))
  3. {
  4. header("location:index.php");
  5.  
  6. }
  7. else
  8. {
  9.  
  10. ?>
  11. <html>
  12. <head>
  13. <title>Login de Usuario</title>
  14. </head>
  15. <link rel="stylesheet" href="css/login.css" type="text/css" />
  16. <body>
  17. <br /><br /><br />
  18. <center>
  19. <h2>Ingrese sus datos para acceder al sistema</h2>
  20. <form action="logon.php" method="post" name="form">
  21. <table border='0' bgcolor="">
  22. <tr>
  23. <td><b>
  24.  <p align="right">Usuario</p></b></td>
  25. <td align="center"><input type="text" name="user"></td>
  26. </tr>
  27. <tr>
  28. <td><b>
  29. <p align="right">Contrase&ntilde;a</p>
  30. </b></td>
  31. <td align="center"><input type="password" name="pass"></td>
  32. </tr>
  33. <tr align="center">
  34. <td>
  35. </td>
  36. <td>
  37. <input type="submit" value="enviar"><input type="reset" value="limpiar" name="limpiar">
  38. </td>
  39. </tr>
  40. <?php
  41. if (isset($_SESSION['error']))
  42. {
  43. $mensaje=$_SESSION['error'];
  44. echo("<tr align='right'><td colspan='2'>$mensaje</td></tr>");
  45. }
  46.  
  47. ?>
  48. </table>
  49. </form>
  50. </center>
  51. <center><b><a href='guest.php'>Entrar como invitado</a></b></center>
  52.  
  53. <?php
  54. }
  55. ?>
  56. </body>
  57. </html>
  58.  
  59.  
La idea es que si ya tienes un login realizado no te deje acceder a esa página, sino que te redireccione al index.php.

Ahora el logon.php que es quien gestiona los usuarios con la BD
Código
  1. <?php
  2. //recuperacion de variables
  3. session_start();
  4. $usuario=$_REQUEST['user'];
  5. $password=$_REQUEST['pass'];
  6. $mensaje="Usuario o Contrase&ntilde;a incorrectos";
  7.  
  8. //base de datos
  9. $conexion=mysqli_connect("localhost", "usuario", "contraseña") or die (mysqli_error($conexion));
  10. $bd="trabajo";
  11. $tabla="usuarios";
  12. mysqli_select_db($conexion, $bd)or die (mysqli_error($conexion));
  13. //$cifrar=base64_encode($password);
  14.  
  15. //seleccion del usuario
  16. $registro=mysqli_query($conexion, "select * from $tabla where (usuario='$usuario')") or die ("Usuario desconocido");
  17. {
  18. if ($reg=mysqli_fetch_array($registro))
  19. {
  20. if ($password==$reg['password'])
  21. {
  22. $_SESSION['userid']=$_REQUEST['user'];
  23. $_SESSION[nivel]= $reg[nivel];
  24. mysqli_close($conexion);
  25. header("location:index.php");
  26. }
  27. else
  28. {
  29. $_SESSION['error']=$mensaje;
  30. echo ("error");
  31. mysqli_close($conexion);
  32. header("location:login.php");
  33. }
  34. }
  35. else
  36. {
  37. $_SESSION['error']=$mensaje;
  38. echo ("error");
  39. mysqli_close($conexion);
  40. header("location:login.php");
  41. }
  42. }
  43. ?>
  44.  

Y así estamos listos. Yo recupero el nivel porque así puedo establecer permisos a los usuarios dependiendo de su nivel. Y en el login solo necesitamos recuperar las variables de sesion así

Código
  1. session_start();
  2. if (isset($_SESSION['userid']))
  3. {
  4.  
  5. ?>
  6. Aqui ponemos todo el index.php si el usuario se logueó bien. Si no abrimos php de nuevo escribimos
  7. <?php
  8. }
  9. else
  10. {
  11. header("location:login.php");
  12. }
  13. ?>
  14. </body>
  15. </html>
  16.  
  17.  
  18.  


Título: Re: Login solo en PHP
Publicado por: engel lex en 4 Enero 2017, 18:17 pm
el login en lineas generales está bien, aunque debería tener algunas validaciones adicionales...

no uses $_REQUEST, usa ya sea $_POST o el método especifico

las lineas 30 y 38 te causarán errores
según documentación
http://php.net/manual/es/function.header.php

(http://i.imgur.com/TfuTd5s.png)

si usas header, no usas nunca echo antes... y si es para redirect, tampoco es necesario despues porque no se verá (excepto el caso de una api que use no redirect)


la contraseña está almacenada de forma insegura... base64 no es cifrar, es codificar, y las contraseñas deben estar almacenadas en forma de hash+salt ara evitar problemas.... la forma más simple de eso es usar password_hash (http://php.net/manual/es/function.password-hash.php) para guardar y password_verify (http://php.net/manual/es/function.password-verify.php) para comparar



Título: Re: Login solo en PHP
Publicado por: #!drvy en 4 Enero 2017, 18:47 pm
Citar
Código
  1. $cifrar=base64_encode($password);

Eso no es cifrar. Eso es encoding o dicho en español: Codificación. Si lo que quieres es convertir la contraseña en un hash tendrás que usar un algoritmo de un solo camino. Preferiblemente bcrypt o scrypt.

https://es.wikipedia.org/wiki/Codificaci%C3%B3n_de_caracteres
https://es.wikipedia.org/wiki/Funci%C3%B3n_hash
https://en.wikipedia.org/wiki/Bcrypt

Código
  1. $salt = 'hDvTFAsHtrB3oagFNggnUa';
  2. $cifrar = crypt($password, '$2a$12$' . $salt);



Citar
Código
  1. $usuario=$_REQUEST['user'];
  2. $password=$_REQUEST['pass'];
  3. ....
  4.  
  5. $registro=mysqli_query($conexion, "select * from $tabla where (usuario='$usuario')")
  6.  

Regla numero #1 del desarrollador: Nunca te fíes de lo que te manda un usuario.

Ese código es vulnerable a SQLi (inyección sql). Puedes utilizar sentencias preparadas para evitar sqli. Por otro lado, evita usar $REQUEST. Solo quieres obtener datos que se envían por POST (tu formulario HTML). REQUEST incluye GET, POST y COOKIES.. no te interesa, mas bien perjudica.

Código
  1. $usuario=$_POST['user'];
  2. $password=$_POST['pass'];
  3. $salt = 'hDvTFAsHtrB3oagFNggnUa';
  4.  
  5.  
  6. $cifrar = crypt($password, '$2a$12$' . $salt);
  7.  
  8. $query = "select * from {$tabla} where (usuario=?)";
  9.  
  10. $stmt = mysqli_prepare($conexion, $query);
  11. mysqli_stmt_bind_param($stmt, 's', $usuario);
  12.  
  13. ....

http://php.net/manual/es/mysqli.quickstart.prepared-statements.php



Citar
Código
  1. if ($password==$reg['password'])

No uses == para comparar cadenas de texto. Puedes tener problemas porque PHP convierte a los valores a semejanza. Para que me entiendas:

Código
  1. if(0=='hola'){ echo "hola"; } // Imprime hola
  2. if(0==='hola'){ echo "hola"; } // No imprime nada (no cumple)

Usa siempre === para comparar strings. Tampoco veo que estés comparando la contraseña hasheada.. comparas directamente dos cadenas de texto.

Código
  1. if($cifrar===$reg['password'])

Y ya que vamos a utilizar bcrypt, mejor:

Código
  1. if(hash_equals($cifrar, $reg['password']))

http://php.net/manual/es/function.crypt.php
http://php.net/manual/es/function.hash-equals.php



Citar
Código
  1. $_SESSION['userid']=$_REQUEST['user'];

Primera regla. No nos fiemos. El usuario podría suplantar su "user" por el tuyo. Saca el userid siempre de la base de datos, de la entrada que corresponde a su usuario.



Citar
Código
  1. echo ("error");
  2. mysqli_close($conexion);
  3. header("location:login.php");

echo no es una función. No la uses como tal (funciona pero esta mal). Utilizar header() después de imprimir algo suele tirar errores. Recuerda que en protocolo HTTP los headers siempre van antes que el contenido. En algunos navegadores, no pasar la url completa del sitio puede generar errores de redireccionamiento.

Código
  1. mysqli_close($conexion);
  2. header('Location: http://misitio.com/login.php');
  3. echo 'Error';

Saludos


Título: Re: Login solo en PHP
Publicado por: danny920825 en 4 Enero 2017, 19:01 pm
Gracias por su pronta respuesta. Realmente el echo es infuncional, solo que copie el código de una salva anterior porque el original está en casa.
Código
  1.    echo ("error");
  2.    mysqli_close($conexion);
  3.    header("location:login.php");

Ya estoy viendo la documentacion que me dieron sobre el hash y salt y la cifrado en un solo sentido, así como el password verify y password hash. Para la comunicación con la BD no hay forma de encriptarla? que no se vea la contraseña en el código fuente?

y esto no lo entiendo, lo podrían explicar?
Código
  1. $stmt = mysqli_prepare($conexion, $query);
  2. mysqli_stmt_bind_param($stmt, 's', $usuario);
  3.  

Gracias por adelantado


Título: Re: Login solo en PHP
Publicado por: #!drvy en 4 Enero 2017, 19:12 pm
Citar
Para la comunicación con la BD no hay forma de encriptarla? que no se vea la contraseña en el código fuente?

Podrías ofuscarla y parecidos pero generalmente a fin de cuentas, no. Se asume que solo el administrador tiene acceso a dicho código.

Citar
y esto no lo entiendo, lo podrían explicar?

mysqli_prepare, prepara una sentencia para que se le asignen parámetros y posteriormente sea ejecutada. Con las sentencias preparadas, en vez de enviar todos los datos en la query, envías primero la query y luego las variables. De este modo evitas que una variable puede escapar de su entorno y modifique la query.

mysqli_stmt_bind_param, asigna un parámetro a una sentencia. En este caso, lo asignamos a $stmt que es nuestra sentencia. Le decimos que la próxima variable (el ? en la query) tipo string debe contener el valor de la variable $usuario.

En reducidas cuentas, esto:

Código
  1. SELECT * FROM {$tabla} WHERE (usuario=?)

Pasa a ser esto:
Código
  1. SELECT * FROM {$tabla} WHERE (usuario='donpepito')

Pero de forma segura.


mysqli_stmt_execute lo que hace es ejecutar la sentencia y devolver un identificador para su posterior uso. Lo tienes todo bastante explicado en el enlace que te deje:

http://php.net/manual/es/mysqli.quickstart.prepared-statements.php

Saludos


Título: Re: Login solo en PHP
Publicado por: danny920825 en 4 Enero 2017, 19:17 pm
Gracias por la ayuda, no habia visto ese enlace. Ya estoy estudiando. Si tengo otras dudas vuelvo. Es bueno saber que hay personas que responden en tiempo y que están dispuestas a ayudar.