Clickjacking y X-Frame-Options: mantén tus páginas fuera de iframes
El clickjacking engaña a los usuarios para que hagan clic en controles ocultos de tu página, cargándola dentro de un iframe transparente en un sitio controlado por el atacante. X-Frame-Options — o la directiva moderna frame-ancestors de CSP — le dice a los navegadores que se nieguen a incrustar tu página, cerrando el ataque por completo.
Qué es
Un ataque de clickjacking funciona enmarcando tu sitio dentro de un iframe invisible o translúcido en la página del atacante. La víctima ve contenido señuelo y hace clic en lo que parece un botón inocente; el iframe oculto captura el clic real en tu página — una transferencia bancaria, un cambio de configuración, una autorización de OAuth — sin que el usuario lo note.
X-Frame-Options es un encabezado de respuesta HTTP con dos valores útiles: DENY (rechaza el enmarcado por parte de cualquiera) y SAMEORIGIN (solo permite el enmarcado desde páginas de tu propio origen). La directiva frame-ancestors de la CSP hace el mismo trabajo con más precisión — puedes listar orígenes de confianza específicos — y reemplaza a X-Frame-Options en los navegadores compatibles con CSP.
Por qué importa
Cualquier página con una acción significativa — configuración de cuenta, confirmación de pago, preferencias de email o un interruptor de administración — es un objetivo de clickjacking. Un usuario con sesión iniciada que caiga en una página maliciosa puede ser engañado para realizar acciones reales que nunca quiso, sin ninguna señal visible de que algo va mal.
Agregar X-Frame-Options no cuesta nada y lo admite todo navegador moderno. Omitirlo en páginas que ejecutan acciones sensibles es directamente un error de configuración, no una función faltante.
Cómo solucionarlo
Define el encabezado en next.config.js para que se aplique a todas las rutas. DENY es el valor predeterminado seguro para apps que no necesitan incrustarse.
// next.config.js
module.exports = {
async headers() {
return [
{
source: "/:path*",
headers: [{ key: "X-Frame-Options", value: "DENY" }],
},
];
},
};La directiva frame-ancestors de la CSP reemplaza a X-Frame-Options en los navegadores modernos y te da control por origen. Agrégala al encabezado Content-Security-Policy que ya defines.
// extend your existing CSP string
const csp = [
// ... your other directives ...
"frame-ancestors 'none'",
].join("; ");Si incrustas páginas legítimamente en tu propio sitio — un iframe de vista previa o un widget incrustado en el mismo origen — usa X-Frame-Options: SAMEORIGIN en lugar de DENY, o frame-ancestors 'self'.
Si sirves las respuestas a través de un proxy nginx, agrega el encabezado en tu bloque server.
add_header X-Frame-Options "DENY" always;Preguntas frecuentes
¿X-Frame-Options o frame-ancestors de CSP? ¿Cuál debería usar?
Usa ambos. X-Frame-Options cubre los navegadores antiguos; frame-ancestors en la CSP te da granularidad por origen y es el estándar moderno. Conviven sin problemas: los navegadores compatibles con CSP usan frame-ancestors e ignoran X-Frame-Options.
¿DENY rompe la incrustación de mis propios widgets o dashboards de analítica?
Sí: DENY bloquea todo enmarcado, incluido tu propio origen. Si necesitas incrustar una página específica en un iframe de tu propio dominio, usa SAMEORIGIN o frame-ancestors 'self'. Aflójalo solo en las páginas que de verdad necesitan incrustarse.
¿Qué severidad reporta AppSafe por la ausencia de X-Frame-Options?
Media. No es un vector de robo de datos inmediato por sí solo, pero cualquier página que ejecute acciones de cuenta corre un riesgo real de clickjacking sin él.
¿Tu app está afectada?
AppSafe verifica este y docenas de problemas más en un solo escaneo gratis.
Escanear mi app gratisGuías relacionadas
Content-Security-Policy (CSP): qué es y cómo agregarla
El encabezado que impide que se ejecuten scripts inyectados.
Las marcas de cookies Secure, HttpOnly y SameSite
Tres marcas que evitan que te roben las cookies de sesión.
CORS mal configurado: las trampas del comodín y del reflejo
Permite todos los orígenes y cualquier sitio podrá leer tu API.