Passkeys in iFrames

Um eine reibungslose, kontextbezogene Authentifizierung über mehrere Domains hinweg zu ermöglichen, betten Organisationen Anmeldeseiten häufig in iFrames ein. Wenn Authentifizierungskontexte jedoch in Frames von Drittanbietern geladen werden, sind Nutzer kritischen Bedrohungen wie Clickjacking (UI-Redressing) und der unbefugten Erstellung von Anmeldedaten ausgesetzt. Um diese Risiken zu minimieren, deaktivieren Browser WebAuthn in ursprungsübergreifenden iFrames standardmäßig. Um diese Einschränkung sicher aufzuheben, sind aktive Defense-in-Depth-Protokolle erforderlich.

Bedrohungsmodelle identifizieren

Bevor Sie Passkeys (WebAuthn) in Unterframes aktivieren, sollten Sie sich mit den Missbrauchsszenarien vertraut machen, gegen die Sie sich schützen möchten:

  • Tracking durch Einfügen eines verborgenen iFrames:Ein Angreifer löst über eine Anzeige oder ein Widget auf einer vertrauenswürdigen Website einen WebAuthn-Prompt von seiner eigenen Domain aus und bringt Nutzer so dazu, einen Passkey zu autorisieren, ohne den Kontext zu sehen. Dadurch wird die Identität des Nutzers mit einem vom Angreifer kontrollierten Konto verknüpft, um Daten zu sammeln.
  • Visuelles Overlay und Clickjacking (UI-Redressing): Auf einer schädlichen übergeordneten Seite wird der Authentifizierungs-iFrame mit Standard-CSS unsichtbar gemacht und ein gefälschtes UI-Element überlagert, um einen Klick zu stehlen, der einen Authentifizierungsablauf auslöst. Dies kann zu Session-Hijacking oder erzwungenen unbefugten Aktionen führen, wenn der Nutzer den Prompt versehentlich abschließt.

So können Sie diesen Bedrohungen entgegenwirken:

Für das Dokument der obersten Ebene (Top-Frame):

Für das eingebettete Dokument (iFrame):

Für beide Dokumente gilt:

Delegierung mit der Berechtigungsrichtlinie aktivieren

Browser blockieren standardmäßig den Zugriff auf WebAuthn in ursprungsübergreifenden iFrames. Die Permissions Policy ist der einheitliche Mechanismus der Webplattform, mit dem ein Dokument der obersten Ebene diese leistungsstarken Funktionen explizit an bestimmte, vertrauenswürdige Drittanbieterursprünge delegieren kann.

Funktionstokens

WebAuthn verwendet zwei verschiedene Tokens:

  • publickey-credentials-get: Gewährt die Autorisierung für die Anmeldung mit Passkeys (navigator.credentials.get()).
  • publickey-credentials-create: Gewährt die Autorisierung für die Registrierung von Passkeys (navigator.credentials.create()).

Voraussetzungen für die Aktivierung

Wenn Sie diese Funktionen aktivieren möchten, müssen Sie sowohl die Antwort des übergeordneten Servers als auch das clientseitige Markup anpassen:

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

Berechtigungsrichtlinie: Kompatibilität von publickey-credentials-get:

Browser Support

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

Source

Berechtigungsrichtlinie: Kompatibilität von publickey-credentials-create:

Browser Support

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

Source

  • Das HTML-Attribut allow:Im HTML-Markup muss das <iframe>-Element auch deklarieren, dass es die Funktion aktiviert.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>

Kompatibilität von iFrame mit allow="publickey-credentials-get":

Browser Support

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

Kompatibilität von iFrame mit allow="publickey-credentials-create":

Browser Support

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

Partitionierte Drittanbieter-Cookies aktivieren

Damit der Authentifizierungsablauf zuverlässig ist, muss eine Sitzung im eingebetteten iframe mit ursprungsübergreifendem Zugriff eingerichtet und aufrechterhalten werden. Da moderne Browser auf strenge Einschränkungen für Drittanbieter-Cookies umgestellt haben, werden standardmäßige Persistenzmechanismen oft standardmäßig blockiert. Möglicherweise muss die Storage Access API aufgerufen werden, um Zugriff zu erhalten.

Um diese Hindernisse zu umgehen, konfigurieren Sie Ihre Sitzungscookies mit den Attributen SameSite: None, Secure und Partitioned. Dieser einheitliche Plattformmechanismus sorgt für einen persistenten Status im iFrame und berücksichtigt gleichzeitig die Datenschutzeinstellungen auf Browserebene.

SameSite: None festlegen

SameSite: None kennzeichnet ein Cookie explizit für den websiteübergreifenden Zugriff, sodass es mit Anfragen gesendet werden kann, die aus einem Drittanbieterkontext (z. B. einem iFrame) stammen. Dieses Attribut ist eine Voraussetzung dafür, dass Cookies in Cross-Origin-Szenarien funktionieren. Es muss jedoch mit dem Attribut Secure kombiniert werden, damit es von modernen Browsern akzeptiert wird.

Partitioned festlegen

Mit dem Attribut Partitioned wird das Cookie für CHIPS (Cookies Having Independent Partitioned State) aktiviert. Dadurch kann das Cookie für jede Top-Level-Website separat gespeichert werden. So bleibt das Cookie im Kontext des jeweiligen Drittanbieter-iFrames zugänglich und der Sitzungsstatus kann beibehalten werden, ohne dass websiteübergreifendes Tracking aktiviert werden muss. Der Nutzer muss sich für jedes Einbettungselement auf einer anderen Website noch einmal anmelden.

Endpunkt mit Content Security Policy schützen

Während mit der Permissions Policy festgelegt wird, ob in Ihrem iFrame WebAuthn ausgeführt werden kann, wird mit der Content Security Policy (CSP) festgelegt, wer Ihr iFrame hosten darf.

Bei einem Authentifizierungsendpunkt ist es entscheidend, dass nur autorisierte Partnerwebsites oder Ihre eigenen Properties den Anmelde-Subframe laden können. Dadurch werden nicht autorisierte Clickjacking-Versuche unterbunden, bevor die Benutzeroberfläche überhaupt geladen werden kann.

frame-ancestors“ verwenden

Mit der frame-ancestors-Anweisung werden die gültigen übergeordneten Seiten definiert, auf denen Ihre Website eingebettet werden kann. Wenn Sie dieser Direktive Domains hinzufügen, können Sie die Domains zulassen, die den Anmelde-Subframe einbetten dürfen.

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

Content Security Policy: frame-ancestors compatibility (Content Security Policy: frame-ancestors-Kompatibilität):

Browser Support

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

Source

X-Frame-Options festlegen

Der alte X-Frame-Options-Header bietet ähnliche Funktionen, unterstützt aber nur binäre Optionen (DENY oder SAMEORIGIN). Legen Sie sowohl CSP frame-ancestors als auch X-Frame-Options: DENY fest, falls der Browser CSP nicht unterstützt. CSP hat immer Priorität, sofern es unterstützt wird.

X-Frame-Options: DENY

Kompatibilität mit X-Frame-Options:

Browser Support

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

Source

Serverseitig prüfen

Bei den clientseitigen Prüfungen des Browsers werden Absicht und Berechtigungen ausgewertet, aber der Server ist der letztendliche Schiedsrichter für Vertrauen. Überprüfen Sie die Antwort auf dem Server der vertrauenden Partei (Relying Party, RP), um sicherzustellen, dass der Kontext gültig und signiert ist.

Clientdatennutzlast

WebAuthn-Clientdaten enthalten Parameter, die speziell dafür entwickelt wurden, den Kontext einer Anfrage zu überprüfen, die in einem iFrame gestellt wurde:

  • crossOrigin (boolesch): Gibt an, ob die WebAuthn API in einem ursprungsübergreifenden iFrame aufgerufen wurde. Wenn Ihre Architektur auf iFrames basiert, muss Ihr Server erzwingen, dass dieses Flag true ist.
  • topOrigin (String): Der Ursprung des Browsing-Kontexts der obersten Ebene (was in der Adressleiste des Browsers zu sehen ist). Der Server muss dies anhand einer Liste bekannter, autorisierter übergeordneter Ursprünge überprüfen.

Checkliste für die Bestätigung

So prüfen Sie die Authentifikatorantwort auf Ihrem Server:

  1. Parsen und decodieren Sie die signierte collectedClientData aus der Authentifikatorantwort.
  2. Prüfen Sie, ob type mit der Zeremonie (webauthn.get oder webauthn.create) übereinstimmt.
  3. Prüfen Sie die Anwesenheit und die Signatur des Nutzers.
  4. Wenn die Anfrage von einer iFrame-Struktur stammen sollte:
    • Erzwingen Sie crossOrigin === true.
    • Erzwingen Sie, dass topOrigin mit Ihrer autorisierten Liste von übergeordneten Quellen übereinstimmt.

Sitzungen mit postMessage() sicher einrichten

Damit eine Sitzung zuverlässig eingerichtet werden kann, muss das iFrame das Authentifizierungstoken über postMessage() an die übergeordnete Seite zurückgeben. So kann die übergeordnete Seite den Sitzungsstatus im eigenen Kontext verwalten.

Sicherer Workflow

So richten Sie eine sichere Sitzung ein:

  1. Achten Sie darauf, dass die src-URL des iFrames die Suchparameter nonce und origin enthält:
    • Verwenden Sie einen zufälligen Wert für nonce. Ein nonce dient als Sicherheitsüberprüfungstoken, um sicherzustellen, dass das vom iFrame empfangene Authentifizierungstoken der von der übergeordneten Seite initiierten Sitzung entspricht.
    • Verwenden Sie die Domain des übergeordneten Frames für origin. Mit dem Parameter origin wird der Ursprung der übergeordneten Seite angegeben. So kann der iFrame den autorisierten Kontext, in den er eingebettet wurde, sicher identifizieren.
  2. Das iFrame schließt die WebAuthn-Authentifizierung mit seinem eigenen Server ab.
  3. Der Iframe-Server gibt ein Token wie ein JWT aus, das die nonce enthält, und leitet zur übergeordneten Seite weiter.

    // 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. Die übergeordnete Seite wartet auf das message-Ereignis, validiert den Ursprung des Absenders und prüft das 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. Auf der übergeordneten Seite wird die Sitzung beibehalten, wenn das JWT erfolgreich überprüft wurde.

Sowohl der Absender als auch der Empfänger sind für die Sicherheit verantwortlich:

  • Absender (iFrame): Geben Sie beim Senden von Nachrichten immer einen strengen Zielursprung an (verwenden Sie niemals "*").
  • Der Empfänger (Elternteil): Überprüfen Sie beim Empfang von Nachrichten immer event.origin, um das Spoofing von Absendern zu verhindern.

Fazit

Die sichere Verwendung von iFrames hängt von der Permissions Policy für die Aktivierung, CSP für die Einschränkung, partitionierten Drittanbieter-Cookies für die Sitzungspersistenz, serverseitigen Überprüfung des Clientkontexts und kontextsensitiven Sitzungsübergabe mit postMessage() ab.

Weitere Informationen zu verwandten Themen finden Sie im Chrome-Entwicklerblog von Google und in der Dokumentation zur Chrome-Entwickleridentität.