Passkey all'interno di iframe

Per fornire un'autenticazione fluida e contestuale su più domini, le organizzazioni spesso incorporano le pagine di accesso all'interno di iframe. Tuttavia, il caricamento dei contesti di autenticazione all'interno di frame di terze parti espone gli utenti a minacce critiche come il clickjacking (UI redressing) e la creazione non autorizzata di credenziali. Per mitigare questi rischi, i browser disattivano WebAuthn negli iframe multiorigine per impostazione predefinita. Per rimuovere in sicurezza questa limitazione sono necessari protocolli di difesa in profondità attivi.

Identificare i modelli di minaccia

Prima di attivare le passkey (WebAuthn) all'interno dei subframe, comprendi gli scenari di abuso da cui ti stai difendendo:

  • Monitoraggio tramite l'inserimento di iframe nascosti: un malintenzionato attiva una richiesta WebAuthn dal proprio dominio utilizzando un annuncio o un widget su un sito attendibile, inducendo gli utenti ad autorizzare una passkey senza vedere il contesto. In questo modo, l'identità dell'utente viene collegata a un account controllato da un malintenzionato per raccogliere dati.
  • Sovrapposizione visiva e clickjacking (UI redressing): una pagina principale dannosa rende invisibile l'iframe di autenticazione utilizzando CSS standard e sovrappone un elemento UI falso per rubare un clic che attiva un flusso di autenticazione. Ciò può comportare il dirottamento della sessione o azioni non autorizzate forzate se l'utente completa inavvertitamente il prompt.

Per contrastare queste minacce, segui queste best practice:

Per il documento di primo livello (frame superiore):

Per il documento incorporato (iframe):

Per entrambi i documenti:

Attivare la delega utilizzando Permissions Policy

Per impostazione predefinita, i browser bloccano l'accesso a WebAuthn negli iframe multiorigine. Permissions Policy è il meccanismo unificato della piattaforma web che consente a un documento di primo livello di delegare esplicitamente queste potenti funzionalità a origini di terze parti specifiche e attendibili.

Token delle funzionalità

WebAuthn utilizza due token distinti:

  • publickey-credentials-get: Concede l'autorizzazione per i flussi di accesso con passkey (navigator.credentials.get()).
  • publickey-credentials-create: Concede l'autorizzazione per i flussi di registrazione delle passkey (navigator.credentials.create()).

Requisiti per l'attivazione

L'attivazione di queste funzionalità richiede l'allineamento sia nella risposta del server principale sia nel markup lato client:

Permissions-Policy: publickey-credentials-get=(self "https://embedded-auth.example.com")

Norme relative alle autorizzazioni: compatibilità con publickey-credentials-get:

Browser Support

  • Chrome: 88.
  • Edge: 88.
  • Firefox: not supported.
  • Safari: not supported.

Source

Norme relative alle autorizzazioni: compatibilità con publickey-credentials-create:

Browser Support

  • Chrome: 88.
  • Edge: 88.
  • Firefox: not supported.
  • Safari: not supported.

Source

  • L'attributo HTML allow: nel markup HTML, l'elemento <iframe> deve anche dichiarare che attiva la funzionalità.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>

Compatibilità dell'iframe allow="publickey-credentials-get":

Browser Support

  • Chrome: 84.
  • Edge: 84.
  • Firefox: 118.
  • Safari: not supported.

Compatibilità dell'iframe allow="publickey-credentials-create":

Browser Support

  • Chrome: not supported.
  • Edge: not supported.
  • Firefox: 123.
  • Safari: not supported.

Attivare i cookie di terze parti partizionati

Per garantire un flusso di autenticazione affidabile, è necessario stabilire e mantenere una sessione all'interno dell'iframe multiorigine incorporato. Con il passaggio dei browser moderni a rigide restrizioni dei cookie di terze parti, i meccanismi di persistenza standard vengono spesso bloccati per impostazione predefinita e potrebbero richiedere la chiamata dell'API Storage Access per ottenere l'accesso.

Per mitigare questi ostacoli, configura i cookie di sessione con gli attributi SameSite: None, Secure e Partitioned. Questo meccanismo della piattaforma unificata garantisce uno stato persistente all'interno dell'iframe rispettando i controlli della privacy a livello di browser.

Imposta SameSite: None

SameSite: None contrassegna esplicitamente un cookie per l'accesso cross-site, consentendone l'invio con richieste effettuate da un contesto di terze parti (come un iframe). Questo attributo è un prerequisito per il funzionamento dei cookie in scenari multiorigine, anche se deve essere combinato con l'attributo Secure per essere accettato dai browser moderni.

Imposta Partitioned

L'attributo Partitioned attiva CHIPS (Cookies Having Independent Partitioned State), consentendo l'archiviazione separata del cookie per ogni sito di primo livello. In questo modo, il cookie rimane accessibile nel contesto specifico dell'iframe di terze parti, consentendo uno stato della sessione persistente senza abilitare il monitoraggio tra siti. L'utente dovrà accedere di nuovo per ogni incorporamento su un sito diverso.

Proteggere l'endpoint con Content Security Policy

Mentre Permissions Policy determina se l'iframe può eseguire WebAuthn, Content Security Policy (CSP) determina chi è autorizzato a ospitare l'iframe.

Per un endpoint di autenticazione, è fondamentale assicurarsi che solo i siti partner autorizzati o le tue proprietà possano caricare il subframe di accesso, impedendo tentativi di clickjacking non autorizzati prima ancora che possano caricare la UI.

Utilizza frame-ancestors

L'istruzione frame-ancestors definisce le pagine principali valide che possono incorporare il tuo sito. Aggiungendo domini a questa direttiva, puoi consentire ai domini autorizzati di incorporare il subframe di accesso.

Content-Security-Policy: frame-ancestors 'self' https://parent-site.example.com;

Content Security Policy: compatibilità con frame-ancestors:

Browser Support

  • Chrome: 40.
  • Edge: 15.
  • Firefox: 58.
  • Safari: 10.

Source

Imposta X-Frame-Options

L'intestazione X-Frame-Options legacy supporta una funzionalità simile, ma supporta solo opzioni binarie (DENY o SAMEORIGIN). Imposta sia CSP frame-ancestors sia X-Frame-Options: DENY nel caso in cui il browser non supporti CSP. CSP ha sempre la priorità dove è supportato.

X-Frame-Options: DENY

Compatibilità con X-Frame-Options:

Browser Support

  • Chrome: 4.
  • Edge: 12.
  • Firefox: 4.
  • Safari: 4.

Source

Attendibile con verifica lato server

I controlli lato client del browser valutano l'intento e le autorizzazioni, ma il server è l'arbitro finale dell'affidabilità. Verifica la risposta sul server Relying Party (RP) per assicurarti che il contesto sia valido e firmato.

Payload dei dati del cliente

I dati client WebAuthn includono parametri progettati specificamente per aiutarti a verificare il contesto di una richiesta effettuata all'interno di un iframe:

  • crossOrigin (booleano): indica se l'API WebAuthn è stata richiamata all'interno di un iframe multiorigine. Se la tua architettura si basa sugli iframe, il server deve imporre che questo flag sia true.
  • topOrigin (stringa): l'origine del contesto di navigazione di primo livello (ciò che è visibile nella barra degli indirizzi del browser). Il server deve verificare questo valore rispetto a un elenco di origini principali autorizzate note.

Elenco di controllo per la verifica

Per verificare la risposta dell'autenticatore sul server:

  1. Analizza e decodifica il collectedClientData firmato dalla risposta dell'autenticatore.
  2. Assicurati che type corrisponda alla cerimonia (webauthn.get o webauthn.create).
  3. Verifica la presenza e la firma dell'utente.
  4. Se la richiesta doveva provenire da una struttura iframe:
    • Applica crossOrigin === true.
    • Forza la corrispondenza di topOrigin con l'elenco autorizzato di origini principali.

Stabilire sessioni in modo sicuro utilizzando postMessage()

Per stabilire una sessione in modo affidabile, l'iframe deve trasmettere il token di autenticazione alla pagina principale utilizzando postMessage(), consentendo alla pagina principale di gestire lo stato della sessione nel proprio contesto proprietario.

Workflow sicuro

Per stabilire una sessione sicura:

  1. Assicurati che l'URL dell'iframe src contenga i parametri di query nonce e origin:
    • Utilizza un valore casuale per nonce. Un nonce funge da token di verifica della sicurezza per garantire che il token di autenticazione ricevuto da un iframe corrisponda legittimamente alla sessione specifica avviata dalla pagina principale.
    • Utilizza il dominio del frame principale per origin. Un parametro origin specifica l'origine della pagina principale, consentendo all'iframe di identificare in modo sicuro il contesto autorizzato in cui è stato incorporato.
  2. L'iframe completa l'autenticazione WebAuthn con il proprio server.
  3. Il server iframe emette un token, ad esempio un JWT che include nonce e lo inoltra alla pagina principale.

    // 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);
    
  4. La pagina principale rimane in ascolto dell'evento message, convalida l'origine del mittente e verifica il 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,
      });
    });
    
  5. La pagina principale mantiene la sessione se il JWT viene verificato correttamente.

Il mittente e il destinatario condividono le responsabilità in materia di sicurezza:

  • Il mittente (iframe): specifica sempre un'origine di destinazione rigorosa quando invii messaggi (non utilizzare mai "*").
  • Il destinatario (genitore): verifica sempre event.origin quando ricevi messaggi per evitare lo spoofing dell'origine.

Conclusione

L'utilizzo di iframe sicuri dipende dalla Permissions Policy per l'attivazione, dalla CSP per la limitazione, dai cookie di terze parti partizionati per la persistenza della sessione, dalla verifica lato server del contesto client e dal trasferimento della sessione sensibile al contesto tramite postMessage().

Per saperne di più sugli argomenti correlati, segui il blog per sviluppatori di Chrome di Google ed esplora altre risorse nella documentazione sull'identità dello sviluppatore di Chrome.