[Resuelto]Login solo en PHP

Iniciado por danny920825, 4 Enero 2017, 17:59 PM

0 Miembros y 1 Visitante están viendo este tema.

danny920825

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 (php) [Seleccionar]

<?php 
session_start
();
if (isset(
$_SESSION['userid']))
{
header("location:index.php");

}
else
{

?>

<html>
<head>
<title>Login de Usuario</title>
</head>
<link rel="stylesheet" href="css/login.css" type="text/css" />
<body>
<br /><br /><br />
<center>
<h2>Ingrese sus datos para acceder al sistema</h2>
<form action="logon.php" method="post" name="form">
<table border='0' bgcolor="">
<tr>
<td><b>
 <p align="right">Usuario</p></b></td>
<td align="center"><input type="text" name="user"></td>
</tr>
<tr>
<td><b>
<p align="right">Contrase&ntilde;a</p>
</b></td>
<td align="center"><input type="password" name="pass"></td>
</tr>
<tr align="center">
<td>
</td>
<td>
<input type="submit" value="enviar"><input type="reset" value="limpiar" name="limpiar">
</td>
</tr>
<?php 
if (isset(
$_SESSION['error']))
{
$mensaje=$_SESSION['error'];
echo("<tr align='right'><td colspan='2'>$mensaje</td></tr>");
}

?>

</table>
</form>
</center>
<center><b><a href='guest.php'>Entrar como invitado</a></b></center>

<?php 
}

?>

</body>
</html>


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 (perl) [Seleccionar]

<?php 
//recuperacion de variables
session_start();
$usuario=$_REQUEST['user'];
$password=$_REQUEST['pass'];
$mensaje="Usuario o Contrase&ntilde;a incorrectos";

//base de datos
$conexion=mysqli_connect("localhost""usuario""contraseña") or die (mysqli_error($conexion));
$bd="trabajo";
$tabla="usuarios";
mysqli_select_db($conexion$bd)or die (mysqli_error($conexion));
//$cifrar=base64_encode($password);

//seleccion del usuario
$registro=mysqli_query($conexion"select * from $tabla where (usuario='$usuario')") or die ("Usuario desconocido");
{
if ($reg=mysqli_fetch_array($registro))
{
if ($password==$reg['password'])
{
$_SESSION['userid']=$_REQUEST['user'];
$_SESSION[nivel]= $reg[nivel];
mysqli_close($conexion);
header("location:index.php");
}
else
{
$_SESSION['error']=$mensaje;
echo ("error");
mysqli_close($conexion);
header("location:login.php");
}
}
else
{
$_SESSION['error']=$mensaje;
echo ("error");
mysqli_close($conexion);
header("location:login.php");
}
}
?>



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 (php) [Seleccionar]
session_start();
if (isset($_SESSION['userid']))
{

?>
Aqui ponemos todo el index.php si el usuario se logueó bien. Si no abrimos php de nuevo escribimos
<?php
}
else
{
header("location:login.php");
}
?>

</body>
</html>


"Los que reniegan de Dios es por desesperación de no encontrarlo".
   Miguel de Unamuno

engel lex

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



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 para guardar y password_verify para comparar

El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

#!drvy

#2
Citar
Código (php) [Seleccionar]
$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 (php) [Seleccionar]
$salt = 'hDvTFAsHtrB3oagFNggnUa';
$cifrar = crypt($password, '$2a$12$' . $salt);





Citar
Código (php) [Seleccionar]
$usuario=$_REQUEST['user'];
$password=$_REQUEST['pass'];
....

$registro=mysqli_query($conexion, "select * from $tabla where (usuario='$usuario')")

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 (php) [Seleccionar]
$usuario=$_POST['user'];
$password=$_POST['pass'];
$salt = 'hDvTFAsHtrB3oagFNggnUa';


$cifrar = crypt($password, '$2a$12$' . $salt);

$query = "select * from {$tabla} where (usuario=?)";

$stmt = mysqli_prepare($conexion, $query);
mysqli_stmt_bind_param($stmt, 's', $usuario);
mysqli_stmt_execute($stmt);

....


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




Citar
Código (php) [Seleccionar]
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 (php) [Seleccionar]
if(0=='hola'){ echo "hola"; } // Imprime hola
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 (php) [Seleccionar]
if($cifrar===$reg['password'])

Y ya que vamos a utilizar bcrypt, mejor:

Código (php) [Seleccionar]
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 (php) [Seleccionar]
$_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 (php,1,3) [Seleccionar]
echo ("error");
mysqli_close($conexion);
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 (php) [Seleccionar]
mysqli_close($conexion);
header('Location: http://misitio.com/login.php');
echo 'Error';


Saludos

danny920825

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 (php) [Seleccionar]

    echo ("error");
    mysqli_close($conexion);
    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 (php) [Seleccionar]

$stmt = mysqli_prepare($conexion, $query);
mysqli_stmt_bind_param($stmt, 's', $usuario);
mysqli_stmt_execute($stmt);


Gracias por adelantado
"Los que reniegan de Dios es por desesperación de no encontrarlo".
   Miguel de Unamuno

#!drvy

CitarPara 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.

Citary 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 (sql) [Seleccionar]
select * from {$tabla} where (usuario=?)

Pasa a ser esto:
Código (sql) [Seleccionar]
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

danny920825

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.
"Los que reniegan de Dios es por desesperación de no encontrarlo".
   Miguel de Unamuno