Validación de entradas, saneamiento y prevención de ataques de inyección

Descubre cómo la validación y el saneamiento de entradas protegen tus formularios de ataques de inyección y mantienen seguros los datos.

Borrador

Cuando un atacante va a por un formulario, no lo rellena como una persona normal. Envía código pensado para entrar en tus sistemas o robar datos. Puede enviar JavaScript para que se ejecute en el navegador de tus visitantes, comandos SQL para romper tu base de datos o contenido malicioso para causar daños. La validación y el saneamiento de entradas son las defensas que frenan estos ataques.

Qué vas a aprender: qué son la validación y el saneamiento de entradas, en qué se diferencian, cómo funcionan los ataques de inyección, qué protecciones sirven para cada tipo de dato y cómo aplicarlas en tus formularios.

¿Qué es la validación de entradas?

La validación de entradas consiste en comprobar que los datos enviados a tu formulario tienen el formato que esperas y cumplen tus requisitos. Es la primera línea de defensa contra las entradas maliciosas.

La validación responde a preguntas como estas: si esto es un correo electrónico o texto al azar, si es un número o una palabra, si este campo está vacío cuando no debería, y si el visitante ha escrito algo con sentido para este campo o algo sospechoso.

Ejemplos de lo que comprueba la validación:

  • Un campo de correo debe contener una arroba y un dominio
  • Un campo de teléfono debe contener solo dígitos y guiones
  • Un campo numérico no debe contener letras
  • Un campo obligatorio no debe estar vacío
  • Un campo de contraseña debe cumplir una longitud mínima

La validación ocurre en dos sitios. En el dispositivo del visitante se llama validación en el cliente. En tu servidor se llama validación en el servidor. La validación en el cliente avisa al visitante al momento si se equivoca. La validación en el servidor es la que realmente protege frente a ataques, porque un atacante puede saltarse las comprobaciones del cliente.

¿Qué es el saneamiento de entradas?

El saneamiento consiste en eliminar o neutralizar todo lo peligroso de lo que escribe el usuario antes de guardarlo o procesarlo. Aunque los datos pasen la validación, aún pueden contener código o caracteres pensados para hacer daño.

Ejemplos de lo que hace el saneamiento:

  • Elimina etiquetas HTML como `<script>` y `<img>` de los campos de texto
  • Elimina caracteres especiales de SQL que podrían usarse para entrar en las bases de datos
  • Escapa los caracteres especiales para que se traten como texto y no como código
  • Limita la longitud de la entrada para evitar ataques de desbordamiento de búfer

La validación y el saneamiento se complementan, pero cumplen funciones distintas. La validación comprueba que los datos tienen el formato correcto. El saneamiento elimina todo lo peligroso aunque el formato sea técnicamente correcto.

Cómo funcionan los ataques de inyección

Inyección SQL

Un ataque de inyección SQL ocurre cuando un atacante escribe código SQL en un campo del formulario. Si el código de tu formulario no sanea esa entrada, el código SQL se ejecuta en tu base de datos.

Ejemplo: un formulario de acceso pide un correo electrónico. En lugar de su correo, el atacante envía:

' OR '1'='1

Si tu formulario no lo sanea, tu código podría ejecutar una consulta SQL como esta:

SELECT * FROM users WHERE email = '' OR '1'='1'

La parte `OR '1'='1'` hace que la condición sea siempre verdadera, así que la consulta devuelve a todos los usuarios y no solo al de ese correo. El atacante ya se ha saltado el sistema de acceso.

Cross-Site Scripting (XSS)

Un ataque XSS ocurre cuando un atacante envía código JavaScript en un campo del formulario. Si el formulario no sanea ese código y lo guarda, el JavaScript se ejecuta en el navegador de cualquiera que vea esos datos más adelante.

Ejemplo: un formulario de comentarios acepta los comentarios de los usuarios. Un atacante envía:

<script>alert('hacked')</script>

Si no se sanea y se guarda en la base de datos, cuando alguien abra la sección de comentarios se ejecutará el JavaScript y mostrará una alerta. Una versión más peligrosa podría robar cookies, redirigir a los visitantes a una página de phishing o extraer datos del formulario.

Inyección de comandos

Si los datos de tu formulario se usan en comandos del sistema (algo que ocurre en algunos sistemas de backend), un atacante puede inyectar comandos del sistema operativo.

Ejemplo: un campo del formulario se usa en un comando como este:

ffmpeg -i $filename output.mp4

Si `$filename` no se sanea y un atacante envía `;rm -rf /`, el comando pasa a ser:

ffmpeg -i ;rm -rf / output.mp4

El comando `rm -rf /` se ejecuta y borra archivos del sistema. Por eso los comandos del sistema nunca deben recibir entradas de usuario sin sanear.

Validación y saneamiento según el tipo de dato

Direcciones de correo electrónico

Validación: comprueba que la entrada sigue un patrón de correo (algo como texto@dominio.extensión). Confirma que solo tiene caracteres permitidos.

Saneamiento: elimina las etiquetas HTML y los caracteres especiales. Conserva solo caracteres alfanuméricos, puntos, guiones y la arroba.

Números de teléfono

Validación: comprueba que solo contiene dígitos, guiones, paréntesis y espacios. Verifica que la longitud es la correcta para el país esperado.

Saneamiento: elimina todos los caracteres no numéricos salvo guiones y paréntesis. Quita los ceros o espacios iniciales si hace falta.

Campos de texto (comentarios, nombres, direcciones)

Validación: comprueba que el campo no está vacío y que la longitud es razonable (no millones de caracteres).

Saneamiento: elimina o escapa las etiquetas HTML, el JavaScript y los caracteres especiales de SQL. Conserva solo texto plano y signos de puntuación básicos.

Números e importes

Validación: comprueba que la entrada es un número. En precios o cantidades, comprueba que sea un número positivo.

Saneamiento: elimina los caracteres no numéricos. Si hace falta, redondea al número correcto de decimales.

Contraseñas

Validación: comprueba la longitud mínima (al menos 8 caracteres) y, si quieres, exige una mezcla de mayúsculas, minúsculas, números y símbolos.

Saneamiento: no recortes ni modifiques las contraseñas. Deben guardarse tal cual (con hash, nunca en texto plano). Si quitas caracteres de una contraseña, los usuarios no podrán iniciar sesión.

Subida de archivos

Validación: comprueba que el tipo de archivo es el esperado (por ejemplo, solo PDF o solo imágenes). Comprueba que el tamaño no es excesivo.

Saneamiento: renombra el archivo para que los atacantes no puedan usar nombres especiales. Analiza el archivo en busca de malware. Guárdalo fuera de la raíz web para que no pueda ejecutarse como código.

Cómo aplicar la validación y el saneamiento

En el cliente (en el navegador)

Usa los atributos de validación de HTML5 para dar respuesta inmediata a los visitantes:

<input type="email" name="email" required> <input type="tel" name="phone" pattern="[0-9]{10}"> <input type="number" name="age" min="0" max="120">

Esto detecta los errores evidentes y mejora la experiencia de usuario. Pero la validación en el cliente se puede saltar, así que por sí sola no es una medida de seguridad.

En el servidor (en tu servidor)

Aquí es donde se juega la seguridad. Tu código de backend debe validar y sanear cada dato:

// Pseudo-code example if (email does not match email pattern) { reject the submission } // Remove HTML tags sanitized_comment = remove_html_tags(comment_text) // Escape special characters for database safe_name = escape_sql_characters(user_name) // Only then store the data store_in_database(safe_name, sanitized_comment)

Usa consultas parametrizadas en las bases de datos

La mejor defensa contra la inyección SQL son las consultas parametrizadas (también llamadas sentencias preparadas). En lugar de meter la entrada del usuario directamente en una consulta SQL, usas marcadores de posición y pasas los datos por separado:

// Bad (vulnerable): query = "SELECT * FROM users WHERE email = '" + email + "'" // Good (safe): query = "SELECT * FROM users WHERE email = ?" execute(query, [email])

Con las consultas parametrizadas, el analizador de SQL sabe que la entrada del usuario son datos y no código. Aunque un atacante envíe código SQL, se trata como texto plano.

Usa bibliotecas y frameworks

No escribas el código de saneamiento desde cero. Usa bibliotecas consolidadas creadas para ello. En PHP, usa htmlspecialchars() o una biblioteca como HTML Purifier. En Python, usa el módulo `html` o una biblioteca como bleach. En Node.js, usa `express-validator` o algo similar. Estas bibliotecas están probadas y se actualizan para cubrir nuevos tipos de ataque.

Errores habituales de validación y saneamiento

Validar solo en el cliente. La validación en el cliente sirve para la experiencia de usuario, no para la seguridad. Un atacante puede saltársela. También tienes que validar en el servidor.

Bloquear caracteres peligrosos en lugar de permitir solo los seguros. Si intentas frenar la inyección SQL quitando punto y coma y comillas, los atacantes encontrarán la forma de esquivarlo. Es mejor crear una lista de los caracteres que esperas (en teléfonos, solo dígitos y guiones) y rechazar todo lo demás.

Fiarse del tipo de dato del campo. Si tienes un campo numérico, el navegador envía texto que parece un número. Tu servidor tiene que comprobar que de verdad es un número antes de usarlo. Nunca des por hecho que el tipo de dato es correcto.

Olvidar sanear los datos que se muestran. Aunque los datos se guarden de forma segura, si los muestras en una página web sin escapar el HTML, los atacantes pueden inyectar código que se ejecute en el navegador de los visitantes al verlos.

Sanear en el orden equivocado. Primero valida (¿tiene el formato correcto?) y después sanea (¿es seguro?). Si saneas y luego validas, puedes rechazar datos que en realidad eran seguros.

Qué hace WEMASY en la validación de entradas

WEMASY valida los campos del formulario de forma automática según el tipo de campo que elijas. En los campos de correo se comprueba que el formato sea válido. En los campos numéricos se comprueba que la entrada sea numérica. En los campos obligatorios se comprueba que haya contenido antes de enviar. En el servidor, WEMASY sanea toda la entrada para eliminar HTML, JavaScript y otro código peligroso antes de guardar los envíos. Tú eliges qué campos recoger y WEMASY se encarga de la validación y el saneamiento por detrás.

Consulta qué funciones de formularios incluye tu plan en la página de precios.

Preguntas frecuentes

¿Puedo usar un WAF (Web Application Firewall) en lugar de la validación?
Un WAF puede detectar algunos ataques de inyección antes de que lleguen a tu formulario, y eso ayuda. Pero no sustituye a la validación ni al saneamiento. Un WAF es una segunda línea de defensa. El código de tu formulario sigue teniendo que validar y sanear los datos por sí mismo. Usar a la vez un WAF y la validación de entradas te da varias capas de protección.
¿Y si un visitante necesita enviar caracteres especiales de forma legítima?
Los caracteres especiales como apóstrofos, guiones y el signo & son seguros si saneas bien. Por ejemplo, alguien puede llamarse "O'Brien" o "Mary-Jane". Es seguro aceptarlos si los escapas correctamente para la base de datos (con consultas parametrizadas) y al mostrarlos (con escape de HTML). Lo importante es sanear bien, no bloquear los caracteres.
¿Debo validar tanto en el cliente como en el servidor?
Sí. La validación en el cliente da respuesta inmediata a los visitantes y mejora la experiencia (se dan cuenta de un error de escritura antes de enviar). La validación en el servidor es la que realmente protege frente a ataques. Usa las dos capas. El cliente es para la experiencia de usuario. El servidor es para la seguridad.
¿Cuál es la diferencia entre escapar y sanear?
Escapar convierte los caracteres peligrosos para que se traten como texto plano (por ejemplo, convertir < en <). Sanear elimina por completo el contenido peligroso (por ejemplo, quitar todas las etiquetas HTML). Escapar conserva los datos; sanear elimina la amenaza. En la mayoría de los datos de formulario, sanear (quitar las etiquetas por completo) es más seguro que escapar (convertirlas).
¿Tengo que preocuparme por la inyección en formularios de solo lectura?
Si un formulario solo muestra información (no envía nada), no tiene vulnerabilidad de inyección. Pero si ese formulario llega a mostrar datos enviados por usuarios, sigues teniendo que sanear. Un atacante pudo enviar código malicioso antes, y al mostrarlo ese código se ejecuta. Sanea siempre los datos enviados por usuarios antes de mostrarlos, sea cual sea el tipo de formulario.

Ponlo en práctica
en tu propia web.

Empieza gratis con WEMASY y crea tu web en pocos minutos.