Frena el spam en formularios de contacto

Frena el spam en formularios de contacto7 min de lectura

Cómo añadir un campo honeypot que rellenan los bots y no las personas

Añade a cualquier formulario un honeypot que atrape bots sin molestar a lectores de pantalla, teclado ni autocompletado, con la comprobación en el servidor para cada stack.

Preet SutharFundador, Ikiform

Añade un input de texto extra que ocultas fuera de pantalla, sacas del orden de tabulación y envuelves en aria-hidden, con un nombre que ningún navegador autocompleta. Las personas nunca lo rellenan; los bots que rellenan todos los inputs, sí. En el servidor, trata como spam cualquier envío que lo traiga con un valor y responde exactamente igual que a un mensaje real.

Qué tiene de especial un honeypot

Un honeypot tiene que ser dos cosas a la vez. Para un bot que lee el HTML, debe parecer un campo normal que vale la pena rellenar. Para cualquier persona, no debe existir, y eso incluye a quienes no usan el formulario como tú: alguien con lector de pantalla, alguien que navega con el teclado, alguien cuyo gestor de contraseñas rellena los formularios por él. La mayoría de los fallos de honeypot vienen de olvidar a alguna de esas personas, y el síntoma es un mensaje real archivado en silencio como spam.

Cómo una persona y un bot se encuentran con el mismo campo honeypotUna persona, con cualquier navegador o tecnología de asistenciaUn bot de scriptrellena elformulariopantalla,teclado olector depantallase salta latrampafuera depantalla,tabindex -1,aria-hiddenelautocompletadola ignoraun nombre queningúnnavegadorreconocerecibidola trampa estávacíalee elHTMLencuentratodos losinputslos rellenatodosincluida latrampaenvía alinstantespammismarespuesta deéxitoCómo una persona y un bot se encuentran con el mismo campo honeypotUna persona, con cualquier navegador o tecnología de asistenciaUn bot de scriptrellena el formulariopantalla, teclado o lector depantallase salta la trampafuera de pantalla, tabindex -1,aria-hiddenel autocompletado laignoraun nombre que ningún navegadorreconocerecibidola trampa está vacíalee el HTMLencuentra todos los inputslos rellena todosincluida la trampaenvía al instantespammisma respuesta de éxito
  1. Una persona rellena el formulario con lo que use: una pantalla, un teclado o un lector de pantalla.
  2. La trampa está fuera de pantalla, fuera del orden de tabulación y oculta a la tecnología de asistencia, así que nunca llega a ella.
  3. Su nombre es uno que los navegadores y los gestores de contraseñas no autocompletan, así que se queda vacía.
  4. El envío llega con la trampa vacía y se recibe.
  5. Un bot de script lee el HTML y encuentra todos los inputs, incluida la trampa.
  6. Los rellena todos y envía al instante.
  7. La trampa tiene un valor, así que el envío es spam. El bot recibe igualmente una respuesta de éxito normal.
Cada protección de la fila de arriba cierra una vía por la que una persona real podría llegar al campo. Quita cualquiera y la fila de arriba también puede acabar en spam.

El markup

Pon la trampa dentro del formulario, junto a los campos reales, como un input de texto normal. Un input type="hidden" no sirve: los bots saben que las personas no pueden editarlos y los dejan en paz.

contact.html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="POST">
  <label for="email">Email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />
  <label for="message">Message</label>
  <textarea id="message" name="message" required></textarea>

  <div class="hp" aria-hidden="true">
    <label for="hp-field">Leave this empty</label>
    <input id="hp-field" name="_gotcha" type="text" tabindex="-1" autocomplete="off" />
  </div>

  <button>Send</button>
</form>
estilos
<style>
.hp {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
</style>
  • aria-hidden="true" en el contenedor quita la etiqueta y el input del árbol de accesibilidad, así que los lectores de pantalla no los anuncian.
  • tabindex="-1" evita que la tecla Tab caiga en un input que nadie ve.
  • La etiqueta dice Leave this empty (déjalo vacío). Si alguna herramienta llega a mostrar el campo, quien lo lea sabe qué hacer.
  • No añadas required. Un campo obligatorio que las personas no pueden ver bloquea todos los envíos honestos.

Cómo ocultarlo

Los bots han aprendido a saltarse los campos que están ocultos de forma evidente. Los scrapers sencillos siguen rellenándolo todo, pero algunos miran el atributo hidden o un display: none en línea antes de escribir. Cuanto más lejos del propio input esté la ocultación, más bots caen.

TécnicaOculto para las personasBots que aún atrapa
Atributo hidden o display: none en líneaSíSolo los más simples. Es lo primero que comprueba un bot más listo
Clase fuera de pantalla en tu hoja de estilosSíLa mayoría. El bot tendría que cargar y aplicar tu CSS para darse cuenta
opacity: 0 o tamaño ceroCasi siempre. Algunas lupas y contornos de foco aún lo revelanLa mayoría, pero es más arriesgado para las personas
Añadido con JavaScript después de cargarSíBots que ejecutan scripts. Los scrapers de HTML no lo ven nunca, así que se le escapan

Usa la clase fuera de pantalla de tu hoja de estilos. Atrapa más bots y es la más segura para las personas. Si un honeypot deja de funcionar, añade un segundo con otro nombre en lugar de un truco de ocultación más ingenioso.

Elige un nombre que el autocompletado ignore

Los navegadores y los gestores de contraseñas rellenan campos adivinando a partir de su name, su id, su etiqueta y su valor de autocomplete. autocomplete="off" es una sugerencia, y algunos navegadores la ignoran en campos que parecen direcciones o datos de contacto. Así que el nombre es lo que hace el trabajo de verdad.

EvitaPor quéUsa en su lugar
email2, phone, name, addressEl autocompletado los reconoce y los rellena para personas reales_gotcha, company_website
honeypot, trap, botAlgunos bots se saltan los campos con nombres obviosUn nombre soso y creíble
url o website a secasAlgunas herramientas de autocompletado rellenan un campo de sitio web desde un perfil guardadoUn nombre compuesto, como company_website

Compruébalo en el servidor

Un honeypot solo funciona si el servidor lo lee. Una comprobación en el navegador no sirve de nada, porque un bot nunca ejecuta tu script. Cuando el campo tenga un valor, responde exactamente igual que a un mensaje real, y no guardes ni reenvíes el envío. Una respuesta distinta le dice al bot qué campo lo delató. Los ejemplos de abajo llaman a tu propio saveMessage; cámbialo por lo que guarde o envíe por email el mensaje.

Un formulario HTML básico no tiene servidor propio. Apúntalo a Ikiform y llama a la trampa _gotcha, o renómbrala en cada formulario en Honeypot field. Ikiform hace la comprobación en el servidor, y la trampa nunca se guarda como respuesta.

contact.html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="POST">
  <label for="email">Email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />
  <label for="message">Message</label>
  <textarea id="message" name="message" required></textarea>

  <div class="hp" aria-hidden="true">
    <label for="hp-field">Leave this empty</label>
    <input id="hp-field" name="_gotcha" type="text" tabindex="-1" autocomplete="off" />
  </div>

  <button>Send</button>
</form>
Registra los envíos atrapados aunque no los guardes. Un conteo diario te dice si el honeypot sigue mereciendo su lugar, y una caída repentina a cero significa que los bots han aprendido a saltárselo.

Cómo gestiona Ikiform el honeypot

Cada formulario de Ikiform tiene por defecto un honeypot llamado _gotcha. Cámbialo en cada formulario en Honeypot field, en los ajustes del formulario; el nombre que elijas queda reservado y nunca se guarda como respuesta. Un honeypot relleno suma 5 a la puntuación de spam, lo que alcanza por sí solo el umbral de 5.

Ikiform no descarta el envío. Lo guarda como spam, así que si alguna vez una persona real cae en la trampa, puedes encontrar el mensaje y restaurarlo. Un envío considerado spam recibe la misma respuesta de éxito que uno real, así que el bot no aprende nada. Se guarda con el estado spam, no envía email de notificación ni webhook, no cuenta para tu uso y se elimina a los 30 días. Cada lunes, un espacio de trabajo que haya bloqueado spam recibe un email de resumen con el total, los formularios con más actividad y los motivos principales. La documentación de spam y Formularios HTML tienen la referencia.

Comprueba que funciona

  1. Carga el formulario con un lector de pantalla activado y recórrelo. La trampa nunca se anuncia.
  2. Recorre el formulario con Tab. El foco pasa del último campo real directamente al botón.
  3. Deja que tu navegador y tu gestor de contraseñas autocompleten el formulario. La trampa sigue vacía.
  4. Envía con el honeypot relleno, _gotcha=bot. Sigue recibiendo una respuesta de éxito, pero el envío se guarda como spam y no envía email ni webhook.
  5. Envía un mensaje normal. Llega como recibido, sin rastro del campo trampa.

Trampas habituales

  • Envíos JSON. Si construyes el cuerpo a mano en lugar de con FormData, incluye la trampa, o tu servidor la leerá vacía también para los bots.
  • Creadores de formularios que renombran campos. Algunos creadores añaden prefijos o renombran los inputs. Mira el cuerpo enviado, no el editor, para saber el nombre real de la trampa.
  • Caché. Si una página en caché conserva el nombre antiguo de la trampa después de renombrarla, los envíos llegan con el nombre viejo y pasan. Renómbrala en ambos lados a la vez.
  • Honeypots de checkbox. Una checkbox oculta también funciona, pero los lectores de pantalla gestionan peor las checkboxes sueltas que los inputs de texto. Mejor un input de texto.
  • Una sola capa. Los bots que usan un navegador real y se saltan los campos invisibles pasan por delante de cualquier honeypot. Combínalo con un límite de frecuencia y, si hace falta, una verificación humana.

Preguntas

¿Te atascaste en un paso o quieres una guía para tu caso? Escribe a hello@ikiform.com.