SEGURIDAD

CSRF

Ataque que engaña al navegador de un usuario con sesión abierta para que ejecute una acción en otra web sin que él lo sepa ni lo quiera.

Nivel · intermedio4 min de lecturaActualizado 23 ago 2026
También conocido como: Cross-Site Request Forgery, Falsificación de petición

Definición

El CSRF (Cross-Site Request Forgery) aprovecha una característica del navegador que normalmente es cómoda: las cookies se envían automáticamente en cada petición a un dominio, venga de donde venga esa petición.

Eso significa que si tienes la sesión abierta en tu banco y visitas otra web, esa otra web puede provocar que tu navegador haga una petición al banco... con tu cookie de sesión dentro. El banco recibe una petición perfectamente autenticada y no tiene forma de saber que tú no querías hacerla.

La diferencia con el XSS es importante: en XSS el atacante ejecuta código en tu web. En CSRF no necesita entrar en tu web para nada: usa el navegador de la víctima como intermediario desde otro sitio.

Cómo funciona un ataque

El usuario tiene la sesión abierta en tu panel. Visita una página cualquiera que contiene esto:

<img src="https://tu-panel.com/borrar-cliente?id=42">

El navegador intenta cargar la imagen, hace la petición, adjunta la cookie de sesión y el servidor borra el cliente 42. El usuario no ha pulsado nada y ni siquiera ve que ha pasado algo.

Con un formulario que se envía solo se puede hacer lo mismo con peticiones POST. No hace falta que el atacante vea la respuesta: le basta con que la acción ocurra.

Las defensas

Token anti-CSRF. La clásica y la más sólida. El servidor genera un valor aleatorio, lo guarda en la sesión y lo incluye como campo oculto en cada formulario. Al recibir la petición, comprueba que el token coincide.

Funciona porque el atacante no puede leer ese token: está en tu página, y la política del navegador le impide leer el contenido de una página de otro dominio. Puede provocar la petición a ciegas, pero no puede acertar el token.

// al pintar el formulario
$_SESSION['csrf'] = bin2hex(random_bytes(32));

// al recibirlo
if (!hash_equals($_SESSION['csrf'], $_POST['csrf'] ?? '')) {
    http_response_code(403); exit;
}

Cookies SameSite. La defensa moderna, y en gran medida ha resuelto el problema de fondo. Le dice al navegador que no mande la cookie en peticiones que vengan de otro sitio:

  • SameSite=Strict — nunca desde fuera. Lo más seguro, y rompe el caso de llegar desde un enlace externo ya con sesión.
  • SameSite=Lax — es el valor por defecto hoy en los navegadores. Manda la cookie en navegaciones normales y no en peticiones POST desde otro dominio.
  • SameSite=None — se manda siempre. Solo con Secure, y solo si de verdad lo necesitas.

Comprobar el origen. Mirar las cabeceras Origin o Referer y rechazar lo que no venga de tu dominio.

Usar el método correcto. Una acción que cambia algo nunca debe hacerse con GET. Si borrar se hace con GET, basta una imagen para provocarlo.

Ejemplo práctico

El asistente público de aeworks.tech es un caso interesante porque no usa sesiones, y aun así hay que protegerlo.

El endpoint acepta solo POST y comprueba el origen de la petición: si viene de otro dominio, devuelve un 403. No hay cookie de sesión que robar, pero sí hay un coste por cada llamada al modelo de IA, así que el peligro no es que alguien actúe en tu nombre: es que alguien use tu endpoint desde su web y te pase la factura.

En el panel de AEWorks, en cambio, sí hay sesión y la protección es la de manual: token en los formularios y cookie de sesión con las banderas puestas.

Una decisión de la que aprendí: el panel usa una cookie con nombre propio, no la de sesión estándar. Eso no aporta seguridad por sí mismo —la seguridad la dan las banderas y el token—, pero sí evita colisiones cuando varias aplicaciones comparten el mismo dominio, que es exactamente lo que pasa en un hosting compartido.

Errores comunes

  • Acciones que modifican datos con GET. Es el fallo de diseño que hace el ataque trivial.
  • Confiar solo en Referer. Se puede omitir, y hay configuraciones de privacidad que lo eliminan legítimamente.
  • Token que no cambia nunca o es predecible. Tiene que ser aleatorio y de longitud suficiente.
  • Comparar el token con ==. Usa una comparación de tiempo constante.
  • Creer que una API con token en cabecera es inmune. Lo es mientras el token vaya en una cabecera que el navegador no añade solo. Si lo guardas en una cookie que se manda automáticamente, vuelves a ser vulnerable.
  • Suponer que SameSite=Lax lo cubre todo. Cubre mucho y no es excusa para saltarse el token en las acciones críticas.

Cuándo preocuparte

Siempre que tengas sesiones con cookies y acciones que cambien datos. Es decir, en cualquier panel, portal de cliente o aplicación con login.

El escenario que más daño hace es un panel de administración: ahí una petición falsificada se ejecuta con los permisos más altos del sistema.

Referencias

Tagsprogramacionseguridadwebbackend
Escrito por
Antonio Echeverría

Dirijo IMDICA, una empresa de suministro industrial, desde 2007. Escribo estas definiciones desde el lado de quien las usa para decidir, no desde el de quien las estudia.

Si necesitas que alguien construya esto de verdad y no solo lo explique, eso es lo que hago en AE Works.