CategoriasDesarrollo web

Evitar spam en formularios PHP

Los formularios de los sitios web que se procesan y se envian a una dirección de correo electrónico pueden ser aprovechados por los «spammers» para hacer envios masivos de «spam» utilizando los servidores de correo y la IP de la maquina en la que se aloja el dominio. En este manual vamos a ver como podemos hacer que nuestros formularios sean un poco más seguros, evitando los ataques del tipo «email injection» a los que muchos formularios son sensibles.

1. En que consiste el «email injection»

Un ataque a un formulario del tipo «email injection» consiste en que el «spammer» aprovecha un formulario de un sitio web para «inyectar» cabeceras de email con direcciones y contenidos diferentes a los establecida en el formulario. Un «spammer» puede, a través de la inyección de cabeceras cambiar tanto el mensaje enviado, como los destinatarios, utilizando nuestro servidor de correo y nuestra maquina y nuestro dominio como emisor del mensaje, con lo que seremos nosotros los que estaremos haciendo «SPAM», y el rastro hasta el «spammer» se pierde.

Aquí tenemos un correo de ejemplo:

To:direccion@destinataria.com
Subject:Motivo del mensaje
From:direccion@emisora.com
Este seria el cuerpo del mensaje.

Dicho esto, la técnica utilizada por el spammer es incluir y/o alterar las cabeceras del mensaje por las suyas propias, antes de que se produzcan 2 saltos de línea, y por tanto, comienze el cuerpo del mensaje. Si el spammer consigue alterar o introducir sus cabeceras, los destinatarios y el cuerpo del mensaje se pueden alterar. Asi por ejemplo, si tenemos el siguiente correo:

To:direccion@destinataria.com
Subject:Motivo del mensaje
From:direccion@emisora.com
To:nuevadireccion@destinataria.com
Cc:otradireccion@spameada.com
Subject:Nuevo subject del mensaje spameado
Texto introducido por el spammer.

Este seria el cuerpo del mensaje.

Observamos que después del «From:» original, el «spammer» ha añadido un nuevo «To:» y otras direcciones de correo con la etiqueta «Cc:». También ha introducido un nuevo texto en el cuerpo del mensaje. El hecho de que haya 2 cabeceras «To:», o 2 «Subject:», no supone ningún problema. En la mayoría de los casos, si una cabecera se define 2 veces, la última es la que se tiene en cuenta.

Un correo básico se compone normalmente de 2 partes: las cabeceras, y un cuerpo del mensaje. Sin embargo, utilizando cabeceras especificas a tal fin, un correo pude tener varios «bodys» o cuerpos de mensaje alternativos. Por simplificar analizamos aquí la estructura de un correo básico.

2. Como puede el spammer inyectar cabeceras en la función mail() de PHP

La función que habitualmente se utiliza en PHP para enviar a una dirección de correo electrónico los datos de un formulario será mail(). La sintáxis de esta función es la siguiente:

  • mail (To, Subject, Mensaje, Headers, Parametros_Adicionales);

El siguiente es un script de ejemplo básico de un formulario que se enviará a una dirección de correo:

  • $to=»webmaster@website.com»;//direccion destinataria «hardcoded»
    if (!isset($_POST[«send»])){
    // si no vienen datos-> mostrar el form
    ?>To: webmaster@website.com
    From:
    Subject :
    Message :

    }else{
    // si vienen datos POST.. procesamos y enviamos los datos del form
    $from=$_POST[’sender’];
    // send mail :
    if (mail($to,$_POST[’subject’],$_POST[’message’],»From: $from\n»)){
    // si se ha enviado correctamente mostramos un mensaje de OK
    echo «Su mensaje se ha enviado correctamente a $to.»;
    }else{
    // Se ha producido un error
    echo «Su mensaje no se ha podido enviar»;
    }
    }
    ?>

En el ejemplo anterior, mostramos un formulario de contacto donde el usuario puede incluir el From, el Subject del Mensaje y el Mensaje. El destinatario «To:» esta «hardcoded» y en principio un usuario no tiene la opción de alterarlo. Sin embargo, esto no nos garantiza nada tal y como hemos visto anteriormente. Un usuario spammer, aprovecharía el campo «From:» para introducir sus propias cabeceras. Solo tiene que añadir un salto de línea al campo del formulario e insertar otras cabeceras. El caracter hexadecimal «%0A» es el equivalente a un salto de línea. Por tanto, si el spammer introduce en el campo «From:» el siguiente contenido:

  • direccionFrom@ficticia.com%0ATo:nuevadireccion@destinataria.com%0ACc:otradireccion@spameada.com%0ASubject:Nuevo subject del mensaje spameado%0A%0ATexto introducido por el spammer en el cuerpo de texto.

Cuando se procese el formulario, las “headers” maliciosas llegarán a la función mail() y gracias a los saltos de línea introducidos en el campo From. Los últimos 2 saltos de línea marcan el comienzo del “body” y a partir de ahí, todo lo demas formará parte del cuerpo del mensaje. En nuestro ejemplo, el spammer no necesita hacer esto último, ya que tiene un campo en el que puede introducir su propio mensaje, pero esta técnica muestra como se puede alterar hasta el cuerpo del mensaje una vez que podemos inyectar nuestras propias cabeceras. El mensaje de correo que devolverá la función mail() será el siguiente:

To:direccion@destinataria.com
Subject:Motivo del mensaje
From:direccion@emisora.com
To:nuevadireccion@destinataria.com
Cc:otradireccion@spameada.com
Subject:Nuevo subject del mensaje spameado
Texto introducido por el spammer en el cuerpo de texto.
Este seria el cuerpo del mensaje.

Que como vimos anteriormente, produce un envio a direcciones diferentes de las previstas, y con otro Subject y Body. Logicamente, el spammer puede introducir tantas direcciones separadas por comas como quiera, con lo que en un simple envio pueden salir cientos de correos SPAM desde nuestro formulario.

En formularios más restrictivos, en los que el cuerpo del mensaje esta «hardcoded» y no se coge desde un campo del formulario, el spammer puede añadir una cabecera del tipo: «Content-Type: multipart/mixed; boundary=»SeparadorDePartes», que permitiría crear un mensaje multi-partes. En un mensaje del tipo «multi-partes», se establece una cadena como «separador» que marcará donde comienza y termina cada parte. Asi, «–SeparadorDePartes», marca el comienzo de una nueva parte del mensaje, que terminará cuando se encuentre nuevamente otro «–SeparadorDePartes» que indique el comienzo de otra parte. Finalmente, «–SeparadorDePartes–» con dos guiones al final, marcaría el final del cuerpo del mensaje.

Utilizando esta cabecera y otras similares, un spammer puede ocultar el cuerpo del mensaje originalmente establecido, dejandolo fuera del separador que marca el fin del body. También podría utilizar esta técnica para añadir ficheros adjuntos, ya que cada una de las partes puede tener su propio «Content-Type», y por tanto podemos hacer que una de las partes sea una imagen o un fichero binario, como se puede ver en esta ejemplo de «email injection» avanzado.
Soluciones

Después de habernos extendido en la explicación del problema, con el fin de que quede claro como se produce, podemos sentir un poco de pánico, aunque en realidad la solución o soluciones (hay varias) son bien sencillas.
Detectar los saltos de línea con expresiones regulares

La más abordable inicialmente es proteger nuestro script para que no le lleguen cabeceras indeseadas. Hemos de tener especial cuidado en todos aquellos campos de un formulario cuyo destino sea el parametro «headers» de la función mail(). En nuestro ejemplo básico el «From:». En lugar de pasarlo directamente, tendremos que hacer una comprobación sobre estos campos y asegurarnos que no vienen saltos de línea, en cuyo caso podemos estar sufriendo una «email injection» y podemos detener el script:

$from = $_POST[«sender»];
$from = urldecode($from);
if (eregi(«\r»,$from) || eregi(«\n»,$from)){
die(«Posible email injection»);
}
?>

También es recomendable utilizar librerias como la Zend_Mail para enviar correos. Esta libreria realiza varias comprobaciones de seguridad antes de enviar el correo, de forma que el usuario no tiene que preocuparse por estos aspectos. Existen otras librerias para el envio de correos que también toman este tipo de precauciones. En cualquier caso, no es menos cierto que existen muchos más scripts hechos personalmente con usuarios poco o nada experimentados y que son el objetivo de los spammers. Para ellos va este Post, a ver si entre todos les ponemos las cosas un poco más dificiles a los spammers. Cuidado con los formularios del tipo «Send to a friend»

Es algo obvio pero como observo que todavía es una practica extendida veo aconsejable recordar lo siguiente. Las medidas de seguridad mencionadas en este manual le protegen o tratan de hacerlo del uso pernicioso que algunos spammers pueden hacer de un formulario previsto con otra funcionalidad.

Sin embargo, poco o nada se puede hacer con algunos formularios del tipo «send to a friend» o «enviar a un amigo» que no han observado la más mínima medida de seguridad. Me refiero a esos formularios que permiten a un usuario anónimo rellenar un formulario en el que todo se puede establecer: El «To:», el «From:», el «Subject:» y el «Body:». Estos formularios pueden ser utilizados como proxies de correo por cualquiera, «spammer» o no. Cualquiera puede enviar un correo a la dirección que quiera, con el subject que quiera, el cuerpo del mensaje que quiera, y simular la dirección desde que lo enviará que quiera, y sin necesidad de utilizar ninguna técnica ni hack para inyectar cabeceras.

En fin, se que es una obviedad, pero había que comentarlo porque hay muchos formularios así. No utilize NUNCA este tipo de formularios sin tomar precauciones obvias de seguridad. Aseguese al menos de que el «From:» no puede ser establecido por el usuario, enviando los correos desde una dirección «fija». Limite las posibilidades de introducir un «Subject:» o un «Body:» personalizado y siga las reglas de filtrado explicadas en este post para evitar ataques «email injection».

Para seguir leyendo :

* https://www.securephpwiki.com/index.php
* https://blogs.pathf.com/highperf/2006/05/php_spam_inject.html

Un comentario en “Evitar spam en formularios PHP”

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *