Para proporcionar una autenticación fluida y contextual en varios dominios, las organizaciones suelen incorporar páginas de acceso en elementos iframe. Sin embargo, cargar contextos de autenticación dentro de marcos de terceros expone a los usuarios a amenazas críticas, como el clickjacking (suplantación de la IU) y la creación no autorizada de credenciales. Para mitigar estos riesgos, los navegadores inhabilitan WebAuthn en los elementos iframe de origen cruzado de forma predeterminada. Para levantar esta restricción de forma segura, se requieren protocolos activos de defensa en profundidad.
Identifica modelos de amenazas
Antes de habilitar las llaves de acceso (WebAuthn) dentro de los submarcos, comprende las situaciones de abuso contra las que te defiendes:
- Seguimiento con la inserción de un iframe oculto: Un atacante activa un mensaje de WebAuthn desde su propio dominio con un anuncio o widget en un sitio de confianza, lo que engaña a los usuarios para que autoricen una llave de acceso sin ver el contexto. Esto vincula la identidad del usuario a una cuenta controlada por el atacante para recopilar datos.
- Superposición visual y clickjacking (revestimiento de la IU): Una página principal maliciosa renderiza el iframe de autenticación invisible con CSS estándar y superpone un elemento de IU falso para robar un clic que activa un flujo de autenticación. Esto puede provocar el secuestro de la sesión o acciones no autorizadas forzadas si el usuario completa la instrucción sin querer.
Para contrarrestar estas amenazas, sigue estas prácticas recomendadas:
Para el documento de nivel superior (marco superior):
Para el documento incorporado (iframe):
- Habilita las cookies de terceros particionadas
- Protege el extremo con la Política de Seguridad del Contenido
- Confía, pero verifica en el servidor
Para ambos documentos:
Habilita la delegación con la Política de permisos
De forma predeterminada, los navegadores bloquean el acceso a WebAuthn en iframes de origen cruzado. La Política de permisos es el mecanismo unificado de la plataforma web que permite que un documento de nivel superior delegue de forma explícita estas potentes capacidades a orígenes de terceros específicos y confiables.
Tokens de funciones
WebAuthn usa dos tokens distintos:
publickey-credentials-get: Otorga autorización para los flujos de acceso con llave de acceso (navigator.credentials.get()).publickey-credentials-create: Otorga autorización para los flujos de registro de llaves de acceso (navigator.credentials.create()).
Requisitos para habilitar la función
Para habilitar estas capacidades, se requiere alineación tanto en la respuesta del servidor principal como en el lenguaje de marcado del cliente:
- Encabezado de respuesta HTTP de Permissions-Policy (sitio del servidor principal): La página principal debe declarar los orígenes permitidos en sus encabezados de respuesta HTTP con la sintaxis de campos estructurados.
Permissions-Policy: publickey-credentials-get=(self "https://embedded-auth.example.com")
Política de Permisos: Compatibilidad con publickey-credentials-get:
Política de Permisos: Compatibilidad con publickey-credentials-create:
- El atributo
allowde HTML: En el lenguaje de marcado HTML, el elemento<iframe>también debe declarar que habilita la función.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>
Compatibilidad con iframe allow="publickey-credentials-get":
Browser Support
Compatibilidad con iframe allow="publickey-credentials-create":
Browser Support
Habilita las cookies de terceros particionadas
Para garantizar un flujo de autenticación confiable, se debe establecer y mantener una sesión dentro del iframe incorporado de origen cruzado. A medida que los navegadores modernos pasaron a tener restricciones estrictas para las cookies de terceros, los mecanismos de persistencia estándar suelen bloquearse de forma predeterminada y es posible que debas llamar a la API de Storage Access para obtener acceso.
Para mitigar estos obstáculos, configura tus cookies de sesión con los atributos SameSite:
None, Secure y Partitioned. Este mecanismo de plataforma unificada garantiza un estado persistente dentro del iframe y, al mismo tiempo, respeta los controles de privacidad a nivel del navegador.
Conjunto SameSite: None
SameSite:
None
marca explícitamente una cookie para el acceso entre sitios, lo que permite que se envíe con solicitudes realizadas desde un contexto de terceros (como un iframe). Este atributo es un requisito previo para que las cookies funcionen en situaciones de varios orígenes, aunque debe combinarse con el atributo Secure para que los navegadores modernos lo acepten.
Conjunto Partitioned
El atributo Partitioned habilita la cookie para CHIPS (Cookies Having Independent Partitioned State), lo que permite que la cookie se almacene por separado para cada sitio de nivel superior. Esto garantiza que la cookie siga siendo accesible dentro del contexto específico del iframe de terceros, lo que permite un estado de sesión persistente sin habilitar el seguimiento entre sitios. El usuario deberá volver a acceder a cada incorporación en un sitio diferente.
Protege el endpoint con la Política de Seguridad del Contenido
Si bien la Política de Permisos determina si tu iframe puede ejecutar WebAuthn, la Política de Seguridad del Contenido (CSP) determina quién puede alojar tu iframe.
En el caso de un endpoint de autenticación, es fundamental garantizar que solo los sitios de socios autorizados o tus propias propiedades puedan cargar el submarco de inicio de sesión, lo que detiene los intentos de clickjacking no autorizados antes de que puedan cargar la IU.
Usa frame-ancestors
La directivaframe-ancestors define las páginas principales válidas que pueden incorporar tu sitio. Si agregas dominios a esta directiva, puedes permitir los dominios que pueden incorporar el submarco de inicio de sesión.
Content-Security-Policy: frame-ancestors 'self' https://parent-site.example.com;
Política de seguridad del contenido: Compatibilidad con frame-ancestors:
Conjunto X-Frame-Options
El encabezado X-Frame-Options heredado admite una capacidad similar, pero solo admite opciones binarias (DENY o SAMEORIGIN). Establece CSP frame-ancestors y X-Frame-Options: DENY en caso de que el navegador no admita CSP. El CSP siempre tiene prioridad cuando se admite.
X-Frame-Options: DENY
Compatibilidad con X-Frame-Options:
Confía, pero verifica en el servidor
Las verificaciones del cliente del navegador evalúan la intención y los permisos, pero el servidor es el árbitro final de la confianza. Verifica la respuesta en el servidor de la parte que confía (RP) para asegurarte de que el contexto sea válido y esté firmado.
Carga útil de datos del cliente
Los datos del cliente de WebAuthn incluyen parámetros diseñados específicamente para ayudarte a verificar el contexto de una solicitud realizada dentro de un iframe:
crossOrigin(booleano): Indica si se invocó la API de WebAuthn dentro de un iframe de origen cruzado. Si tu arquitectura depende de los elementos iframe, tu servidor debe aplicar que esta marca seatrue.topOrigin(cadena): Es el origen del contexto de navegación de nivel superior (lo que se ve en la barra de direcciones del navegador). El servidor debe verificar esto en una lista de orígenes principales conocidos y autorizados.
Lista de verificación
Para verificar la respuesta del autenticador en tu servidor, sigue estos pasos:
- Analiza y decodifica el
collectedClientDatafirmado de la respuesta del autenticador. - Asegúrate de que
typecoincida con la ceremonia (webauthn.getowebauthn.create). - Verifica la presencia y la firma del usuario.
- Si la solicitud se envió desde una estructura de iframe, haz lo siguiente:
- Aplica
crossOrigin === true. - Asegúrate de que
topOrigincoincida con tu lista autorizada de orígenes principales.
- Aplica
Establece sesiones de forma segura con postMessage()
Para establecer una sesión de forma confiable, el iframe debe pasar el token de autenticación a la página principal con postMessage(), lo que permite que la página principal administre el estado de la sesión en su propio contexto propio.
Flujo de trabajo seguro
Para establecer una sesión segura, sigue este flujo de trabajo:
- Asegúrate de que la URL del iframe
srccontenga los parámetros de consultanonceyorigin:- Usa un valor aleatorio para
nonce. Unnoncefunciona como un token de verificación de seguridad para garantizar que el token de autenticación recibido de un iframe coincida de forma legítima con la sesión específica que inició la página principal. - Usa el dominio del iframe principal para
origin. Un parámetrooriginespecifica el origen de la página principal, lo que permite que el iframe identifique de forma segura el contexto autorizado en el que se incorporó.
- Usa un valor aleatorio para
- El iframe completa la autenticación de WebAuthn con su propio servidor.
El servidor de iframe emite un token, como un JWT, que incluye el
noncey reenvía a la página principal.// Extract nonce and origin from the URL params const urlParams = new URLSearchParams(window.location.search); const nonce = urlParams.get('nonce'); const origin = urlParams.get('origin'); if (!nonce || !origin) { alert('Nonce or origin is missing in the URL'); return; } // Create a JWT const response = await post('/createToken', { nonce, origin }); const token = response.token; // Post the JWT to the parent frame window.parent.postMessage({ token }, origin);La página superior escucha el evento
message, valida el origen del remitente y verifica el token.window.addEventListener("message", (event) => { if (event.origin !== "https://embedded-auth.example.com") return; // Verify the received JWT const result = await post('/verifyIdToken', { token: event.data.token, origin: provider.origin, }); });La página principal conserva la sesión si el JWT se verifica correctamente.
El remitente y el destinatario comparten responsabilidades de seguridad:
- El remitente (iframe): Siempre especifica un origen de destino estricto cuando envíes mensajes (nunca uses
"*"). - El receptor (elemento superior): Siempre verifica
event.origincuando recibas mensajes para evitar la suplantación de origen.
Conclusión
El uso seguro de iframe depende de la Política de permisos para la habilitación, la CSP para la restricción, las cookies de terceros particionadas para la persistencia de la sesión, la verificación del servidor del contexto del cliente y la transferencia de sesión adaptada al contexto con postMessage().
Para obtener más información sobre temas relacionados, sigue el blog para desarrolladores de Chrome de Google y explora más recursos en la documentación sobre la identidad del desarrollador de Chrome.