El clickjacking te engaña para que pulses un botón de una página oculta bajo la que ves. Aquí tienes cómo funciona y cómo prevenirlo de forma fiable (sin pasos de ataque).
Qué se ataca
Cualquier cosa que sea "un clic, listo, y valioso".
| Objetivo probable | Por qué |
|---|---|
| Confirmar una transferencia/compra | Un clic mueve dinero |
| Cambio de configuración (visibilidad, apps conectadas) | Prepara un secuestro posterior o el acceso a datos |
| "Permitir" de OAuth / permisos | Aprueba en silencio la vinculación de una cuenta |
| Seguir / me gusta / publicar en redes | Se abusa para difusión y granjas de "me gusta" |
Por qué funciona
Los navegadores pueden cargar otro sitio en un iframe y apilarlo encima. El atacante hace ese iframe transparente (opacity 0), de modo que el usuario solo ve el señuelo de la interfaz colocado debajo. Cuando el usuario pulsa el "botón falso", el botón real superpuesto justo encima recibe el clic.
Se parece a CSRF, pero CSRF envía una solicitud por detrás, mientras que el clickjacking hace que el usuario opere la pantalla real: por eso los tokens CSRF por sí solos no lo detienen.
Caso real: el diálogo de permisos de un plugin del navegador (2008)
En octubre de 2008, Adobe publicó un aviso de seguridad (APSA08-08) sobre un problema de clickjacking que afectaba a varios navegadores. Según la prensa, superponiendo de forma invisible el diálogo de configuración de Flash Player, un sitio podía conseguir que el usuario le concediera acceso a la cámara y al micrófono sin darse cuenta. Adobe publicó versiones corregidas de Flash Player y, como solución provisional, recomendó elegir "denegar siempre" en el administrador de configuración.
La lección: los botones de transferencia no son el único objetivo. Cualquier pantalla en la que un solo clic entrega un permiso ("Permitir", "Aceptar", "Conectar") entra en juego. MITRE clasifica esta debilidad como CWE-1021 (Improper Restriction of Rendered UI Layers or Frames).
Defensa: no permitas que otros sitios incrusten el tuyo
Configura CSP frame-ancestors (lo más importante)
Añade Content-Security-Policy: frame-ancestors 'self' (solo tu propio origen puede enmarcarte). Si nadie necesita incrustarte, 'none' es lo más seguro. Lista dominios solo para los socios que permitas explícitamente.
Añade también X-Frame-Options (retrocompatible)
Para clientes antiguos, envía también X-Frame-Options: DENY (o SAMEORIGIN). Así cubres tanto navegadores antiguos como nuevos.
Añade un paso de confirmación en las acciones críticas
Protege las transferencias y las concesiones de permisos tras una reautenticación, un diálogo de confirmación o una comprobación de intención: así es más difícil forzarlas mediante una superposición silenciosa.
Marca las cookies de sesión como SameSite
SameSite=Lax/Strict frena el envío automático entre sitios. No resuelve el clickjacking por sí solo, pero debilita la clase más amplia de "acción iniciada desde otro sitio".
X-Frame-Options frente a CSP frame-ancestors
Los dos encabezados impiden que otros sitios incrusten el tuyo, pero difieren en los detalles.
| X-Frame-Options | CSP frame-ancestors | |
|---|---|---|
| Valores | DENY (bloquear todo) / SAMEORIGIN (solo el mismo origen) | 'none' / 'self' / una lista de dominios permitidos |
| Varios sitios autorizados a incrustar | No es posible (ALLOW-FROM no funciona en navegadores modernos) | Posible |
| Configurarlo con etiqueta meta | Sin efecto | Sin efecto |
| Cuando están los dos | Lo ignoran los navegadores compatibles | Tiene prioridad |
| Papel | Respaldo para navegadores antiguos | La defensa principal hoy |
Si envías los dos, mantén el mismo significado: combina frame-ancestors 'none' con DENY, y frame-ancestors 'self' con SAMEORIGIN.
Errores de configuración habituales
- Suponer que
default-srcde CSP lo cubre.frame-ancestorsno hereda dedefault-src. Incluso condefault-src 'none', la incrustación sigue permitida si no escribesframe-ancestors - Ponerlo en una etiqueta meta:
<meta http-equiv>no tiene efecto aquí, así que envíalo como encabezado de respuesta - Dejarlo como
Content-Security-Policy-Report-Only: eso solo informa de las infracciones y no bloquea la incrustación. Cambia al encabezado que aplica la política cuando hayas confirmado que funciona - Configurarlo solo en algunas páginas: se suele comprobar la portada y se olvidan la página de inicio de sesión, las de configuración o las de error. Comprueba también que un CDN o un proxy no esté eliminando el encabezado
Cómo comprobar tu propio sitio
Compruébalo con una herramienta de encabezados
Introduce la URL de tu sitio en el verificador de encabezados de seguridad y mira si se devuelven X-Frame-Options y frame-ancestors de CSP. No revises solo la portada: revisa también las páginas de configuración con sesión iniciada y las de transferencias o concesión de permisos.
Compruébalo en las herramientas de desarrollo del navegador
Recarga la página con la pestaña Red abierta y mira los encabezados de la respuesta HTML. Comprueba también que el encabezado no se envíe dos veces ni con valores contradictorios.
Configúralo en un solo lugar
Añadirlo a todas las respuestas desde un único punto (el servidor web, como nginx o Caddy, el proxy inverso o el framework) evita tanto los huecos como los duplicados. Si vas a escribir una CSP nueva, el generador de CSP puede montar una que incluya frame-ancestors.
La opinión de este sitio: una línea de encabezado es la corrección más eficaz, así que comprueba primero tu propio sitio
La defensa frente al clickjacking no es código complejo; son una o dos líneas de encabezado de respuesta que bloquean la incrustación. Aplícalas en todo el sitio desde el framework o el proxy inverso (Caddy/nginx) para que nada se cuele. El fallo más común es un encabezado que creías haber puesto pero que en realidad falta, así que, después de configurarlo, confirma con los pasos anteriores que de verdad se devuelve.
Fuentes (primarias)
- OWASP, "Clickjacking Defense Cheat Sheet" — cheatsheetseries.owasp.org (frame-ancestors, X-Frame-Options, SameSite; ALLOW-FROM ya no funciona; las etiquetas meta no tienen efecto; límites del frame-busting)
- MDN, "CSP: frame-ancestors" — developer.mozilla.org (valores admitidos, sin herencia de default-src, no admitido en meta)
- RFC 7034, "HTTP Header Field X-Frame-Options" — rfc-editor.org
- IPA, "How to Secure Your Web Site, 1.9 Clickjacking" (en japonés) — ipa.go.jp
- Adobe, "Security Advisory for Flash Player (APSA08-08)" (7 de octubre de 2008) — adobe.com
- Computerworld, "Clickjackers could hijack webcams, microphones, Adobe warns" (octubre de 2008) — computerworld.com (el objetivo era el diálogo de permisos de cámara y micrófono)
- MITRE, "CWE-1021: Improper Restriction of Rendered UI Layers or Frames" — cwe.mitre.org
Sigue leyendo
- Glosario: Qué es CSRF · Qué es XSS
- Guía: Elegir encabezados de seguridad (qué sigue haciendo falta y qué está obsoleto) (en inglés)
- Comprueba: Verificador de encabezados de seguridad · Generador de CSP