Geek & Roll - Blog Archive » Cómo no programar una encuesta Web

Cómo no programar una encuesta Web

Cesar May 22nd, 2011 programacion, tips 3 comentarios

Frecuentemente me encuentro con sitios que deciden atraer más visitantes, creando concursos en donde la gente vota por su participante favorito. No hay nada de malo con eso, sólo que son fácilmente abusadas si no se tiene cuidado al programarlos. Al final podemos tener un ganador que no fue la elección popular, sino el más hábil con los bits.

Supongamos que hay una encuesta para votar por la flor más bella del ejido, y tenemos a las siguientes candidatas:
La Flor Mas Bella del Ejido

De izquierda a derecha las numeramos como Flor 1, 2, 3 ,4, 5 y 6.

El programador del sitio se siente muy confiado, ya que guarda una cookie en el navegador para identificar de manera única a los usuarios y evitar que voten repetido. Empieza la votación y por alguna razón la flor #3 va en la última posición, pero esta flor tiene amigos que le saben a eso de las computadoras y les pide algo de ayuda. Lo que hacen los amigos de la flor #3 es lo siguiente (en PHP):

function xrun($email,$name){

//set POST variables
$url = ‘http://www.laflormasbelladelejido.com.mx/votar.php’;
$fields = array(
‘Nombre’=>$name,
‘Email’=>$email,
‘Voto7′=>’VOTO POR LA FLOR #3′
);

$fields_string =”";

//url-ify the data for the POST
foreach($fields as $key=>$value) { $fields_string .= $key.’=’.$value.’&'; }
rtrim($fields_string,’&');

//open connection
$ch = curl_init();

//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);

//execute post
$result = curl_exec($ch);

//close connection
curl_close($ch);

}

Lo que hace el script anterior es enviar un HTTP POST a la URL de votación, previa preparación de las variables que espera la forma. Esto es muy fácil saberlo utilizando Firebug por ejemplo, o la consola para desarrolladores de Chrome. Para enviar el POST, están utilizando curl que es la neta del planeta cuando se trata de transferir datos por medio de HTTP, en este caso los datos del voto.

Pero ejecutar el script manualmente para aumentar el número de votos por la flor #3 es muy tedioso, así que los emprendedores amigos de esta pobre flor decidieron llevarlo un paso más alla:

$nombres = file_get_contents(”nombres.txt”);
$correos = file_get_contents(”correos.txt”);
$nom = split(”\n”,$nombres);
$ema = split(”\n”,$correos);
$r = count($nom);

for($x=0;$x<$r;$x++){

if($ema[$x] && $nom[$x]){
xrun( $ema[$x], $nom[$x]);
}

}

Ahora basado en un archivo de nombres y correos, se van a enviar tantos votos como nombres existan en el archivo. Este pedazo de código se puede mejorar muchísimo, por ejemplo sólo enviar tantos votos como pares nombre – correo existan, en vez de basarse en el número de nombres. Otra posibilidad es enviar votos en un ciclo pero restringido en tiempo, es decir simular que ha pasado cierto tiempo entre voto y voto, para que no sea tan obvio que es un programa y no gente real la que está votando.

Y ya con eso la flor más bella del ejido es la #3, como podemos verla en la imagen tan contentota.

¿Y la cookie? Obviamente se la pasa por el arco del triunfo. El problema es que el programador supuso que los votos siempre vendrían del navegador, es decir confió de la entrada del usuario. ¿Y cual es la primera regla de la seguridad programación Web?

  1. Desconfía en la entrada del usuario.

Lo repetiremos de nuevo solo para asegurarnos de que quedó claro:

  1. Desconfía en la entrada del usuario.

Así es, desconfía de la entrada del usuario. Desconfía como desconfías del que te quiere vender un tiempo compartido, o del informe de gobierno.

¿Qué podemos hacer para evitarlo?
Lo más obvio es guardar la IP, pero eso deja por fuera a muchísimas personas que se conectan usando NAT. Me explico: en una casa puede que existan 3 personas que comparten una conexión a Internet. Estas tres personas quieren votar por la flor mas bella del ejido, pero la persona 1 ya se les adelantó y su IP fue guardado en el servidor del sitio por lo que al querer votar la persona 2 ya no puede, le aparece un mensaje que su voto ya fue registrado. La decisión de qué hacer dependerá de que tan flexible y seguro necesitamos que sea la encuesta.

Si se esta votando por la flor mas bella del ejido, probablemente sea suficiente con guardar la IP por 30 minutos o más y validar contra eso. Si se está votando por el presidente de un país, probablemente sea necesario un poco más de seguridad.

3 Comentarios

Pablo Aguilar

May 22nd, 2011

Así me tocó una encuesta que hizo frontera.info (del periódico Frontera, acá en Tijuana) el año pasado (fue una sóla encuesta la que me interesó, no sé si su sistema siga igual de malo). Ni siquiera ocupabas programar propiamente. Como la página ya usa jQuery, bastaba con algo del estilo:

javascript:for( var i = 1; i < 10000; ++i ) $.post( … );

en la barra de direcciones… y en un par de minutos cambiabas las tendencias.

Cesar

May 23rd, 2011

Ahí todavía esta más crítico, te esta permitiendo inyectar código JavaScript desde la URL.

Axel

May 24th, 2011

Excelente post César :)

Haz un comentario:

Es necesario que dejes tu nombre y correo electrónico (no se publicarán).

Si dejas un comentario anónimo, con insultos o ajeno al tema, iremos hasta tu casa y le diremos a tu mamá la cantidad de porno que hay en tu computadora. Si, lo sabemos.