technical
Bloquea el clickjacking con frame-ancestors
MetricSpot busca X-Frame-Options o CSP frame-ancestors. Estas cabeceras impiden que un atacante embeba tu sitio en un iframe oculto para engañar al usuario.
Qué comprueba esta auditoría
Inspecciona las cabeceras de respuesta en busca de una de estas dos:
X-Frame-Options: DENYoX-Frame-Options: SAMEORIGINContent-Security-Policy: frame-ancestors 'none'oframe-ancestors 'self'
La comprobación falla cuando no hay ninguna y un atacante podría embeber tu página en un iframe oculto dentro de un sitio malicioso.
Por qué importa
El clickjacking es un ataque de “UI redress”: el atacante carga tu sitio en un iframe transparente sobre un botón aparentemente inocente (“¡iPad gratis! Haz clic”). El clic del usuario aterriza en realidad sobre un botón real dentro de tu iframe: enviando un pago, cambiando una contraseña, transfiriendo fondos.
- El ataque funciona contra cualquier sesión con login. Si el usuario está autenticado en tu sitio en otra pestaña, el iframe hereda las cookies de sesión, así que el clic se ejecuta como ese usuario.
- Se ha usado en la práctica contra bancos, redes sociales y paneles de admin. Se han visto ataques contra flujos OAuth y páginas de alta de 2FA.
- El parche es una sola cabecera. Los navegadores se niegan a renderizar tu página en un iframe cuando está la cabecera: el ataque deja de ser posible.
La protección anti-frame es la mitigación más barata de la seguridad web: una cabecera de respuesta por página, sin cambios de código y sin coste de rendimiento.
Cómo solucionarlo
Elige uno de los dos mecanismos. Los navegadores modernos prefieren frame-ancestors de CSP; X-Frame-Options es la cabecera legacy que también funciona en navegadores antiguos. Envía las dos para máxima cobertura: no entran en conflicto.
Denegar todo embebido (recomendado para sitios que no deben embeberse):
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
Permitir embebido solo desde tu propio origen:
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN
Permitir embebido desde orígenes concretos de confianza (solo CSP lo soporta; X-Frame-Options no admite varios dominios):
Content-Security-Policy: frame-ancestors 'self' https://partner.example.com
nginx:
add_header Content-Security-Policy "frame-ancestors 'none'" always;
add_header X-Frame-Options "DENY" always;
El flag always es crítico: sin él, nginx omite la cabecera en respuestas de error.
Apache:
Header always set Content-Security-Policy "frame-ancestors 'none'"
Header always set X-Frame-Options "DENY"
Caddy:
header {
Content-Security-Policy "frame-ancestors 'none'"
X-Frame-Options "DENY"
}
Cloudflare — Rules → Transform Rules → Modify Response Header, añade ambas cabeceras globalmente. O usa el producto Page Shield si quieres control a nivel WAF.
Next.js (next.config.js):
module.exports = {
async headers() {
return [
{
source: "/(.*)",
headers: [
{ key: "Content-Security-Policy", value: "frame-ancestors 'none'" },
{ key: "X-Frame-Options", value: "DENY" },
],
},
];
},
};
Express:
import helmet from "helmet";
app.use(helmet.frameguard({ action: "deny" }));
app.use(
helmet.contentSecurityPolicy({
directives: { frameAncestors: ["'none'"] },
})
);
Pruébalo:
curl -sI https://tudominio.com/ | grep -iE 'frame'
Espera las dos cabeceras, o al menos frame-ancestors. Luego intenta embeber en un iframe local para confirmar que el navegador se niega.
Preguntas frecuentes
¿Niego todo el embebido o solo permito el mismo origen?
Por defecto, frame-ancestors 'none' y solo relájalo si necesitas embeber tus páginas de forma activa. La mayoría de sitios de marketing, paneles de admin y aplicaciones nunca deberían ser embebidos, y los proveedores OAuth (Google, Apple, Stripe) que sí lo necesitan tienen flujos de embebido bien definidos que no requieren relajar tu CSP.
¿Y X-Frame-Options: ALLOW-FROM?
Está deprecado y no se soporta en Chrome ni en Firefox. Usa Content-Security-Policy: frame-ancestors en su lugar: acepta varios orígenes y funciona en todos los navegadores modernos.
¿Esto rompe Google PageSpeed Insights o alguna herramienta?
No. Esas herramientas piden la página directamente, no dentro de un iframe. La cabecera solo afecta al embebido en iframes.
Fuentes
Última actualización 2026-05-11