Volver al código PHP

Proteger un formulario público sin sesión ni cookie

Un sello firmado con HMAC que vence solo, no se puede fabricar y de paso delata a los robots por lo rápido que responden.

El problema

Un formulario abierto al público recibe envíos automáticos. Abrir una sesión para cada visitante solo por eso es caro y deja cookies que nadie pidió.

PHP
<?php
const SEMILLA = 'cambiar-por-un-secreto-largo';

function sello(): string {
    $ts = time();
    return $ts . '.' . hash_hmac('sha256', 'form|' . $ts, SEMILLA);
}

function sello_edad(string $sello): ?int {
    [$ts, $firma] = array_pad(explode('.', $sello, 2), 2, '');
    $esperada = hash_hmac('sha256', 'form|' . (int) $ts, SEMILLA);
    if (!hash_equals($esperada, $firma)) return null;   // fabricado o alterado
    $edad = time() - (int) $ts;
    return ($edad < 0 || $edad > 21600) ? null : $edad; // vence a las 6 horas
}

// En el formulario:  <input type="hidden" name="sello" value="<?= sello() ?>">
$edad = sello_edad($_POST['sello'] ?? '');
if ($edad === null)  exit('Formulario vencido. Recargá la página.');
if ($edad < 3)       exit('Demasiado rápido para ser una persona.');

Por qué está escrito así

  1. El sello es la hora en que se sirvió el formulario más su firma HMAC. Sin la semilla, nadie puede fabricar uno válido.
  2. hash_equals compara en tiempo constante: no filtra información por cuánto tarda la comparación.
  3. Como la hora viaja firmada, el servidor sabe cuánto tardó la persona en responder sin guardar nada.
  4. Un envío en menos de tres segundos casi nunca es humano: es el filtro contra robots más barato que existe.
Cómo probarlo

Poné el campo oculto en tu formulario y el bloque final al principio del script que lo recibe. Enviá apenas carga la página: debe rechazarlo por rápido.

Ojo con esto

El mismo sello sirve para varios envíos durante seis horas: frena robots, no reemplaza un límite de envíos por IP. Y la semilla va en un archivo de configuración fuera del repositorio.

Adaptalo a tu caso con IA

El botón copia este prompt con el código pegado debajo. Reemplazá los corchetes con lo tuyo y pegalo en ChatGPT, Claude, Gemini o Copilot.

El prompt
Uso este sello HMAC en PHP para proteger un formulario público sin sesión. Agregale un campo trampa oculto (honeypot) y un límite de [CANTIDAD] envíos por IP por día guardado en [DÓNDE GUARDO: archivo, SQLite o MySQL]. Que los rechazos devuelvan mensajes distintos para una persona y silencio para un robot. PHP 8, sin frameworks.

Ejemplo escrito y revisado a mano.

Compartir

Comentarios

Todavía no hay comentarios. El primero puede ser el tuyo.

Solo texto, sin enlaces. No se pide correo. Los comentarios se revisan antes de publicarse.

¿Lo adaptaste a algo tuyo?

Contame qué resolviste con esto, o qué le faltó.

Seguí probando

Más código

Ver todos
Darinel Ortega En línea · respondo durante el día
Hoy
Hola. Acá no vendo nada: esto es para intercambiar conocimiento sobre tecnología.
Escribime lo que quieras — podés mandar texto, imágenes o documentos. Los mensajes llegan a mi consola y te respondo desde ahí.
Estás escribiendo fuera de horario. Te leo apenas empiece el día.

Conversación abierta para compartir conocimiento. Los mensajes llegan a mi consola y respondo desde ahí.

Agendemos una conversación

Elegí el día y la hora que te sirvan. Son treinta minutos, sin agenda comercial.

Videollamada

Para una videollamada, pedila por acá y te paso el enlace de la sesión.