Los formularios de contacto, endpoints de login y APIs públicas son blancos frecuentes de abuso: spam, fuerza bruta, scraping y envíos automatizados. La protección efectiva combina varias capas, ninguna por sí sola es suficiente.
Este artículo describe un enfoque en capas para proteger formularios y endpoints en aplicaciones Astro, Laravel y Node.js — el mismo patrón que usa este portafolio en producción.
Capas de protección
- Rate limiting: limitar requests por IP en ventana de tiempo.
- Honeypot: campo oculto que los bots llenan y los humanos no.
- Form timing: detectar envíos más rápidos que un humano (< 3.5s).
- Origin check: validar Origin/Referer en producción.
- Validación con esquemas: Zod u equivalente en el servidor.
- Sanitización: limpiar inputs antes de procesar o almacenar.
- CAPTCHA opcional: Cloudflare Turnstile cuando el volumen lo justifica.
Rate limiting
Aplicar en endpoints públicos sensibles:
- Login y registro: 5 intentos por IP por minuto.
- Reset de password: 3 por IP por hora.
- Formulario de contacto: 5 por IP por minuto.
- APIs sin autenticación: según el caso de uso.
Implementación en memoria para un solo proceso; Redis cuando hay múltiples réplicas. Responder con 429 Too Many Requests y header Retry-After.
Honeypot
Campo oculto con CSS (display: none o position: absolute; left: -9999px). Los bots lo llenan automáticamente; los humanos no lo ven. Si llega con valor, rechazar silenciosamente (responder 200 sin procesar, para no dar pistas al bot).
Form timing
Registrar timestamp al renderizar el formulario (campo oculto o session). Al recibir el POST, rechazar si el tiempo transcurrido es menor a 3–4 segundos. Los bots envían instantáneamente; los humanos tardan al menos unos segundos en leer y completar.
Validación en servidor
Esquemas con Zod (o equivalente) en cada endpoint API:
- Tipos estrictos: email como email, teléfono con formato, longitud máxima.
- Campos requeridos vs opcionales explícitos.
- Rechazar payloads con campos no esperados (strip o reject).
- Mensajes de error genéricos al cliente; detalle solo en logs del servidor.
Sanitización
- Strip HTML de campos de texto plano.
- Normalizar espacios y caracteres de control.
- Truncar strings que excedan longitud máxima.
- Nunca interpolar input del usuario en queries SQL ni en templates sin escape.
Origin check
En producción, validar que el header Origin o Referer coincida con el dominio del sitio. Rechazar requests de dominios desconocidos. No es infalible (se puede falsificar), pero filtra bots básicos y scripts cross-origin.
Cloudflare Turnstile
Cuando el volumen de spam justifica fricción adicional, Turnstile de Cloudflare es ligero y respeta privacidad. Se configura con TURNSTILE_SITE_KEY (público) y TURNSTILE_SECRET_KEY (servidor). El servidor verifica el token antes de procesar el formulario.
Flujo completo en un endpoint
- Rate limit check → 429 si excede.
- Honeypot check → 200 silencioso si lleno.
- Form timing check → 400 si muy rápido.
- Origin check → 403 si origen inválido.
- Turnstile verification (si configurado) → 400 si inválido.
- Validación Zod → 400 con errores de campo.
- Sanitización → procesar.
Errores frecuentes
- Confiar solo en validación del frontend.
- Rate limiting solo en login, no en contacto ni webhooks.
- Honeypot visible o con
tabindexaccesible (los lectores de pantalla lo llenan). - Responder 403 al honeypot (el bot aprende y adapta).
- Loguear payloads completos con emails y teléfonos (PII en logs).
- Rate limit en memoria con 3 réplicas (cada una tiene su propio contador).
Conecta con auditoría de seguridad, ciberseguridad y APIs REST .