Formulario de conexión de usuario

Formulario de conexión

Se trata de realizar un formulario que pida el usuario y la contraseña para entrar en la zona privada de una web.

Internet es un canal inseguro para el envío de contraseñas así que hay que buscar una estrategia para minimizar el posible robo de la contraseña

Utilizaremos Javascript en el cliente, PHP en el servidor y la base de datos MySQL para almacenar las cuentas de usuario

Introducción

En la base de datos no guardaremos la contraseña en claro sino codificada con una función de hash. A partir de la contraseña codificada con el hash no se puede averiguar la contraseña original a no ser que se utilize un ataque por fuerza bruta. Pero en este caso basta con crear una contraseña lo suficientemente compleja. Usaremos la función de hash MD5

Primera solución

La conexión se realizará con los siguientes pasos:

  1. El usuario escribe el usuario y la contraseña en claro en un formulario de una página web.
  2. Utilizando Javascript en el navegador web del cliente codificaremos la contraseña con MD5 y borraremos la contraseña en claro.
  3. El formulario se envía al servidor. En el camino los datos viajan por Internet, y los datos que viajan son el nombre de usuario y la contraseña codificada en MD5.
  4. En el servidor buscaremos si coinciden el usuario y la contraseña recibidos con lo que hay en la base de datos. Sí es así concederemos el paso y sino lo denegaremos.

El problema de esta solución es que si obtenemos la contraseña codificada en MD5 podremos entrar en la zona privada. No conoceremos la contraseña en claro pero tampoco nos hace falta. Hemos de tener siempre presente que cualquiera podrá acceder al código HTML y al Javascript de la página de conexión con sólo ver el código fuente.

Solución final

Lo que haremos es que la contraseña codificada que va del navegador web cliente al servidor sea distinta en cada ocasión. Para ello mezclaremos la codificación de la contraseña con un número aleatorio que generará el servidor. De esta forma aunque algún intruso averiguase la contraseña codificada no le serviría para entrar la próxima vez ya que la codificación cambia en cada sesión gracias al número aleatorio que es siempre distinto. Aquí tenemos un diagrama de todos los pasos que se siguen en este proceso:

Ver a pantalla completa…

Pasos a seguir

  1. Creación de la tabla de usuarios
  2. Código del formulario de entrada

1) Creación de la tabla de usuarios

La tabla de usuarios la crearemos en la base de datos MySQL

Insertamos dos usuarios: "pepe" y "ana" en la tabla "usuarios". Las contraseñas almacenadas ya están codificadas con la función de hash MD5.

CREATE DATABASE pruebas;

USE pruebas;

CREATE TABLE users (
id INT NULL AUTO_INCREMENT,
user VARCHAR(25) NOT NULL,
hashed_password VARCHAR(32) NOT NULL,
PRIMARY KEY(id),
UNIQUE UQ_USER(user)
)

INSERT INTO users(user, hashed_password)
VALUES('pepe', MD5('pepe')), ('ana', MD5('ana'))

Después de ejecutar el anterior código SQL el contenido de la tabla será:

id user hashed_password
1 pepe 926e27eecdbc7a18858b3798ba99bddd
2 ana 276b6c4692e78d4799c12ada515bc3e4

2) Código del formulario de entrada

En el archivo entrada.php tenemos distintos tipos de código:

  • html: Corresponde a la presentación del formulario.
  • css: Estilos de presentación del html.
  • javascript: Código que se ejecuta en el cliente (navegador web) que se encarga de recoger los datos del formulario y enviarlo al servidor
  • php: Código que se ejecuta en el servidor. Tiene dos cometidos:
    • Generar el número aleatorio que enviaremos al cliente
    • Comprobar que el usuario se autentifica correctamente según lo almacenado en la base de datos

Código PHP y Javascript

En negrita se marcan las referencias a los campos del formulario

<?php
// Notepad++: Menú: Formato: 'Codificar en ANSI' y 'Mostrar como UTF-8 (sin BOM)'
session_start();

$user = $_POST['user'];
$ticket = $_POST['ticket'];
$random_number = $_SESSION['random_number'];
$hashed_password = '';
$scrambled_password = '';
$_SESSION['random_number'] = strtolower(md5(rand()));

// CONFIGURACION DE LA BASE DE DATOS
DEFINE(DB_USER, 'root');
DEFINE(DB_PASSWORD, '');
DEFINE(DB_HOST, 'localhost');
DEFINE(DB_DATABASE, 'pruebas');

// OBTENER LA CONTRASEÑA MD5 DE LA BASE DE DATOS
if ($user != '' and $ticket != '') {
$con = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD) or die('no puedo conectar con el servidor de base de datos');
mysql_select_db(DB_DATABASE) or die('no puede seleccionar la base de datos');
$query = "SELECT * FROM users WHERE user='" . addslashes($user) . "'";
$result = mysql_query($query) or die('no puedo ejecuta la consulta sql');
$row = mysql_fetch_assoc($result);
$hashed_password = '';
if ($row) { $hashed_password = $row['hashed_password']; }
mysql_free_result($result);
mysql_close();

$hashed_password = strtolower($hashed_password);
$scrambled_password = md5($hashed_password . $random_number);

if ($scrambled_password == $ticket) {
$_SESSION['connected'] = "El usuario '$user' está conectado";
}
else {
$_SESSION['connected'] = "Desconectado";
}
}
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Entrada</title>

<script type="text/javaScript" src="md5.js"></script>
<script type="text/javaScript">

var random_number = "<?php echo $_SESSION['random_number']; ?>";

function entrar()
{
var frm = document.forms[0];
var user = frm.user.value.toLowerCase();
var password = frm.password.value;

// Comprobar que se haya introducido un usuario y contraseña
if (user == "" || password == "") {
alert ("Falta el usuario o la contraseña");
return false;
}
else {
// Calcular contraseña mezclada con el número aleatorio
var hashed_password = calcMD5(password).toLowerCase();
var ticket = calcMD5 (hashed_password + random_number);

// Datos a enviar
frm.password.value = ""; // Importante: la contraseña no se envía nunca
frm.ticket.value = ticket; // Lo que se envía es el hash mezclado con el número aleatorio

// Enviar el formulario al servidor
return true;
}
}

// Enfoque del teclado
window.onload = function () { document.forms[0].user.focus(); }

</script>

<style type="text/css">
html,body { background:whitesmoke; font-family: verdana, arial, helvetica;}
label { float:left; width:6em; text-align:right; }
input[type='submit'] { font-weight: bold; }
#entrada { background:cornsilk; border:1px solid bisque; width:16em; margin:1em auto; padding:0 1em; }
#variables { background:azure; border:1px solid gainsboro; width:26em; margin:1em auto; padding:0 1em; }

</style>

</head>

<body>

<div id="entrada">
<h1>Entrada</h1>
<form method="post" onSubmit="return entrar();">
<input type="hidden" name="ticket" id="ticket" value="" />
<p>
<label for="user">Usuario: </label>
<input type="text" name="user" id="user" value="<?php echo $_POST['user']; ?>" />
<br />
<label for="password">Contraseña: </label>
<input type="password" name="password" id="password" />
</p>
<p>
<input type="submit" value="Entrar" />
</p>
</form>
<p>Estado: <?php echo $_SESSION['connected']; ?></p>
</div>

<div id="variables">
<h3>Las variables</h3>
<ul>
<li>ticket*: <strong><?php echo $ticket; ?></strong></li>
<li>random_number: <strong><?php echo $random_number; ?></strong></li>
<li>hashed_password: <strong><?php echo $hashed_password; ?></strong></li>
<li>scrambled_password*: <strong><?php echo $scrambled_password; ?></strong></li>
</ul>
<p><small>* = deben ser iguales para que se efectúe la conexión</small></p>
</div>

</body>

</html>

Comentarios

Proinf.net, ©2003-2017 ci 3.1.5 (CC) Esta obra está bajo una licencia de Creative Commons Este software está sujeto a la CC-GNU GPL