http://proinf.net/permalink/formulario_de_conexion_de_usuario
Fecha: 07-07-04, Autor: Francisco, Categoría: Programación, PHP
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
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
La conexión se realizará con los siguientes pasos:
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.
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:
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 |
En el archivo entrada.php tenemos distintos tipos de código:
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>