JavaScript / Intermedio / 6 min
Verificar Cloudflare Turnstile en un Worker
Valida el token de Turnstile del lado del servidor para bloquear spam y bots en formularios sin CAPTCHAs molestos.
Turnstile reemplaza a los CAPTCHAs, pero solo protege de verdad si verificas el token en el servidor. Un atacante puede saltarse la comprobación del navegador; la validación server-side no. Este Worker recibe el cf-turnstile-response que envía tu formulario, lo valida contra la API de Cloudflare con tu secret key y solo deja pasar la petición si el token es legítimo.
Guía de Implementación Paso a Paso
- En el panel de Cloudflare ve a Turnstile y crea un widget para tu dominio.
- Copia la Site Key (para el frontend) y la Secret Key (para el Worker).
- Añade el widget a tu formulario en el HTML con
<div class="cf-turnstile" data-sitekey="TU_SITE_KEY"></div>y el script de Turnstile. - Crea un Worker en Workers & Pages → Create Worker.
- Pega el código de abajo y guarda.
- En Settings → Variables, añade una variable secreta llamada
TURNSTILE_SECRETcon tu Secret Key. - Apunta el
actionde tu formulario a la ruta del Worker y despliega.
JAVASCRIPT
export default {
async fetch(request, env) {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
const body = await request.formData();
const token = body.get('cf-turnstile-response');
const ip = request.headers.get('CF-Connecting-IP');
if (!token) {
return new Response('Falta el token de Turnstile', { status: 400 });
}
const form = new FormData();
form.append('secret', env.TURNSTILE_SECRET);
form.append('response', token);
form.append('remoteip', ip);
const result = await fetch(
'https://challenges.cloudflare.com/turnstile/v0/siteverify',
{ method: 'POST', body: form }
);
const outcome = await result.json();
if (!outcome.success) {
return new Response('Verificación fallida. Reintenta.', { status: 403 });
}
// Token válido: aquí procesas el formulario (guardar, enviar email, etc.)
return new Response('Formulario recibido correctamente', { status: 200 });
}
};
Nunca expongas la Secret Key en el frontend: va siempre como variable de entorno del Worker. El campo remoteip es opcional pero refuerza la validación al atar el token a la IP que lo generó.
