Protección de APIs y formularios: el portero contra spam y abuso

Protección de APIs y formularios: el portero contra spam y abuso

Actualizado: 12 min de lectura
  • seguridad
  • rate-limiting
  • anti-spam
  • validación
  • api
  • turnstile

Un formulario de contacto o una API pública sin control es como un edificio sin portero: cualquiera entra, deja basura o intenta forzar la puerta. El spam, la fuerza bruta y el scraping no son “ruido menor”: saturan bandejas, consumen cuota de email y pueden tumbar un endpoint un viernes por la tarde.

Este artículo explica un enfoque en capas — el mismo patrón que usa este portafolio en producción con Astro, y aplicable a Laravel y Node — para que una persona no técnica entienda el porqué, y un técnico tenga checklist, orden de checks y errores a evitar.

Por qué importa para el negocio

Cada lead falso cuesta tiempo de ventas. Cada intento de login sin límite es una lotería contra credenciales filtradas. Cada webhook o endpoint “abierto” es superficie de abuso. Proteger no es paranoia: es mantener el canal útil para humanos reales y caro para bots.

  • Bandeja usable: menos spam = más respuestas a clientes reales.
  • Disponibilidad: rate limit evita que un script tumbe el servidor.
  • Confianza: validar en servidor reduce basura en CRM y tickets inventados.
  • Cumplimiento práctico: menos PII de atacantes en logs y bases.

Conceptos clave (simple + técnico)

El portero en capas

Ninguna capa sola basta. El honeypot atrapa bots torpes; el rate limit frena el volumen; el timing detecta envíos inhumanos; la validación y sanitización cuidan lo que entra; Turnstile añade fricción solo cuando hace falta. Como un edificio: recepción, cámara, llave y alarma — no solo un cartel de “prohibido”.

CapaQué bloqueaRespuesta típica
Rate limitingVolumen / fuerza bruta429 + Retry-After
HoneypotBots que rellenan todo200 silencioso (sin procesar)
Form timingEnvíos < ~3.5s400
Origin checkScripts cross-origin básicos403
TurnstileBots más sofisticados400 si token inválido
Zod + sanitizarBasura y payloads raros400 con errores de campo

Rate limiting

Limita requests por IP (y, si aplica, por usuario) en una ventana de tiempo. En un solo proceso basta memoria; con varias réplicas hace falta Redis u otro store compartido. Ejemplos orientativos: login 5/min, reset password 3/hora, contacto 5/min.

Honeypot y timing

El honeypot es un campo oculto (display: none o fuera de pantalla) que los humanos no ven. Si llega lleno, rechaza en silencio (200 sin procesar) para no educar al bot. El timing guarda un timestamp al renderizar y rechaza envíos más rápidos que un humano razonable.

Validación, sanitización y origen

La validación del frontend mejora UX; la del servidor es la que importa. Esquemas (Zod u equivalente), strip de HTML en texto plano, longitudes máximas, y en producción comprobar Origin/Referer. No es infalible, pero filtra mucho ruido barato.

Guía práctica: flujo en un endpoint

  1. Rate limit check → 429 si excede.
  2. Honeypot check → 200 silencioso si el campo oculto tiene valor.
  3. Form timing check → 400 si es demasiado rápido.
  4. Origin check → 403 si el origen no es el del sitio.
  5. Turnstile (si está configurado) → 400 si el token falla.
  6. Validación con esquema → 400 con errores de campo.
  7. Sanitización → procesar (email, CRM, cola).

Honeypot bien hecho

  • Oculto con CSS, no con type="hidden" obvio si puedes evitarlo.
  • Nombre engañoso (website, company_url) — no honeypot.
  • tabindex="-1" y autocomplete="off"; no debe ser accesible para lectores de pantalla de forma accidental.
  • Si está lleno: responder éxito falso, no 403 explícito.

Cloudflare Turnstile

Cuando el volumen de spam justifica fricción extra, Turnstile es ligero y respeta privacidad frente a alternativas más agresivas. TURNSTILE_SITE_KEY en el cliente; TURNSTILE_SECRET_KEY solo en servidor. El servidor verifica el token antes de procesar.

Errores frecuentes

  • Confiar solo en validación del frontend.
  • Rate limit solo en login, no en contacto ni endpoints públicos.
  • Honeypot visible, con label real, o enfocable por teclado/lectores.
  • 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 contador).
  • Mensajes de error que revelan si un email “existe” en el sistema.

Checklist de protección

  • Lista de endpoints públicos sensibles (login, contacto, reset, webhooks).
  • Rate limit con límites documentados y Retry-After.
  • Honeypot + timing en formularios HTML.
  • Origin/Referer check en producción.
  • Esquema de validación en servidor + sanitización.
  • Turnstile opcional cuando el spam lo justifica.
  • Store compartido (Redis) si hay más de una réplica.
  • Logs sin PII innecesaria; métricas de 429/400 para detectar ataques.

Conecta con auditoría de seguridad, ciberseguridad y APIs REST .

Preguntas frecuentes

¿El honeypot basta contra bots?

No solo. Filtra bots básicos, pero conviene combinarlo con rate limiting, timing y, en producción con mucho spam, un CAPTCHA como Turnstile.

¿Dónde aplicar rate limiting?

En endpoints públicos: login, registro, reset de password, formularios de contacto, webhooks y APIs sin autenticación. Por IP y, si aplica, por usuario autenticado.

¿Validar en frontend o backend?

En ambos, pero el backend es obligatorio. El frontend mejora la experiencia; el backend es la puerta que no se puede saltar con curl.

¿Turnstile o reCAPTCHA?

Turnstile suele ser más ligero y amigable con la privacidad. reCAPTCHA funciona pero depende de Google. Elige según stack y política de privacidad del sitio.

¿El rate limiting en memoria escala?

Para un solo proceso, sí. Con varias réplicas hace falta Redis u otro store compartido; si no, cada instancia tiene su propio contador y el límite real se multiplica.