Klucze dostępu w elementach iframe

Aby zapewnić płynne uwierzytelnianie w kontekście w wielu domenach, organizacje często umieszczają strony logowania w ramkach iframe. Jednak wczytywanie kontekstów uwierzytelniania w ramkach innych firm naraża użytkowników na poważne zagrożenia, takie jak clickjacking (przekierowanie interfejsu) i nieautoryzowane tworzenie danych logowania. Aby ograniczyć to ryzyko, przeglądarki domyślnie wyłączają WebAuthn w elementach iframe z innych domen. Bezpieczne zniesienie tego ograniczenia wymaga aktywnych protokołów obrony warstwowej.

Identyfikowanie modeli zagrożeń

Zanim włączysz klucze dostępu (WebAuthn) w ramkach podrzędnych, zapoznaj się ze scenariuszami nadużyć, przed którymi chcesz się chronić:

  • Śledzenie za pomocą wstrzykiwania ukrytego elementu iframe: atakujący wywołuje prośbę WebAuthn z własnej domeny za pomocą reklamy lub widżetu w zaufanej witrynie, nakłaniając użytkowników do autoryzacji klucza dostępu bez znajomości kontekstu. Powoduje to powiązanie tożsamości użytkownika z kontem kontrolowanym przez atakującego, co umożliwia zbieranie danych.
  • Nakładka wizualna i clickjacking (przekształcanie interfejsu): złośliwa strona nadrzędna renderuje ramkę iframe uwierzytelniania jako niewidoczną za pomocą standardowego CSS-u i nakłada na nią fałszywy element interfejsu, aby przechwycić kliknięcie, które uruchamia przepływ uwierzytelniania. Jeśli użytkownik nieumyślnie wykona prompt, może to doprowadzić do przejęcia sesji lub wymuszenia nieautoryzowanych działań.

Aby przeciwdziałać tym zagrożeniom, stosuj te sprawdzone metody:

W przypadku dokumentu najwyższego poziomu (głównej ramki):

W przypadku dokumentu umieszczonego (element iframe):

W przypadku obu dokumentów:

Włączanie przekazywania uprawnień za pomocą zasad uprawnień

Przeglądarki domyślnie blokują dostęp do WebAuthn w międzyźródłowych elementach iframe. Permissions Policy to ujednolicony mechanizm platformy internetowej, który umożliwia dokumentowi najwyższego poziomu wyraźne przekazywanie tych zaawansowanych funkcji określonym, zaufanym źródłom zewnętrznym.

Tokeny funkcji

WebAuthn używa 2 rodzajów tokenów:

  • publickey-credentials-get: przyznaje autoryzację w przypadku logowania za pomocą klucza dostępu (navigator.credentials.get()).
  • publickey-credentials-create: przyznaje autoryzację w przypadku przepływów rejestracji klucza dostępu (navigator.credentials.create()).

Wymagania dotyczące włączania

Włączenie tych funkcji wymaga zgodności zarówno w odpowiedzi serwera nadrzędnego, jak i w kodzie po stronie klienta:

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

Zasady dotyczące uprawnień: zgodność interfejsu publickey-credentials-get:

Browser Support

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

Source

Zasady dotyczące uprawnień: zgodność z publickey-credentials-create:

Browser Support

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

Source

  • Atrybut HTML allow: w znaczniku HTML element <iframe> musi też deklarować, że włącza tę funkcję.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>

Zgodność elementu iframe z atrybutem allow="publickey-credentials-get":

Browser Support

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

Zgodność elementu iframe z atrybutem allow="publickey-credentials-create":

Browser Support

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

Włączanie partycjonowanych plików cookie innych firm

Aby zapewnić niezawodny proces uwierzytelniania, w osadzonym elemencie iframe z innej domeny musi zostać utworzona i utrzymana sesja. W miarę jak nowoczesne przeglądarki przechodzą na rygorystyczne ograniczenia dotyczące plików cookie innych firm, standardowe mechanizmy utrwalania są często domyślnie blokowane i mogą wymagać wywołania interfejsu Storage Access API, aby uzyskać dostęp.

Aby uniknąć tych problemów, skonfiguruj pliki cookie sesji za pomocą atrybutów SameSite: None, SecurePartitioned. Ten ujednolicony mechanizm platformy zapewnia trwały stan w ramach elementu iframe przy jednoczesnym poszanowaniu ustawień prywatności na poziomie przeglądarki.

Zestaw SameSite: None

SameSite: None wyraźnie oznacza plik cookie jako dostępny w wielu witrynach, co umożliwia wysyłanie go z żądaniami pochodzącymi z kontekstu innej firmy (np. z elementu iframe). Ten atrybut jest warunkiem wstępnym działania plików cookie w scenariuszach obejmujących różne domeny, ale musi być połączony z atrybutem Secure, aby był akceptowany przez nowoczesne przeglądarki.

Zestaw Partitioned

Atrybut Partitioned włącza plik cookie w technologii CHIPS (Cookies Having Independent Partitioned State), dzięki czemu plik cookie jest przechowywany oddzielnie dla każdej witryny najwyższego poziomu. Dzięki temu plik cookie pozostaje dostępny w konkretnym kontekście elementu iframe innej firmy, co umożliwia utrzymanie stanu sesji bez włączania śledzenia w witrynach. Użytkownik będzie musiał zalogować się ponownie w przypadku każdego osadzenia w innej witrynie.

Ochrona punktu końcowego za pomocą standardu Content Security Policy

Zasady dotyczące uprawnień określają, czy element iframe może uruchamiać WebAuthn, a Content Security Policy (CSP) określają, kto może hostować element iframe.

W przypadku punktu końcowego uwierzytelniania kluczowe jest zapewnienie, że tylko autoryzowane witryny partnerów lub Twoje własne usługi mogą wczytywać ramkę podrzędną logowania. Dzięki temu można zapobiegać nieautoryzowanym próbom klikania w celu oszustwa, zanim jeszcze wczyta się interfejs.

Używaj funkcji frame-ancestors

frame-ancestorsDyrektywa określa prawidłowe strony nadrzędne, które mogą osadzać Twoją witrynę. Dodając domeny do tej dyrektywy, możesz zezwolić na domeny, które mogą osadzać ramkę podrzędną logowania.

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

Zgodność z zasadami Content Security Policy: frame-ancestors:

Browser Support

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

Source

Zestaw X-Frame-Options

Starszy nagłówek X-Frame-Options obsługuje podobne funkcje, ale tylko opcje binarne (DENY lub SAMEORIGIN). Ustaw oba nagłówki CSP frame-ancestorsX-Frame-Options: DENY na wypadek, gdyby przeglądarka nie obsługiwała CSP. CSP jest zawsze traktowany priorytetowo, jeśli jest obsługiwany.

X-Frame-Options: DENY

Zgodność z X-Frame-Options:

Browser Support

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

Source

Zaufaj, ale weryfikuj po stronie serwera

Sprawdzanie po stronie klienta w przeglądarce ocenia intencje i uprawnienia, ale ostatecznym arbitrem zaufania jest serwer. Sprawdź odpowiedź na serwerze Relying Party (RP), aby upewnić się, że kontekst jest prawidłowy i podpisany.

Ładunek danych klienta

Dane klienta WebAuthn zawierają parametry zaprojektowane specjalnie po to, aby pomóc Ci w weryfikacji kontekstu żądania wysłanego w ramce iframe:

  • crossOrigin (boolean): wskazuje, czy interfejs WebAuthn API został wywołany w ramce iframe z innej domeny. Jeśli Twoja architektura opiera się na elementach iframe, serwer musi wymuszać, aby ten flag był ustawiony na true.
  • topOrigin (string): pochodzenie kontekstu przeglądania najwyższego poziomu (to, co jest widoczne na pasku adresu przeglądarki). Serwer musi zweryfikować ten element na podstawie listy znanych, autoryzowanych domen nadrzędnych.

Lista kontrolna weryfikacji

Aby zweryfikować odpowiedź uwierzytelniania na serwerze, wykonaj te czynności:

  1. Przeanalizuj i zdekoduj podpisany obiekt collectedClientData z odpowiedzi uwierzytelniania.
  2. Upewnij się, że type pasuje do ceremonii (webauthn.get lub webauthn.create).
  3. Sprawdź obecność użytkownika i jego podpis.
  4. Jeśli żądanie miało pochodzić ze struktury elementu iframe:
    • Wymuś crossOrigin === true.
    • Wymuszaj, aby topOrigin pasowało do autoryzowanej listy źródeł nadrzędnych.

Bezpieczne nawiązywanie sesji za pomocą postMessage()

Aby niezawodnie utworzyć sesję, element iframe musi przekazać token uwierzytelniania z powrotem do strony nadrzędnej za pomocą funkcji postMessage(), umożliwiając stronie nadrzędnej zarządzanie stanem sesji w kontekście własnych danych.

Bezpieczny przepływ pracy

Aby nawiązać bezpieczną sesję, wykonaj te czynności:

  1. Sprawdź, czy adres URL elementu iframe src zawiera parametry zapytania nonceorigin:
    • Użyj losowej wartości w przypadku parametru nonce. nonce pełni funkcję tokena weryfikacji bezpieczeństwa, który zapewnia, że token uwierzytelniania otrzymany z elementu iframe jest zgodny z sesją zainicjowaną przez stronę nadrzędną.
    • Użyj domeny ramki nadrzędnej dla parametru origin. Parametr origin określa źródło strony nadrzędnej, co umożliwia elementowi iframe bezpieczne zidentyfikowanie autoryzowanego kontekstu, w którym został umieszczony.
  2. Element iframe przeprowadza uwierzytelnianie WebAuthn na własnym serwerze.
  3. Serwer elementu iframe wydaje token, np. JWT, który zawiera nonce, i przekazuje go na stronę nadrzędną.

    // 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. Strona nadrzędna nasłuchuje zdarzenia message, sprawdza pochodzenie nadawcy i weryfikuje 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. Strona nadrzędna zachowuje sesję, jeśli token JWT zostanie zweryfikowany.

Nadawca i odbiorca ponoszą wspólną odpowiedzialność za bezpieczeństwo:

  • Nadawca (element iframe): podczas wysyłania wiadomości zawsze podawaj dokładny docelowy adres pochodzenia (nigdy nie używaj "*").
  • Odbiorca (rodzic): zawsze weryfikuj event.origin podczas odbierania wiadomości, aby zapobiec podszywaniu się pod nadawcę.

Podsumowanie

Bezpieczne używanie elementu iframe zależy od włączenia za pomocą zasady uprawnień, ograniczenia za pomocą CSP, podzielonych plików cookie innych firm w celu zachowania sesji, weryfikacji po stronie serwera kontekstu klienta i przekazywania sesji z uwzględnieniem kontekstu za pomocą postMessage().

Więcej informacji na powiązane tematy znajdziesz na blogu Google dla deweloperów Chrome oraz w dokumentacji dotyczącej tożsamości dewelopera Chrome.