Muchas veces las aplicaciones web no tienen acceso por ssl (https) y suelen tener un formulario de ‘login’ de usuario y contraseña.
Esto quiere decir que información sensible como la contraseña se transmite en texto claro y que sea relativamente fácil que terceros pueden tener acceso a ella. Por ejemplo esnifando el tráfico si el usuario se conecta con una wifi abierta.
Lo que presento a continuación es una manera sencilla de securizar la contraseña utilizando el algoritmo hash sha-1. Por simplicidad este ejemplo lo he hecho en PHP, pero no tiene complicación hacerlo en Java. He utilizado también la librería de javaScript PHP.js que no conocía pero ‘me ha gustado su lógica‘ 🙂
Bueno este es el problema y esta es la solución que propongo. Al lío…
¿Qué es una función hash?. Es una función criptográfica de un sólo sentido. A grandes rasgos es:
Del valor obtengo el hash => Del hash NO puedo obtener el valor.
Además me asegura que si el valor cambia en un carácter o en un bit, el hash obtenido es totalmente diferente.
Tengo que decir que el algoritmo sha1 es matemáticamente reventable con ataques de fuerza bruta del rango 263 operaciones. Una barbaridad que hace que para el propósito que nos ocupa el uso del sha-1 sea más que suficiente.
Esta es la idea. Desde el navegador se genera con javascript el hash del resultado de concatenar la contraseña y una parte aleatoria (que se guardada en sesión). Esta es la cadena que viaja y no la contraseña. Cada vez será diferente, porque se ha generado con una parte aleatoria, y será inteligible, no se sabrá con que cadenas se ha creado al ser un hash. Para comprobar el acceso, en el servidor se realiza el mismo calculo y se comparan las cadenas.
Se ve mejor en un ejemplo, lo tienes disponible en:
https://github.com/logicaalternativa/ejemplosPHP/tree/master/loginsha1
Son dos ficheros. El index.php, que tiene el formulario de acceso y el javaScript del cáculo del hash, envía los datos a resultado.php. Este obtiene a partir del usuario la contraseña, vuelve a calcular el hash y compara las cadenas.
Index.php
Lo primero que se hace es en PHP crear la cadena aleatoria y almacenarla en sesión:
PHP |copy code |?
1 // Se calcula la cadena aleatoria
2 $tokenSesion = rand(1,9) * 1000000 + rand(0,10) * rand(0, 10000) ;3 // Se guarda en sesión
4 $_SESSION['tokenSesion'] = $tokenSesion;
Código 01
La línea 2 es una manera de calcular un número aleatorio. Se consigue un valor entre 1000000 y 9999999. Puedes utilizar tu propio método.
En la línea 3 se guarda el valor generado en sesión que luego se usará en resultado.php donde se recogen los datos del formulario de acceso.
El formulario de acceso además de los campos de usuario y contraseña tiene el campo oculto ‘token‘.
HTML |copy code |?
1 <form name="formularioAcceso" method="post" action="resultado.php" onSubmit="return acceder()">
2 <input name="token" type="hidden" value="">
3 ...4 <input name="usu" type="text" id="usu" value=""> </td>5 ...6 <input name="contra" type="password" id="contra"></td>
Código 02
El quit de la cuestión está en la función javaScript acceder(). Está función se llama desde el evento onSubmit del formulario
Javascript |copy code |?
1 function acceder(){2 var contra = document.forms.formularioAcceso.contra.value + '';3 var token= sha1('<?=$tokenSesion?>' + contra);4 document.forms.formularioAcceso.contra.value = '';5 document.forms.formularioAcceso.c.value = token;6 return true;7 }
Código 03
Explico un poco la función. Se obtiene el valor de la contraseña tecleada por el usuario en la línea 2. En la 3 se concatena el valor aleatorio generado en PHP con la contraseña del usuario, y se hace el sha-1. Después se ‘borra’ la contraseña para que no viaje, colocando la cadena vacía en el campo del ‘contra’ formulario. Finalmente se coloca el token calculado en el campo oculto ‘token’ que tiene el formulario.
Para hacer el cálculo de la función sha-1, he utilizado la librería JavaScript PHP.js.
Esta gente ha implementado en JavaScript las funciones disponibles en PHP. Sencillo y genial, lógica alternativa. Así que si tienes un problema en JavaScript y piensas ‘… esto en PHP lo haría en dos «pataas«…’, no lo dudes esta es tu librería. Su repositorio tiene la misma estructura que en el índice de funciones del manual de PHP así que son fáciles de encontrar.
He incluido las librerías en el head
HTML |copy code |?
1 ...2 <script language="JavaScript" src="https://raw.github.com/kvz/phpjs/master/functions/xml/utf8_encode.js"></script>
3 <script language="JavaScript" src="https://raw.github.com/kvz/phpjs/master/functions/strings/sha1.js"></script>
4 ....
Código 04
Para que sea más didáctico he incluido directamente las librerías de su repositorio. Pero lo lógico es bajarlas a tu proyecto, los ficheros js están disponibles en el ejemplo. Es necesario incluir la función utf8_encode.js porque la de sha1 depende de ella (vienen indicado en la cabecera de la función)
resultado.php
Este es el PHP que se encarga de recibir el usuario y el token sha-1.
PHP |copy code |?
1 $usuario = $_REQUEST[ 'usu'];2 $token = $_REQUEST['token'];3 4 $tokenSesion = $_SESSION['tokenSesion'];5 $_SESSION['tokenSesion'] = null;
Código 05
Obtiene el usuario y el token del formulario enviado. En la línea 4 se obtiene de sesión la cadena aleatoria con la que se ha generado el hash. Por seguridad en la línea 5 se borra de sesión.
A partir del usuario que se ha enviado en el formulario se obtiene la contraseña
PHP |copy code |?
1 // Usuarios
2 $claseAcceso = new AccesoDummy();3 // Se obtiene la contraseña del usuario
4 $contra = $claseAcceso->dameContrasena( $usuario );5 // Se calcula el token
6 $tokenCalculado = sha1( $tokenSesion.$contra );
Código 06
La clase ‘AccesoDummy‘ es una implementación muy tonta que se ha hecho para este ejemplo. Aquí cada uno lo hará a su manera. Lo importante es obtener la contraseña del usuario por medio de su identificador.
En la línea 6 lo que se ha hecho es obtener otra vez el token de acceso pero esta vez en el servidor. Ahora sólo queda comparar las dos cadenas para ver si está todo correcto y darle acceso al usuario.
PHP |copy code |?
1 if ( isset( $contra ) &&2 $token == $tokenCalculado ){3 $texto = 'Acceso correcto';4 ...
5 } else {6 $texto = 'Acceso incorrecto';7 ...
8 }
Código 07
… Y el resultado
Puedes probar una demo en:
http.http://localhost:8080/etc/ejemplos/php/loginsha1
Si lo probáis varias veces veréis que, siendo el acceso correcto con el mismo usuario, el token siempre cambia.
Espero que os sirva de ayuda…