CSP frame-ancestors Membatasi Penyematan Halaman

Clickjacking tidak mengharuskan attacker mengganti interface aplikasi target. Halaman berbahaya dapat menempatkan aplikasi asli di dalam frame yang transparan atau diposisikan secara cermat, lalu menyusun control umpan agar klik user jatuh pada action terautentikasi di halaman yang berada dalam frame.

Directive frame-ancestors pada Content Security Policy memindahkan keputusan penyematan ke response yang hendak ditempatkan di dalam frame. Target menyatakan ancestor yang dapat diterima. Browser yang mengikuti CSP memeriksa rantai ancestor sebelum mengizinkan resource terlindungi dimuat dalam nested browsing context.

Content-Security-Policy: frame-ancestors 'none'

Untuk halaman yang memang tidak perlu disematkan, 'none' membentuk boundary yang ringkas: tidak ada parent yang diterima.

Response yang berada dalam frame menetapkan boundary

frame-ancestors dievaluasi untuk resource yang hendak disematkan oleh document lain. Directive ini bukan aturan mengenai frame yang dimuat oleh halaman terlindungi itu sendiri.

Perbedaan tersebut memisahkannya dari frame-src:

frame-ancestors -> siapa yang boleh menyematkan halaman ini
frame-src       -> source frame mana yang boleh dimuat halaman ini

Sebuah site dapat mengizinkan payment provider melalui frame-src, tetapi tetap menolak dirinya ditempatkan dalam frame oleh site lain melalui frame-ancestors. Kedua directive mengatur sisi yang berlawanan dari relasi tersebut.

Policy dapat mengizinkan framing dari origin yang sama:

Content-Security-Policy: frame-ancestors 'self'

Policy juga dapat menyebut source tertentu ketika penyematan cross-origin memang diperlukan:

Content-Security-Policy: frame-ancestors 'self' https://portal.example

Allowlist sebaiknya sesuai dengan kebutuhan penyematan yang nyata. Memperluas daftar hanya demi kemudahan ikut memperbesar kumpulan context yang dapat menampilkan interface terlindungi di dalam halaman lain.

Setiap ancestor pada rantai bertingkat ikut diperiksa

Nested frame dapat memiliki lebih dari satu ancestor. Browser memeriksa seluruh rantai, bukan menerima load hanya karena immediate parent cocok.

Perhatikan struktur berikut:

https://outer.example
    |
    v
https://portal.example
    |
    v
https://app.example

Jika app.example hanya mengizinkan portal.example, outer ancestor tetap diperhitungkan. Ancestor yang tidak cocok membuat load terlindungi diblokir.

Sifat ini mencegah intermediary yang diizinkan otomatis menjadi jalur bagi top-level site lain untuk menyematkan target. Deployment dengan portal bertingkat karena itu perlu memperhitungkan struktur ancestor lengkap yang akan dilihat browser.

default-src tidak menjadi fallback

Banyak fetch directive CSP memakai default-src sebagai fallback ketika directive terkait tidak ditulis. frame-ancestors tidak melakukannya.

Policy berikut tidak melarang site lain menempatkan response dalam frame:

Content-Security-Policy: default-src 'none'

Pembatasan penyematan harus dinyatakan secara eksplisit:

Content-Security-Policy: default-src 'none'; frame-ancestors 'none'

Menganggap default-src 'none' sebagai deny rule universal dapat meninggalkan celah framing yang tidak disengaja. Setiap kelas directive CSP memiliki aturan processing sendiri, sehingga fetch policy yang ketat bukan pengganti ancestor policy.

Directive harus berada pada HTTP response header

CSP mendukung sebagian policy melalui elemen HTML <meta http-equiv="Content-Security-Policy">, tetapi frame-ancestors bukan salah satunya. Spesifikasi CSP mewajibkan browser mengabaikan directive ini jika muncul dalam policy yang dikirim melalui elemen meta.

Bentuk yang efektif adalah HTTP response header:

Content-Security-Policy: frame-ancestors 'none'

Penempatan ini juga membuat keputusan tersedia sebelum markup document terlindungi dapat mencoba memengaruhi perilaku framing. Route aplikasi, reverse proxy, dan konfigurasi CDN perlu diperiksa agar header mencapai setiap response yang membutuhkan boundary tersebut.

X-Frame-Options memiliki ruang policy yang lebih sempit

X-Frame-Options hadir sebelum CSP dan lazim memakai DENY atau SAMEORIGIN:

X-Frame-Options: DENY

Nilai tersebut secara kasar berpadanan dengan kasus umum frame-ancestors:

X-Frame-Options: DENY
CSP: frame-ancestors 'none'

X-Frame-Options: SAMEORIGIN
CSP: frame-ancestors 'self'

frame-ancestors juga dapat menyatakan host atau scheme source tertentu. Dalam processing CSP, enforced policy yang memuat frame-ancestors mengambil precedence atas X-Frame-Options pada user agent yang mengimplementasikan directive tersebut.

Sebagian deployment mengirim kedua header untuk kompatibilitas dengan client lama. Nilainya sebaiknya menyatakan intent yang selaras, bukan membentuk dua policy yang saling bertentangan.

Framing policy bukan authorization check

Memblokir framing yang tidak disetujui menghilangkan salah satu kondisi yang dipakai banyak serangan UI redressing, tetapi tidak memberi authorization untuk operasi sensitif. Request yang mengubah state akun tetap memerlukan control authentication dan authorization normal milik aplikasi.

Directive ini juga tidak menggantikan defense CSRF. Clickjacking berkaitan dengan user yang berinteraksi dengan interface di dalam frame; CSRF berkaitan dengan site yang menyebabkan browser mengirim authenticated request yang tidak diinginkan. Jalur serangan dapat bersinggungan pada authenticated browser state, tetapi control-nya bekerja pada layer berbeda.

Pengaturan cookie SameSite dapat mengurangi pengiriman credential pada sebagian situasi penyematan cross-site. Pengaturan tersebut tetap terpisah dari keputusan eksplisit mengenai apakah sebuah halaman boleh disematkan.

Penyematan yang sah memerlukan kontrak sempit

Aplikasi kadang memerlukan framing untuk administration console, partner portal, atau composed interface. Dalam kondisi itu, 'none' terlalu ketat, sedangkan framing tanpa pembatasan membiarkan UI boundary terbuka.

Source list yang sempit membuat dependency tersebut terlihat:

Content-Security-Policy: frame-ancestors https://console.example https://partner.example

Daftar itu perlu dipelihara dengan disiplin yang sama seperti trust boundary lain. Origin yang diizinkan dapat menempatkan aplikasi di dalam document miliknya, sehingga ownership dan keamanan origin tersebut menjadi bagian dari framing model.

Perubahan topology portal juga perlu diuji. Penambahan wrapper frame dapat memutus rantai yang sebelumnya valid jika ancestor baru tidak tercantum dalam target policy.

Uji response, bukan hanya file konfigurasi

Security property berada pada header yang benar-benar dikirim ke browser. Konfigurasi yang tampak benar pada satu layer dapat hilang pada error route, ditimpa proxy, atau tidak diterapkan pada surface aplikasi lain.

Verifikasi perlu memeriksa response yang representatif serta menjalankan jalur penyematan yang diterima dan ditolak. Untuk framing bertingkat, pengujian perlu mencakup rantai ancestor lengkap, bukan hanya iframe langsung.

Policy yang ringkas hanya berguna jika mencapai response yang dituju. frame-ancestors memberi halaman terlindungi control atas embedding boundary; deployment memastikan boundary tersebut konsisten di seluruh aplikasi.

References