Para proteger un formulario web contra spam y abuso no alcanza con validar campos mediante JavaScript. Cualquier visitante puede modificar el código del navegador o enviar una solicitud directamente al endpoint. Todas las decisiones de seguridad deben repetirse y aplicarse en el servidor.
Un formulario de contacto, registro, comentario, presupuesto o carga de archivos necesita varias capas. Ningún CAPTCHA, regla de firewall o filtro aislado resuelve todos los riesgos.
Definí qué debe aceptar el formulario
Antes de programar controles, establecé qué campos existen, qué formato admiten, qué longitud necesitan y qué acción realiza cada uno. Una lista de valores permitidos es más segura que intentar bloquear todas las variantes peligrosas.
- Nombre: caracteres esperados y longitud razonable.
- Email: formato válido y longitud máxima.
- Teléfono: caracteres, prefijo y extensión admitidos.
- Asunto: opciones predefinidas cuando sea posible.
- Mensaje: límite de longitud y tratamiento como texto, no como HTML confiable.
- Archivos: tipos estrictamente necesarios, tamaño y cantidad máximos.
También verificá las reglas del negocio. Un valor puede tener formato correcto y ser inválido para la acción solicitada.
Validación del lado servidor
El navegador puede mejorar la experiencia indicando errores antes de enviar, pero el backend debe volver a comprobarlo todo. Rechazá campos inesperados, arreglos donde se esperaba texto, valores demasiado largos y codificaciones inválidas.
Normalizá los datos únicamente cuando sea apropiado. No elimines caracteres al azar hasta conseguir que un valor parezca válido, porque podrías cambiar su significado o esconder un intento de ataque.
La validación no reemplaza la codificación
Un dato validado todavía debe prepararse para el contexto donde se utilizará:
- Al mostrarlo en una página, codificá la salida para prevenir XSS.
- Al almacenarlo en SQL, utilizá consultas preparadas y parámetros.
- Al usarlo en un correo, no permitas que construya cabeceras.
- No lo concatenes dentro de comandos, rutas o plantillas ejecutables.
Consultá las explicaciones específicas de Cross-Site Scripting y inyección SQL.
Protección CSRF
Si el formulario realiza una acción utilizando una sesión autenticada, incorporá la protección CSRF del framework. El servidor debe generar un token impredecible, asociarlo al contexto apropiado y rechazar solicitudes que no presenten un valor válido.
No utilices solicitudes GET para cambiar contraseñas, preferencias, direcciones o datos. El atributo SameSite de las cookies ayuda como defensa adicional, pero no reemplaza el control de la aplicación en todos los escenarios.
Límites de frecuencia y volumen
Definí cuántas solicitudes puede procesar el endpoint durante una ventana de tiempo. El control puede considerar IP, sesión, usuario autenticado, dirección de destino y comportamiento, sin depender de una sola señal.
Agregá también un límite global. Una red de bots puede enviar pocas solicitudes desde muchas direcciones y superar fácilmente un control exclusivamente individual.
Campos señuelo y tiempo de envío
Un campo señuelo oculto para usuarios normales puede detectar bots básicos que completan todos los campos. Otra señal útil es el tiempo transcurrido entre la presentación y el envío: una solicitud instantánea puede ser sospechosa.
No bloquees basándote solamente en estas señales. Los gestores de contraseñas, lectores de pantalla y otras herramientas legítimas pueden comportarse de manera diferente. Utilizalas como parte de una evaluación por capas.
CAPTCHA o Turnstile
Turnstile y otros sistemas de desafío ayudan a reducir automatización, pero el resultado debe validarse en el servidor antes de procesar el formulario. Mostrar el widget sin llamar al servicio de verificación desde el backend no protege el endpoint.
Los tokens tienen vencimiento y son de un solo uso. No expongas la clave secreta en el navegador, validá cada solicitud y tratá los errores sin revelar información interna.
Correo generado por el formulario
Usá una dirección fija y autorizada de tu dominio como From. Después de validar el email del visitante, podés colocarlo en Reply-To. No permitas que un campo del formulario defina destinatarios, Cc, Bcc o cabeceras adicionales.
Para una implementación completa, revisá cómo enviar desde PHP mediante SMTP y los riesgos de seguridad de PHP mail().
Subida segura de archivos
Si el formulario permite adjuntar archivos, aplicá defensa en profundidad:
- Permití únicamente extensiones necesarias.
- No confíes en el nombre ni en el Content-Type enviado por el navegador.
- Comprobá tipo real, firma y contenido cuando sea posible.
- Generá un nombre interno nuevo y evitá rutas proporcionadas por el usuario.
- Limitá tamaño, cantidad y recursos consumidos al procesarlo.
- Almacená fuera de la raíz pública cuando el flujo lo permita.
- No otorgues permiso de ejecución.
- Analizá el archivo antes de publicarlo o enviarlo.
Una lista de extensiones bloqueadas no es suficiente porque existen dobles extensiones, nombres engañosos y tipos declarados falsos.
Mensajes de error seguros
El visitante necesita saber si faltó un campo o si debe reintentar, pero no debe recibir trazas, consultas SQL, rutas internas, credenciales ni respuestas completas del servidor de correo. Registrá el detalle técnico de forma privada y mostrá un mensaje breve.
En producción, evitá imprimir excepciones o advertencias de PHP en la respuesta. Conservá los registros con acceso restringido y revisalos periódicamente.
Registro y privacidad
Guardá solamente los datos necesarios para operar e investigar. Definí quién puede acceder, cuánto tiempo se conservan y cómo se eliminan. No registres contraseñas, tokens completos, secretos, números de tarjeta ni contenido sensible sin una necesidad justificada.
Una alerta por aumento repentino de solicitudes, errores o correos enviados puede detectar un abuso antes de que afecte la cuenta.
Qué puede aportar un WAF
Un firewall de aplicaciones puede bloquear patrones conocidos, limitar solicitudes y desafiar tráfico sospechoso. Es una capa útil, pero no conoce todas las reglas del formulario y no corrige un código que acepta destinatarios arbitrarios o almacena archivos peligrosos.
Probá las reglas antes de aplicarlas de forma general para evitar bloquear formularios legítimos, integraciones, pasarelas o solicitudes administrativas.
Cómo responder si comienza el abuso
- Deshabilitá temporalmente el formulario o su acción de correo.
- Revisá registros para conocer volumen, campos y origen.
- Cambiá credenciales si pudieron quedar expuestas.
- Corregí la validación y fijá destinatarios y remitentes.
- Agregá límites y validación del desafío en el servidor.
- Actualizá CMS, plugins, framework y biblioteca de correo.
- Probá casos normales y abusivos antes de rehabilitarlo.
Lista de comprobación final
- Validación sintáctica y semántica en el servidor.
- Codificación según HTML, SQL, correo o archivo.
- Protección CSRF para acciones autenticadas.
- Límites individuales y globales.
- Turnstile o CAPTCHA validado en backend.
- From y destinatarios definidos por la aplicación.
- Adjuntos con tipo, tamaño, nombre y almacenamiento seguros.
- Errores privados, registros limitados y alertas activas.
La protección efectiva combina código seguro, controles de aplicación, límites operativos y monitoreo. Si una capa falla, las demás deben reducir el impacto.