Imagina que un usuario de tu sitio web transfiere fondos o cambia su contraseña en su panel de control sin ser consciente de ello. Así es precisamente como funciona un ataque CSRF.

En este artículo, analizaré con ejemplos cómo se estructura la falsificación de solicitudes entre sitios y te mostraré cómo configurar la protección en dos frameworks populares: Django y Laravel.

Diagrama explicativo de un ataque CSRF
Un atacante engaña al navegador de un usuario autenticado para que envíe una solicitud no deseada.

¿Qué es un ataque CSRF y cómo funciona?

Un ataque CSRF (del inglés Cross-Site Request Forgery) es una vulnerabilidad de seguridad que engaña a un usuario autenticado para que realice acciones no deseadas en una aplicación web, como cambiar su contraseña o transferir fondos. El atacante lo logra creando un enlace malicioso que, al ser visitado, ejecuta una solicitud aprovechando las cookies de sesión del usuario.

Por ejemplo, transferir fondos desde la cuenta bancaria del usuario, modificar su contraseña o datos personales en el sitio, realizar una compra en una tienda en línea y pagarla con la tarjeta de la víctima.

El ataque se desarrolla en cuatro etapas:

  1. El usuario se autentica en el sitio web. Tras un inicio de sesión exitoso, el servidor genera un identificador de sesión, que generalmente se almacena como una cookie en el navegador del usuario. Estas cookies le permiten permanecer autenticado sin necesidad de reintroducir sus credenciales.
  2. El atacante crea un enlace que realiza una solicitud al sitio web en nombre del usuario. El atacante envía este enlace a través de correo electrónico, redes sociales o lo publica en otros sitios web.
  3. El usuario hace clic en el enlace. Cuando el usuario accede al enlace malicioso, el navegador envía automáticamente una solicitud al servidor del sitio de confianza e incluye las cookies de sesión, ya que están asociadas al dominio de dicho sitio. Desde la perspectiva del servidor, la solicitud es legítima, ya que no se puede distinguir de una acción intencionada del usuario.
  4. El sistema ejecuta la solicitud del atacante. Dado que el sistema considera que la solicitud es válida, el servidor ejecuta la acción contenida en ella en nombre del usuario autenticado al que se le emitió la cookie de sesión. De este modo, el atacante puede lograr su objetivo sin acceso directo a las credenciales del usuario.

A diferencia de un ataque XSS, un ataque CSRF (también conocido como XSRF) no requiere la inyección de código malicioso en el sitio web. La diferencia entre XSS y CSRF radica en que el atacante explota la ausencia de un mecanismo de validación de la autenticidad de la solicitud para forzar al navegador del usuario a ejecutar acciones no deseadas. Por lo tanto, no se debe confiar implícitamente en ninguna acción realizada por el usuario en el sistema.

Además, muchos navegadores modernos usan por defecto el atributo SameSite en cookies de sesión para mitigar la mayoría de ataques CSRF clásicos al impedir que se envíen cookies en solicitudes cross-site no seguras.

Un Ataque CSRF en Acción: Ejemplo Práctico

Para que el ataque tenga éxito, deben cumplirse tres condiciones simultáneamente:

  1. Existencia de una acción objetivo. La aplicación o el sitio web deben tener una acción que el atacante pueda ejecutar sin el conocimiento del usuario. Por ejemplo, agregar un nuevo administrador, cambiar la contraseña de un usuario o enviar una transferencia de fondos.
  2. Manejo de sesiones basado en cookies. Para ejecutar la acción, el sitio o la aplicación envía una o más solicitudes HTTP, basándose únicamente en las cookies de sesión para identificar al usuario que las ha enviado.
  3. Inexistencia de parámetros desconocidos. Las solicitudes para ejecutar la acción no contienen valores que sean difíciles de adivinar para el atacante. Por ejemplo, si para cambiar una contraseña es obligatorio proporcionar la contraseña anterior, el ataque no podrá llevarse a cabo, ya que el atacante desconoce ese valor.

Supongamos que una aplicación web gestiona las sesiones mediante cookies. Los usuarios pueden modificar su dirección de correo electrónico mediante el siguiente formulario HTML. Este es un ataque CSRF ejemplo clásico:

<html>
  <body>
    <form action="/user/email" method="POST">
      <input type="email" name="email" value="" />
        <input type="submit" value="Guardar">
    </form>
  </body>
</html>

Si un usuario introduce una nueva dirección en el formulario y pulsa “Guardar”, el navegador enviará una solicitud POST con los siguientes valores:

POST /user/email HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
Cookie: PHPSESSID=JKcciBhFZ0tTp1xh7QW2DigRqdUZknbC

email=user@example.com

Al analizar dicha solicitud, un atacante concluirá que un ataque a través de ella sería exitoso por tres motivos:

  1. La capacidad de cambiar la dirección de correo electrónico en la cuenta de un usuario permite restablecer la contraseña y tomar el control de la cuenta.
  2. La aplicación utiliza una cookie para transmitir el identificador de sesión y así determinar qué usuario ha enviado la solicitud. No se utilizan tokens CSRF ni otros mecanismos para evitar ataques CSRF.
  3. Todos los parámetros necesarios para ejecutar la acción son conocidos.

A continuación, el atacante preparará una página HTML maliciosa que le permitirá ejecutar la acción deseada:

<html>
    <body>
        <form action="https://example.com/user/email" method="POST">
            <input type="hidden" name="email" value="evil@hacker.com" />
        </form>
        <script>
            document.forms[0].submit();
        </script>
    </body>
</html>

Solo le restará alojar la página en internet y atraer a la víctima hacia ella, por ejemplo, mediante un correo de phishing, un SMS, un mensaje en una aplicación de mensajería o un banner publicitario.

Cuando la víctima visite esta página, se ejecutará el formulario oculto con envío automático. El navegador de la víctima adjuntará la cookie de sesión del usuario a la solicitud. El backend de la aplicación web recibirá la cookie y modificará el correo electrónico del usuario al valor especificado por el hacker en el sitio malicioso. Como puedes ver, es fundamental tener un plan para protegerse de un ataque CSRF.

Como resultado, el atacante obtendrá el control de la cuenta, podrá establecer una nueva contraseña y ejecutar cualquier acción en nombre de la víctima.

Cómo Protegerse de un Ataque CSRF con Tokens

Para contrarrestar este ataque, es necesario implementar un token secreto especial (token CSRF), también conocido como token anti-CSRF.

El proceso de protección es el siguiente:

  1. Generación. Para cada usuario, se genera un token único, aleatorio y renovable que se añade al formulario y se almacena en el lado del servidor, dentro de la sesión del usuario.
  2. Transmisión. El token se inserta en el DOM de la página HTML o se transmite a través de una API. Cada solicitud que modifica datos debe contener este token, ya sea como un parámetro o en una cabecera HTTP.
  3. Validación. Al recibir una solicitud, el servidor compara el token recibido con el que se emitió al usuario en el momento de la generación. Si no coinciden, la acción no se ejecutará.
Flujo de validación de un token anti-CSRF
El servidor genera un token único que el cliente debe devolver para validar cada solicitud.

Muchos frameworks ya implementan un mecanismo de protección contra ataques CSRF basado en un token secreto. Mi recomendación es que estudies la documentación del framework que utilizas para el desarrollo y verifiques si dispone de dicho mecanismo.

Para una guía técnica más profunda, la documentación de prevención de CSRF de OWASP es una referencia fundamental.

Por ejemplo, frameworks populares de Java como Spring y GWT disponen de protección integrada que añade un token a todas las solicitudes. La tarea del desarrollador es configurar correctamente estos mecanismos de protección antes de su uso. Una vez hecho esto, la generación de tokens para proteger contra vulnerabilidades se producirá de forma automática.

A continuación, te mostraré cómo configurar la protección contra estos ataques en dos frameworks populares: Django y Laravel.

Protección CSRF Django

En Django, la protección contra ataques CSRF está activada por defecto mediante el middleware django.middleware.csrf.CsrfViewMiddleware, que ya aparece en la configuración estándar de MIDDLEWARE en settings.py.

No es necesario añadirlo manualmente en proyectos nuevos, pero verifica que no lo hayas eliminado si has personalizado la lista. Puedes consultar todos los detalles en la documentación oficial de Django sobre CSRF.

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Esta protección es necesaria siempre que la autenticación se base en cookies de sesión. En arquitecturas modernas con frontend separado (SPA o APIs), si se usan tokens enviados en cabeceras Authorization (no en cookies), el vector clásico de CSRF desaparece, ya que los navegadores no adjuntan automáticamente esos valores en peticiones cross-site.

Para más detalles sobre cómo proteger tus APIs, te recomiendo leer mi checklist para proteger el backend de vulnerabilidades comunes.

Protección CSRF Laravel

En Laravel, se genera automáticamente un token CSRF para cada sesión de usuario. Puedes obtenerlo mediante la función csrf_token() o a través de la sesión de la solicitud, tal como lo indica la documentación oficial de Laravel:

use Illuminate\Http\Request;

Route::get('/token', function (Request $request) {
    $token = $request->session()->token();

    $token = csrf_token();

    // ...
});

En aplicaciones modernas tipo SPA o APIs, Laravel y otros frameworks suelen usar un patrón cookie-a-header: el token se expone en una cookie accesible por JavaScript y luego se envía en una cabecera personalizada (por ejemplo X-CSRF-TOKEN) en cada petición AJAX o fetch, reforzando la protección frente a ataques CSRF en entornos sin formularios HTML clásicos.

Si el framework que utilizas carece de protección CSRF integrada, se recomienda utilizar módulos probados de proveedores reputados, como la biblioteca OWASP CSRFGuard. Además, configura las cookies de sesión con SameSite=Lax o Strict y HttpOnly/Secure siempre que sea posible para añadir una capa adicional de defensa frente a CSRF.

Puntos Clave para Evitar Ataques CSRF

  • CSRF es un tipo de ataque en el que un actor malicioso ejecuta acciones no autorizadas en nombre de un usuario autenticado en un sitio web. Un ejemplo de dicha acción es una transferencia de fondos al atacante.
  • El ataque se produce cuando un atacante envía solicitudes falsificadas en nombre del usuario. Esto es posible si el sitio web no verifica que la solicitud proviene genuinamente del usuario autenticado. A diferencia de los ataques XSS, CSRF no requiere la inyección de código en el sitio.
  • El principal método para contrarrestar estos ataques es la implementación de un token anti-CSRF.
  • Muchos frameworks ya implementan un mecanismo de protección basado en un token secreto. Estudia la documentación del framework que utilizas para el desarrollo y verifica la existencia de dicho mecanismo.

Categorizado en:

Desarrollo Web,