Prevenir ataques en los formularios

Saneamiento de Inputs: Qué es y cómo implementarlo

El saneamiento de inputs es una manera de validar formularios que excluye de los mismos cualquier carácter que podamos considerar peligroso para la web y/o la base de datos.

A fin de cuentas, cualquier formulario de una web es un potencial vector de ataque que un cibercriminal puede aprovechar para comprometer el sitio, bien forzando el cierre de ese input acompañado de una petición a la base de datos (un SQL injection), bien de cara a ejecutar javascript o diversos scripts maliciosos en futuros clientes (ataques cross-site scripting).

Existen muchas maneras de validar un formulario.

  • Las nativas de los campos de un formulario: Las propias definiciones de inputs en HTML5 ofrecen validaciones que pueden ser interesantes para separar el grano (los usuarios) de la paja (ataques y/o spam). También, por cierto, tendríamos maneras de hacer esto mismo mediante javascript, PHP (if(empty($_POST[“nombre”]…)) o incluso CSS (input:required:valide….).
 <input type="email"> //pedirá al usuario una cadena de caracteres que tiene que tener sí o sí el formato loquesea@loquesea.loquesea
 <input type="password"> //todo lo que el usuario escriba en este input se mostrará por pantalla mediante asteriscos (*).
 <input type="text" required> //este campo es obligatorio rellenarlo para poder enviar el formulario...
 <input type="text" pattern="^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$" name="email" required/> //esta sería una manera de exigir que el contenido que el usuario incluya en el input tenga formato email, es decir, loquesea@loquesea.loquesea
  • Escape de caracteres: Sin embargo, de forma nativa no tenemos manera de controlar que, por ejemplo, cuando el usuario vaya a escribir contenido en un input, no incluya caracteres que el sistema reconoce como funcionales (como por ejemplo las dobles comillas o la comilla simple, que quizás sirva para cerrar el propio input), y esto le permita acceder a partes de la web privadas o a contenido de la base de datos. En estos casos se recurre a funciones que permiten sanear el contenido de un input o bien antes de enviarlo o bien justo antes de ejecutarlo en el servidor. Algunos ejemplos serían:
 $input1 = "coche"; //el usuario escribió "coche"
 $input2 = "'or '1'=1"; //el usuario escribió"'or '1'=1"
 select pass from usuarios where usuario=$input1; //devolvería en SQL la contraseña del usuario "coche", si es que existe
 select pass from usuarios where usuario=$input2; //devolvería en SQL la contraseña de cada usuario, ya que 1=1 siempre se cumple
 $peticion = mysqli_real_escape_string($link, $input2); //escapamos el contenido de $input2
 select pass from usuarios where usuario=$input2; //devolvería en SQL la contraseña del usuario "'or '1'=1", que seguramente no exista

Y lo mismo puede hacerse con htmlspecialchars (EN) o escapeshellarg (EN). Incluso mediante los propios filtros de PHP (EN).

En mi caso hago uso del plugin NinjaFirewall para WordPress (EN) que, entre otras cosas, permite de forma automática sanear cualquier petición GET y/o POST que se haga en la página.

Honeypots de formularios: Qué son y cómo implementarlos

Aledaño al problema de los XSS y los SQL injection está la proliferación de bots cuyo único cometido es buscar formularios en webs para publicar enlaces hacia páginas fraudulentas (viagra, malvertising y demás compañía). Y puede llegar a ser un verdadero problema, ya que además de gastar recursos del servidor (son peticiones automatizadas que ocupan ancho de banda), pueden llenar la web de contenido inapropiado y causar verdaderos dolores de muelas a los administradores del sitio.

Afortunadamente, hecha la ley hecha la trampa, y basta entender cómo se desarrollan este tipo de bots y qué es lo que buscan en un formulario para encontrar maneras de engañarlos y hacerles creer que o bien no existe tal formulario, o bien han publicado con éxito lo que querían publicar.

A estas técnicas se las llama honeypots, que en este caso están dirigidas al mundo de los formularios, pero que en la práctica competen a cualquier herramienta cuyo cometido sea engañar a los cibercriminales (la creación por ejemplo de ordenadores supuestamente vulnerables en una red corporativa para localizar ataques antes de que afecten al resto de la organización sería otro aplicativo de los honeypots, solo que enfocado a la seguridad de redes).

Y de nuevo, tenemos mil y un maneras de aplicarlos:

  • Captchas y listas negras: aunque no sean honeypots al uso, lo cierto es que la obligatoriedad de completar un captcha o el llevar en cuenta una lista negra de IPs con actividades curiosas (es normal que un bot intente realizar varias peticiones al mismo tiempo ahí donde un usuario normal claramente no puede) permite evitar la mayoría de spam en formularios web. En el primer caso, a cambio de molestar al usuario (que debe completar un dichoso captcha), y en el segundo, generalmente haciendo uso de servicios de terceros que son los encargados, en base a todas las páginas donde están instalados, de mantener actualizada la lista. En WordPress a mi me gusta especialmente Anti-spam (EN), que (ojo) solo funciona con los formularios de contacto, pero que elimina prácticamente todo el ruido que podría salpicarnos.
  • Honeypots de cliente: La idea pasaría por incluir inputs ocultos al usuario que, de ser completados, no enviasen al servidor la petición. Eso se consigue creando un input de tipo hidden (o bien un input cuyo CSS diga que no debe ser mostrado por pantalla) y cuya petición de envío esté condicionada a que ese input siga vacío. Cosa que ocurrirá con todos los usuarios que lo completen, y que no se cumplirá en el caso de los bots, que necesitan cumplimentar todos los campos para evitar dejarse alguno que sea obligatorio.
 <form action="submit.php" onsubmit="return validateMyForm();" method="post">
    <input type="email" name="email"> //el input verdadero
    <input type="text" id="input-totalmente-falso" style="display: none"> //el input falso que no se mostrará por pantalla
    <input type="submit" value="Submit">
 </form>

 type="text/javascript"> //creamos la función validateMyForm
    function validateMyForm() {
        if(!document.getElementById("input-totalmente-falso").value) {
            return true;
        } //si no existe nada de contenido en el input falso, entonces se envía
        else {
            return false;
       } //si existe, entonces es que es un bot quien intenta completarlo, por lo que no hacemos nada
   }
 
  • Honeypots de servidor: Tienen la ventaja de funcionar aún cuando JavaScript no está habilitado (puede que el bot esté operando en algún entorno más controlado), y la parte mala es que, como todo de cara al servidor, cada petición consume proceso. El procedimiento, no obstante, es semejante al anterior, creando un input falso, pero la validación la hacemos una vez llega la petición al servidor (si el input está vacío, se realiza exitosamente; si no, no). Esto puede hacerse directamente en el SQL o en el PHP.
 <?php
    if(!$input-totalmente-falso){
       mail("pepito@email.com","Nuevo contacto en la web",$cuerpo-del-email);
    }
 ?>

En otros casos lo que creamos son inputs ocultos con un código específico, de manera que si al llegar al servidor ese string ha cambiado, podemos estar seguros de que estamos ante una petición fail.

 <input type="hidden" id="input-de-control" value="0324655847"/>

 <?php
    if($input-de-control!="0324655847"){}
    else{
       mail("pepito@email.com","Nuevo contacto en la web",$cuerpo-del-email);
    }
 ?>

Existen, como decía, múltiples estrategias para controlar el spam que llega a nuestros servidores. Y como todo, hay que buscar el punto medio en el que lo reduzcamos a la mínima expresión sin molestar en demasía al usuario.

Fuente: PabloYglesias

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s