Inicio | Falsificación de formularios Web

Falsificación de formularios web

Domingo, 22 de Mayo de 2011 17:31

Recientemente un cliente me planteo si podría configurar su servicio de correo en su Blackberry a través del protocolo POP3 en vez del habitual IMAP. Aunque la motivación de mi cliente, para tal planteamiento era mas bien fruto de una cierta ignorancia, que de una necesidad fundada, me puse manos a la obra para ver si esto era posible.

A modo de introducción indicar al lector, que los ajustes relativos al correo de los dispositivos Blackberry se hacen a través de la web de nuestro proveedor, y no a través de propio dispositivo como en la mayoría de los casos. Esto es debido a que Blackberry dispone de su propio protocolo de transferencia de datos entre servidores y dispositivos.

Tras acceder al panel de configuración de cuentas de correo del proveedor de servicios, como era de esperar no encuentro posibilidad alguna de escoger el protocolo que quiero usar para el acceso a mis servidores de correo. Sin embargo si veo una caja de texto en modo solo lectura con el valor 143 (el puerto IMAP), de la misma forma, con un vistazo rápido al código fuente veo un campo hidden con el valor “imap”. Por tanto si hay un 143 ¿porque no podría haber un 110? y si hay un imap ¿porque no un pop3?

Falsificación de Formularios WEBBueno pues esto, sólo hay una forma de averiguarlo, y es falsificando los datos del formulario que estamos viendo. Y cómo se hace esto: pues por suerte o desgracia existen un buen número de complementos para exploradores que hacen este tipo de tareas. Yo he usado el conocido Groundspeed para Firefox. dicha herramienta permite analizar y alterar el contenido de campos ocultos y solo lectura de un formulario que hayamos cargado.

Tras un par de intentos en adivinar cual era el valor de cierta variable, tengo mi cuenta de correo configurada como POP3, pese a ser un proceso no permitido por mi proveedor.

¿Porque podemos hacer esto? bueno, es fácil: En cierto momento mi proveedor de servicios si nos permitía elegir el protocolo con el que queríamos acceder a nuestro servidor de correo, pero obviamente, permitir trabajar con POP3 va a demandar mucho más trafico que IMAP donde el contenido total de mensaje se transfiere a demanda del usuario. Por tanto en vez de eliminar esta posibilidad de los servidores, simplemente “caparon” los controles que permitían hacer esto en el lado del cliente, pero manteniendo la lógica inicial.

Este pequeño ejercicio nos lleva al tema central de este artículo, que es la preocupación por la posibilidad de que el usuario de nuestros formularios pueda falsificar su contenido.

Confiar y abusar de los controles hidden o propiedades "read only" y "disabeled" de nuestros formularios para contener variables es una puerta abierta no a las típicas inyecciones SQL, que supongo que estas alturas es un tema más que controlado, sino que a meras falsificaciones de nuestros datos y por tanto, en cierta manera alterar el comportamiento esperado de nuestra aplicación.

De forma similar este es el mismo principio de los ataques CSRF o Cross Site Request Forgery, donde es posible cruzar envíos de datos por POST o GET entre distintos sitios web. Ya que no se hace una validación previa de donde o cual es el estado de los datos que se están recibiendo.

¿Cómo evitamos la falsificación de datos en formularios? Bueno, pues tenemos dos opciones: o usar variables de sesión para almacenar datos que de otra forma guardaríamos en controles tipo hidden, o utilizar Tokens para verificar que los datos que enviamos son los que esperamos.

¿Cómo usamos los Tokens en formularios? Los Tokens para formularios son simples sumas hash tipo md5 de la variables enviadas a nuestros formularios. Si por ejemplo hemos enviado a nuestro formulario dos variables para almacenar en controles hidden, hacemos unas suma md5 con ellas y luego al recibir los datos del formulario volvemos ha crear un md5 con nuestros campos hidden y lo comparamos con el que hemos creado previamente. Si ambas sumas hash coinciden es que los datos recibidos son los esperados.

Enviamos:
   <?php
$mivariable1 = "b";
$mivariable2 = "a";
?>
<form action="test.php" method="post">
<input name="var1" type="hidden" value="<?php echo $mivariable1 ?>" />
<input name="var2" type="hidden" value="<?php echo $mivariable2 ?>" />
<input name="token" type="hidden" value="<?php echo md5( $mivariable2.$mivariable1) ?>" />
<input name="enviar" type="submit" value="enviar" />
</form>
Recibimos:
 <?php
if ( $_POST['token'] != md5( $_POST['var2'].$_POST['var1'] ) ){
die('token no valido!');
}else{
echo "correcto";
}?>

Realmente este es un ejemplo muy simple y en cierta manera tampoco seria muy difícil que alguien dedujese nuestro token. Para hacerlo todo un poco mas interesante, podemos aderezar nuestro token con variables que identifiquen inequivocamente la procedencia de nuestros datos tales como $_SERVER['HTTP_HOST'] o $_SERVER['HTTP_USER_AGENT']. También podemos incluir alguna clave privada o variables como el día, la hora, etc,... En definitiva se trata de evitar que entre los datos que nosotros enviamos a un formulario, y los que este nos envía a nosotros no exista manipulación alguna o cuando menos dispongamos de un método para evaluar posibles falsificaciones de nuestro formulario:

Enviamos:
<?php
$mivariable1 = "b";
$mivariable2 = "a";
$claveprivada = "QwErT"
?>
<form action="test.php" method="post">
<input name="var1" type="hidden" value="<?php echo $mivariable1 ?>" />
<input name="var2" type="hidden" value="<?php echo $mivariable2 ?>" />
<input name="token" type="hidden" value="
<?php echo md5( $mivariable2.$mivariable1.$_SERVER['HTTP_HOST'].
$_SERVER['HTTP_USER_AGENT'].$claveprivada ) ?>" />
<input name="enviar" type="submit" value="enviar" />
</form>
Recibimos:
   <?php
$claveprivada = "QwErT"
if ( $_POST['token'] != md5( $_POST['var2'].$_POST['var1'].$_SERVER['HTTP_HOST'].
$_SERVER['HTTP_USER_AGENT'].$claveprivada ) ){
die('token no valido!');
}else{
echo "correcto";
}
?>

Podemos optar también por el uso de variables de sesión para comparar el token enviado por POST y el enviado por SESSION:

Enviamos

 <?php
session_start();
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
$_SESSION['token_nacimiento'] = time();
?>
<form action="test.php" method="post">
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<input name="var1" type="hidden" value="" />
<input name="enviar" type="submit" value="enviar" />
</form>
Recibimos
<?php
if ($_POST['token'] != $_SESSION['token']){
die('token no valido!');
}else{
echo "correcto";
}
?>
Se puede complicar un poco mas interponiendo una fecha de caducidad al token:
<?php 
$token_nacimiento = time() - $_SESSION['token_nacimiento'];
if ($token_nacimiento <= 200) { //han pasado menos de 3 minutos
echo "Ok!";
}
?>

El uso de tokens, es una metodología realmente recomendable en cualquier proceso donde exista un intercambio de datos susceptibles de ser alterados por el usuario. Su uso es también bastante aconsejable cuando trabajemos con AJAX y peticiones asíncronas:

$.post("mipagina.php", { id: "<?php echo $id ?>",cod: $('#codigo').val() , 
token: "<?php echo md5( $id.$claveprivada ) ) ?>" });
x-rite Professional LED Lighting, DSLR Support and Accessories for Photo and Video BabelColor asociacion española de imagen cientifica y forense