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):
- Mengaktifkan cookie pihak ketiga yang dipartisi
- Mengamankan endpoint dengan Kebijakan Keamanan Konten
- Percayai, tetapi verifikasi sisi server
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:
- Header respons HTTP permissions-policy (situs server induk): Halaman induk harus mendeklarasikan origin yang diizinkan di header respons HTTP-nya menggunakan sintaksis Structured Fields.
Permissions-Policy: publickey-credentials-get=(self "https://embedded-auth.example.com")
Kebijakan Izin: kompatibilitas publickey-credentials-get:
Kebijakan Izin: Kompatibilitas publickey-credentials-create:
- 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
Kompatibilitas iframe allow="publickey-credentials-create":
Browser Support
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:
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:
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 adalahtrue.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:
- Mengurai dan mendekode
collectedClientDatabertanda tangan dari respons pengautentikasi. - Pastikan
typecocok dengan upacara (webauthn.getatauwebauthn.create). - Verifikasi kehadiran dan tanda tangan pengguna.
- Jika permintaan dimaksudkan untuk berasal dari struktur iframe:
- Terapkan
crossOrigin === true. - Memastikan bahwa
topOrigincocok dengan daftar origin induk yang diizinkan.
- Terapkan
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:
- Pastikan URL
srciframe berisi parameter kuerinoncedanorigin:- Gunakan nilai acak untuk
nonce.nonceberfungsi 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. Parameteroriginmenentukan asal halaman induk, sehingga iframe dapat mengidentifikasi konteks resmi tempat iframe disematkan secara aman.
- Gunakan nilai acak untuk
- Iframe menyelesaikan autentikasi WebAuthn dengan servernya sendiri.
Server iframe mengeluarkan token seperti JWT yang mencakup
noncedan 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);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, }); });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.originsaat 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.