Kunci sandi dalam iframe

Untuk menyediakan autentikasi dalam konteks yang lancar di beberapa domain, organisasi sering menyematkan halaman login dalam iframe. Namun, memuat konteks autentikasi di dalam frame pihak ketiga membuat pengguna rentan terhadap ancaman serius seperti clickjacking (pengubahan UI) dan pembuatan kredensial yang tidak sah. Untuk mengurangi risiko ini, browser menonaktifkan WebAuthn di iframe lintas origin secara default. Untuk mencabut pembatasan ini dengan aman, diperlukan protokol pertahanan mendalam yang aktif.

Mengidentifikasi model ancaman

Sebelum mengaktifkan kunci sandi (WebAuthn) di dalam subframe, pahami skenario penyalahgunaan yang harus Anda lindungi:

  • Pelacakan menggunakan injeksi iframe tersembunyi: Penyerang memicu perintah WebAuthn dari domainnya sendiri menggunakan iklan atau widget di situs tepercaya, sehingga menipu pengguna untuk mengizinkan kunci sandi tanpa melihat konteksnya. Tindakan ini menautkan identitas pengguna ke akun yang dikontrol penyerang untuk mengumpulkan data.
  • Overlay visual dan clickjacking (penyelesaian ulang UI): Halaman induk berbahaya merender iframe autentikasi menjadi tidak terlihat menggunakan CSS standar dan meng-overlay elemen UI palsu untuk mencuri klik yang memicu alur autentikasi. Hal ini dapat mengakibatkan pembajakan sesi atau tindakan tidak sah yang dipaksakan jika pengguna tidak sengaja menyelesaikan perintah.

Untuk mengatasi ancaman ini, ikuti praktik terbaik berikut:

Untuk dokumen tingkat teratas (frame atas):

Untuk dokumen yang disematkan (iframe):

Untuk kedua dokumen:

Mengaktifkan delegasi menggunakan Kebijakan Izin

Browser memblokir akses ke WebAuthn di iframe lintas origin secara default. Permissions Policy adalah mekanisme platform web terpadu yang memungkinkan dokumen tingkat teratas secara eksplisit mendelegasikan kemampuan canggih ini ke origin pihak ketiga tertentu yang tepercaya.

Token fitur

WebAuthn menggunakan dua token yang berbeda:

  • publickey-credentials-get: Memberikan otorisasi untuk alur login kunci sandi (navigator.credentials.get()).
  • publickey-credentials-create: Memberikan otorisasi untuk alur pendaftaran kunci sandi (navigator.credentials.create()).

Persyaratan untuk pengaktifan

Untuk mengaktifkan kemampuan ini, diperlukan keselarasan dalam respons server induk dan markup sisi klien:

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

Kebijakan Izin: kompatibilitas publickey-credentials-get:

Browser Support

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

Source

Kebijakan Izin: Kompatibilitas publickey-credentials-create:

Browser Support

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

Source

  • Atribut HTML allow: Dalam markup HTML, elemen <iframe> juga harus menyatakan bahwa elemen tersebut mengaktifkan fitur.
<iframe src="https://embedded-auth.example.com?nonce=deadbeef12345678&client=https%3A%2F%2Fembedded-auth.example.com" allow="publickey-credentials-get"></iframe>

Kompatibilitas iframe allow="publickey-credentials-get":

Browser Support

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

Kompatibilitas iframe allow="publickey-credentials-create":

Browser Support

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

Mengaktifkan cookie pihak ketiga yang dipartisi

Untuk memastikan alur autentikasi yang andal, sesi harus dibuat dan dipertahankan dalam iframe lintas asal yang disematkan. Saat browser modern beralih ke batasan ketat cookie pihak ketiga, mekanisme persistensi standar sering kali diblokir secara default dan mungkin memerlukan panggilan Storage Access API untuk mendapatkan akses.

Untuk mengatasi hambatan ini, konfigurasikan cookie sesi Anda dengan atribut SameSite: None, Secure, dan Partitioned. Mekanisme platform terpadu ini memastikan status persisten dalam iframe sekaligus mematuhi kontrol privasi tingkat browser.

Tetapkan SameSite: None

SameSite: None secara eksplisit menandai cookie untuk akses lintas situs, sehingga cookie dapat dikirim dengan permintaan yang dibuat dari konteks pihak ketiga (seperti iframe). Atribut ini adalah prasyarat agar cookie berfungsi dalam skenario lintas origin, meskipun harus digabungkan dengan atribut Secure agar diterima oleh browser modern.

Tetapkan Partitioned

Atribut Partitioned mengikutsertakan cookie dalam CHIPS (Cookies Having Independent Partitioned State), sehingga cookie dapat disimpan secara terpisah untuk setiap situs tingkat teratas. Hal ini memastikan cookie tetap dapat diakses dalam konteks iframe pihak ketiga tertentu, sehingga memungkinkan status sesi yang persisten tanpa mengaktifkan pelacakan lintas situs. Pengguna harus login lagi untuk setiap sematan di situs yang berbeda.

Melindungi endpoint dengan Kebijakan Keamanan Konten

Meskipun Permissions Policy menentukan apakah iframe Anda dapat menjalankan WebAuthn, Kebijakan Keamanan Konten (CSP) menentukan siapa yang diizinkan untuk menghosting iframe Anda.

Untuk endpoint autentikasi, sangat penting untuk memastikan bahwa hanya situs partner yang sah atau properti Anda sendiri yang dapat memuat subframe login, sehingga menghentikan upaya clickjacking yang tidak sah sebelum upaya tersebut dapat memuat UI.

Gunakan frame-ancestors

frame-ancestors Directive menentukan halaman induk yang valid yang dapat menyematkan situs Anda. Dengan menambahkan domain ke direktif ini, Anda dapat mengizinkan domain yang diizinkan untuk menyematkan subframe login.

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

Kebijakan Keamanan Konten: kompatibilitas frame-ancestors:

Browser Support

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

Source

Tetapkan X-Frame-Options

Header X-Frame-Options lama mendukung kemampuan serupa, tetapi hanya mendukung opsi biner (DENY atau SAMEORIGIN). Tetapkan CSP frame-ancestors dan X-Frame-Options: DENY jika browser tidak mendukung CSP. CSP selalu diprioritaskan jika didukung.

X-Frame-Options: DENY

Kompatibilitas X-Frame-Options:

Browser Support

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

Source

Percayai, tetapi verifikasi sisi server

Pemeriksaan sisi klien browser mengevaluasi maksud dan izin, tetapi server adalah penentu akhir kepercayaan. Verifikasi respons di server Pihak Tepercaya (RP) untuk memastikan konteksnya valid dan ditandatangani.

Payload data sisi klien

Data klien WebAuthn mencakup parameter yang dirancang khusus untuk membantu Anda memverifikasi konteks permintaan yang dibuat dalam iframe:

  • crossOrigin (boolean): Menunjukkan apakah WebAuthn API dipanggil di dalam iframe lintas origin. Jika arsitektur Anda mengandalkan iframe, server Anda harus memastikan bahwa tanda ini adalah true.
  • topOrigin (string): Asal konteks penjelajahan tingkat teratas (apa yang terlihat di kolom URL browser). Server harus memverifikasi hal ini terhadap daftar asal induk yang diketahui dan diberi otorisasi.

Checklist verifikasi

Untuk memverifikasi respons autentikator di server Anda, lakukan langkah-langkah berikut:

  1. Mengurai dan mendekode collectedClientData bertanda tangan dari respons pengautentikasi.
  2. Pastikan type cocok dengan upacara (webauthn.get atau webauthn.create).
  3. Verifikasi kehadiran dan tanda tangan pengguna.
  4. Jika permintaan dimaksudkan untuk berasal dari struktur iframe:
    • Terapkan crossOrigin === true.
    • Memastikan bahwa topOrigin cocok dengan daftar origin induk yang diizinkan.

Membuat sesi secara aman menggunakan postMessage()

Untuk membuat sesi yang andal, iframe harus meneruskan token autentikasi kembali ke halaman induk menggunakan postMessage(), sehingga induk dapat mengelola status sesi dalam konteks pihak pertamanya sendiri.

Alur kerja yang aman

Untuk membuat sesi yang aman, ikuti alur kerja berikut:

  1. Pastikan URL src iframe berisi parameter kueri nonce dan origin:
    • Gunakan nilai acak untuk nonce. nonce berfungsi sebagai token verifikasi keamanan untuk memastikan bahwa token autentikasi yang diterima dari iframe secara sah cocok dengan sesi tertentu yang dimulai oleh halaman induk.
    • Gunakan domain frame induk untuk origin. Parameter origin menentukan asal halaman induk, sehingga iframe dapat mengidentifikasi konteks resmi tempat iframe disematkan secara aman.
  2. Iframe menyelesaikan autentikasi WebAuthn dengan servernya sendiri.
  3. Server iframe mengeluarkan token seperti JWT yang mencakup nonce dan meneruskannya ke halaman induk.

    // 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. Halaman induk memproses peristiwa message, memvalidasi asal pengirim, dan memverifikasi 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. Halaman induk mempertahankan sesi jika JWT berhasil diverifikasi.

Pengirim dan penerima sama-sama berbagi tanggung jawab keamanan:

  • Pengirim (iframe): Selalu tentukan target asal yang ketat saat mengirim pesan (jangan pernah menggunakan "*").
  • Penerima (orang tua): Selalu verifikasi event.origin saat menerima pesan untuk mencegah pemalsuan asal.

Kesimpulan

Penggunaan iframe yang aman bergantung pada Permissions Policy untuk pengaktifan, CSP untuk pembatasan, cookie pihak ketiga yang dipartisi untuk persistensi sesi, verifikasi sisi server dari konteks klien, dan penyerahan sesi yang kontekstual menggunakan postMessage().

Untuk mempelajari lebih lanjut topik terkait, ikuti blog developer Chrome Google dan pelajari lebih lanjut referensi di dokumentasi Identitas Developer Chrome.