iframe “menolak untuk terhubung”: Atasi X-Frame-Options

Poin penting

“Menolak untuk terhubung” di dalam iframe bukan error jaringan. Situs yang di-frame mengirim header X-Frame-Options atau CSP frame-ancestors yang menyuruh browser tidak menampilkannya di dalam halaman lain. Perbaikannya ada di server situs yang di-frame, bukan di tag iframe Anda: pertahankan SAMEORIGIN untuk seluruh situs dan buka satu path embed dengan frame-ancestors *.

Periksa sekarang

X-Frame-Options dijelaskan: iframe “menolak untuk terhubung” dan solusinya — SAMEORIGIN untuk seluruh situs, CSP frame-ancestors * hanya untuk path embed
X-Frame-Options dijelaskan: iframe “menolak untuk terhubung” dan solusinya — SAMEORIGIN untuk seluruh situs, CSP frame-ancestors * hanya untuk path embed
Mulai membaca
  1. Arti Sebenarnya “Menolak untuk Terhubung” di Dalam iframe
  2. Cara Kerja X-Frame-Options
  3. DENY vs SAMEORIGIN: Mana yang Sebaiknya Dikirim?
  4. ALLOW-FROM Sudah Mati — Jangan Gunakan
  5. frame-ancestors: Directive CSP yang Menggantikannya
  6. Apa yang Terjadi Jika Kedua Header Diatur
  7. Langkah 1: Temukan Header yang Memblokir Anda
  8. Langkah 2: Putuskan Siapa yang Boleh Me-frame Halaman
  9. Pola yang Benar: Kunci Situs, Buka Satu Path Embed
  10. Nginx (dan Jebakan add_header)
  11. Apache
  12. Next.js dan Express
  13. Meng-embed Widget Pihak Ketiga dengan Aman
  14. sandbox: Apa yang Perlu Diizinkan untuk Widget Kalkulator
  15. Mengapa Tidak Ada Solusi di Sisi yang Meng-embed
  16. Verifikasi Header Setelah Setiap Perubahan
  17. Gejala → Penyebab → Solusi
  18. Pertanyaan yang Sering Diajukan

Arti Sebenarnya “Menolak untuk Terhubung” di Dalam iframe

Anda menambahkan <iframe> yang menunjuk ke situs lain, memuat ulang, dan alih-alih halamannya Anda melihat kotak abu-abu dengan ikon wajah sedih; arahkan kursor ke atasnya dan tertulis example.com menolak untuk terhubung. Naluri pertama adalah mengira ini masalah jaringan, karena itulah persis yang ditampilkan Chrome untuk server yang mati. Tetapi buka DevTools, dan konsol bercerita lain:

text
Refused to display 'https://emicalcs.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.

Tidak ada yang gagal di jaringan. DNS berhasil di-resolve, koneksi TCP terbuka, TLS selesai, dan server mengembalikan 200 yang sepenuhnya normal. Browser mengunduh halaman, membaca satu header respons, lalu sengaja menolak menampilkannya di dalam halaman Anda. Header itu adalah X-Frame-Options, dan fungsinya mencegah clickjacking — serangan ketika halaman jahat memuat formulir login atau pembayaran di dalam iframe tak terlihat dan menipu pengunjung agar mengklik tombol yang tidak mereka lihat.

Ini penting untuk cara Anda melakukan troubleshooting. Kegagalan koneksi yang sebenarnya — ERR_CONNECTION_REFUSED saat Anda membuka URL langsung di tab — adalah masalah server atau firewall, yang dibahas di ERR_CONNECTION_REFUSED. Versi iframe hanya muncul saat halaman di-frame, sedangkan URL yang sama berfungsi baik di tabnya sendiri. Jika situs termuat langsung tetapi tidak di frame Anda, yang Anda hadapi adalah kebijakan frame, bukan gangguan.

Lihat header X-Frame-Options dan CSP sebuah halaman

Cara Kerja X-Frame-Options

X-Frame-Options adalah header respons HTTP, pertama kali dijelaskan di RFC 7034, sebuah RFC informasional yang kini digantikan oleh standar HTML, dan didukung setiap browser sejak Internet Explorer 8. Server melampirkannya pada sebuah halaman; browser membacanya sebelum merender dan memutuskan apakah halaman boleh muncul di dalam <frame>, <iframe>, <embed>, atau <object> di halaman lain.

Ia menerima salah satu dari dua nilai yang masih penting, ditambah satu yang tidak lagi penting:

NilaiSiapa yang boleh me-frame halamanPenggunaan umum
DENYTidak ada — bahkan situs yang sama pun tidakHalaman login, panel admin, apa pun yang memiliki sesi
SAMEORIGINHanya halaman dengan origin yang persis sama (skema + host + port)Default yang masuk akal untuk sebagian besar situs; memungkinkan Anda me-frame halaman sendiri
ALLOW-FROM https://a.comUsang — diabaikan oleh setiap browser modernJangan digunakan; lihat di bawah

Header berlaku per respons, bukan per situs. Itulah detail yang dilewatkan sebagian besar panduan, dan yang membuat solusi di artikel ini mungkin: server dapat mengirim SAMEORIGIN di 99% halamannya dan kebijakan berbeda di satu path yang memang dimaksudkan untuk di-embed.

DENY vs SAMEORIGIN: Mana yang Sebaiknya Dikirim?

Kirim SAMEORIGIN kecuali Anda punya alasan lain. Ia memblokir setiap frame pihak ketiga sambil membiarkan situs Anda bebas me-frame halamannya sendiri — widget bantuan, pratinjau, dasbor yang memuat halaman internal lain.

Kirim DENY pada halaman yang frame-nya tidak punya tujuan sah dan risikonya berat: formulir masuk, halaman pembayaran, aksi satu klik seperti “hapus akun”. DENY juga mencakup kasus halus ketika penyerang berhasil menyisipkan frame ke salah satu halaman Anda — dengan SAMEORIGIN, frame yang disisipkan itu tetap diizinkan.

Mana pun yang Anda pilih, atur sekali di tingkat web server atau CDN agar mencakup setiap respons, termasuk halaman error dan aset statis. Header yang diatur di dalam kode aplikasi cenderung melewatkan halaman 404 dan halaman pemeliharaan, jadi aturlah di tempat yang dilewati setiap respons.

ALLOW-FROM Sudah Mati — Jangan Gunakan

Artikel lama masih merekomendasikan X-Frame-Options: ALLOW-FROM https://partner.com untuk mengizinkan satu situs yang meng-embed. Ini tidak pernah berfungsi di Chrome atau Safari, dan Firefox menghapusnya di versi 70 (Oktober 2019). Lebih buruk lagi, browser modern yang melihat ALLOW-FROM menganggap seluruh header tidak valid dan mengabaikannya sepenuhnya, sehingga halaman bisa di-frame siapa saja — kebalikan dari maksud Anda.

Jika Anda perlu mengizinkan situs tertentu, jawabannya adalah CSP frame-ancestors, yang dibahas berikutnya. X-Frame-Options hanya bisa berkata “tidak ada” atau “hanya saya”.

frame-ancestors: Directive CSP yang Menggantikannya

Content Security Policy Level 2 memperkenalkan frame-ancestors, sebuah directive yang melakukan semua yang dilakukan X-Frame-Options dan menambahkan hal yang tidak bisa dilakukannya: daftar izin yang sebenarnya. Ia berada di dalam header standar Content-Security-Policy dan menerima satu atau lebih sumber:

http
# Nobody may frame this (same as X-Frame-Options: DENY)
Content-Security-Policy: frame-ancestors 'none'

# Only my own origin (same as SAMEORIGIN)
Content-Security-Policy: frame-ancestors 'self'

# My origin plus two named partners, one with a subdomain wildcard
Content-Security-Policy: frame-ancestors 'self' https://partner.example https://*.trusted.example

# Anyone may frame this — for a public embed endpoint only
Content-Security-Policy: frame-ancestors *

Ada tiga detail yang perlu diketahui sebelum Anda beralih:

  • Ia memeriksa setiap ancestor, bukan hanya parent. Jika halaman A me-frame halaman B dan B me-frame halaman Anda, baik A maupun B harus diizinkan (CSP). Standar HTML kini juga menerapkan X-Frame-Options ke setiap ancestor (WHATWG), tetapi browser lama hanya memeriksa parent atau halaman teratas.
  • Ia hanya berfungsi sebagai header HTTP. frame-ancestors diabaikan secara eksplisit ketika CSP dikirim lewat tag <meta http-equiv> — browser harus tahu kebijakannya sebelum memutuskan apakah akan merender dokumen sama sekali. Hal yang sama berlaku untuk X-Frame-Options. Keduanya tidak bisa diatur dari HTML.
  • Wildcard bersifat per host, bukan global. https://*.example.com cocok dengan subdomain mana pun dari satu situs; * saja cocok dengan setiap origin di internet. Cocok untuk widget kalkulator, salah untuk apa pun yang membawa sesi.

Apa yang Terjadi Jika Kedua Header Diatur

Sebagian besar situs akhirnya mengirim keduanya selama migrasi, dan prioritasnya sudah ditentukan: jika frame-ancestors ada, browser memberlakukannya dan mengabaikan X-Frame-Options. Spesifikasi CSP Level 2 menyatakannya secara gamblang, dan Chrome, Firefox, Safari, serta Edge semuanya mengikutinya.

Itu membuat jalur migrasi yang aman menjadi sederhana. Pertahankan X-Frame-Options: SAMEORIGIN untuk segelintir klien kuno yang lebih tua dari CSP 2, tambahkan Content-Security-Policy: frame-ancestors 'self' di sampingnya, dan setiap browser modern akan memakai aturan CSP. Keduanya hanya menimbulkan masalah jika Anda membuat keduanya mengatakan hal berbeda — misalnya X-Frame-Options: DENY di samping frame-ancestors * — dalam hal itu browser modern mengizinkan frame dan hanya browser yang sangat lama yang memblokir. Jaga agar konsisten dan tidak ada yang perlu di-debug.

Langkah 1: Temukan Header yang Memblokir Anda

Sebelum mengubah apa pun, pastikan kebijakan mana yang berlaku. Konsol browser sudah memberi tahu nama header-nya; curl menunjukkan nilai persis yang dikirim server. Contoh ini memakai situs dari contoh nyata di bagian bawah — halaman utamanya sengaja dikunci:

bash
curl -sI https://emicalcs.com/ | grep -i -E 'x-frame-options|content-security-policy'

# Output:
# x-frame-options: SAMEORIGIN

Hasilnya salah satu dari tiga hal:

  • x-frame-options: SAMEORIGIN atau DENY — kebijakan frame klasik. Hanya perubahan di server itu yang bisa mencabutnya.
  • content-security-policy: … frame-ancestors … — kebijakan CSP. Baca daftar sumbernya; jika origin Anda tidak ada di dalamnya, Anda diblokir. Directive ini sering terselip di header CSP panjang bersama script-src dan kawan-kawannya, jadi baca seluruh nilainya.
  • Tidak ada header: situs yang di-frame mengizinkan frame, dan “menolak untuk terhubung” punya penyebab lain: redirect ke halaman yang terkunci (sering halaman login; ikuti dengan curl -sIL), atau header Cross-Origin-Embedder-Policy: require-corp di halaman Anda sendiri, yang memblokir frame mana pun yang tidak ikut serta dan menampilkan kotak abu-abu yang sama.

Langkah 2: Putuskan Siapa yang Boleh Me-frame Halaman

Semua yang berikut bergantung pada satu pertanyaan: apakah Anda mengendalikan situs yang di-frame?

Jika tidak, berhenti di sini. Tidak ada solusi sisi klien — bukan atribut sandbox, bukan src yang berbeda, bukan flag browser yang akan dimiliki pengunjung Anda. Pemilik situs memutuskan halamannya tidak boleh di-embed, dan browser menegakkan keputusan itu atas namanya. Pilihan Anda adalah menautkan ke halaman itu, bertanya kepada pemilik apakah mereka menyediakan endpoint embed, atau memakai widget resmi jika ada. Banyak layanan yang mengunci situs utamanya memang menyediakannya; contoh di bagian berikutnya menunjukkan seperti apa.

Jika Anda mengendalikannya, tahan godaan untuk menghapus header di seluruh situs. Itu membuka kembali clickjacking di setiap halaman — termasuk yang memiliki sesi dan formulir — hanya untuk memperbaiki satu embed. Sebaliknya, putuskan path spesifik mana yang memang dimaksudkan untuk di-frame, dan oleh siapa:

SituasiHeader yang dikirim di path itu
Alat internal yang di-frame oleh dasbor Anda sendiriframe-ancestors 'self' (plus X-Frame-Options: SAMEORIGIN)
Widget yang di-embed oleh beberapa mitra yang dikenalframe-ancestors 'self' https://partner-a.com https://partner-b.com
Widget publik yang bisa di-embed (kalkulator, peta, pemutar)frame-ancestors * hanya di path embed
Semua yang lainframe-ancestors 'self' plus X-Frame-Options: SAMEORIGIN

Pola yang Benar: Kunci Situs, Buka Satu Path Embed

Contoh dunia nyata paling bersih dari pola ini yang pernah saya temui adalah EMICalcs, kumpulan gratis 45 kalkulator keuangan India — cicilan EMI, SIP, pajak penghasilan, GST, dan lainnya — yang boleh di-embed situs lain. Situs utamanya dikunci; path /embed/ khusus dibuka. Bandingkan header keduanya:

bash
# The calculator page a visitor normally uses — locked
curl -sI https://emicalcs.com/income-tax-calculator/ | grep -i -E 'x-frame|frame-ancestors'
# x-frame-options: SAMEORIGIN

# The same calculator on its embed path — open to any site
curl -sI https://emicalcs.com/embed/income-tax-calculator/ | grep -i -E 'x-frame|frame-ancestors'
# content-security-policy: frame-ancestors *

Perhatikan apa yang tidak ada dalam respons embed: tidak ada header X-Frame-Options sama sekali di /embed/. Itu disengaja. Karena directive CSP didahulukan, membiarkan SAMEORIGIN tidak berbahaya di browser modern — tetapi akan membingungkan engineer berikutnya yang membaca header, dan tetap akan memblokir beberapa klien lama yang hanya memahami X-Frame-Options. Path embed mengirim satu kebijakan, dan isinya hanya satu hal.

Semua yang lain di situs tetap memakai SAMEORIGIN, sehingga beranda, halaman artikel, dan halaman kalkulator lengkap tetap terlindungi dari clickjacking. Versi embed adalah dokumen ringkas tanpa navigasi dan tanpa sesuatu yang layak dibajak, itulah sebabnya membukanya untuk * adalah kompromi yang masuk akal.

Panduan embed mereka layak dibaca sebagai templat jika Anda menerbitkan widget sendiri: satu URL stabil per kalkulator, tinggi tetap yang cocok untuk sebagian besar, loading="lazy" di snippet, dan janji bahwa URL embed yang dihentikan akan di-redirect, bukan 404 — karena setiap situs yang meng-embed Anda percaya URL Anda akan terus berfungsi.

Nginx (dan Jebakan add_header)

Berikut pola yang sama di tiga tempat yang paling sering dipakai untuk mengatur header. Di setiap tempat, aturan seluruh situs mengunci semuanya dan aturan yang lebih sempit menimpanya untuk path embed. Nginx dulu, karena ada jebakannya:

nginx
# Site-wide default (server block)
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;
add_header X-Content-Type-Options "nosniff" always;

location /embed/ {
    # WARNING: any add_header here stops ALL add_header inheritance from the
    # server block — re-declare every header you still want on this path.
    add_header Content-Security-Policy "frame-ancestors *" always;
    add_header X-Content-Type-Options "nosniff" always;
}

Komentar itu bukan bacaan opsional. add_header tidak digabung antar tingkat: begitu blok location mendeklarasikan add_header apa pun, ia berhenti mewarisi semua add_header dari blok server. Tim sering kehilangan header HSTS atau nosniff di path embed dengan cara ini dan baru menyadarinya lewat pemindaian keamanan berbulan-bulan kemudian. Deklarasikan ulang apa yang Anda butuhkan, dan tinggalkan X-Frame-Options dari blok embed agar path mengirim satu kebijakan yang jelas. Sejak nginx 1.29.3, add_header_inherit merge dapat mengaktifkan kembali pewarisan (nginx), tetapi jangan gunakan di blok embed: ia akan menambahkan kembali X-Frame-Options dan frame-ancestors 'self' seluruh situs ke path itu, dan dengan dua header CSP browser memberlakukan keduanya, sehingga frame tetap diblokir.

Apache

Directive Header Apache digabung antar cakupan, sehingga Anda bisa mengatur default sekali dan hanya menyentuh dua header yang berubah di path embed:

apache
# Site-wide default (needs mod_headers)
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Content-Security-Policy "frame-ancestors 'self'"

<LocationMatch "^/embed/">
    Header always unset X-Frame-Options
    Header always set Content-Security-Policy "frame-ancestors *"
</LocationMatch>

Next.js dan Express

Di Next.js, header dideklarasikan di next.config.js. Ketika dua aturan cocok dengan path yang sama dan mengatur header yang sama, aturan yang belakangan menang — tetapi header yang hanya diatur oleh aturan sebelumnya tetap berlaku. Untuk menjauhkan X-Frame-Options dari path embed sepenuhnya, kecualikan dari aturan seluruh situs dengan negative lookahead:

javascript
// next.config.js
module.exports = {
  async headers() {
    return [
      {
        // Every path EXCEPT /embed/... gets the locked defaults
        source: '/((?!embed/).*)',
        headers: [
          { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
          { key: 'Content-Security-Policy', value: "frame-ancestors 'self'" },
        ],
      },
      {
        source: '/embed/:path*',
        headers: [
          { key: 'Content-Security-Policy', value: 'frame-ancestors *' },
        ],
      },
    ]
  },
}

Di Express, middleware helmet yang populer sudah mengirim X-Frame-Options: SAMEORIGIN dan CSP yang menyertakan frame-ancestors 'self' secara default. Pasang secara global, lalu di router embed panggil res.removeHeader('X-Frame-Options') dan atur Content-Security-Policy ke frame-ancestors * sebelum merender. Urutan penting: penimpaan Anda harus berjalan setelah helmet, atau helmet akan menimpanya.

Meng-embed Widget Pihak Ketiga dengan Aman

Sekarang sisi lain pagar: Anda adalah situs yang meng-embed, penyedia punya path embed terbuka, dan Anda ingin frame-nya berperilaku baik. Snippet widget yang dibuat dengan baik terlihat seperti ini; ini adalah snippet yang diterbitkan EMICalcs di setiap halaman kalkulator:

html
<iframe src="https://emicalcs.com/embed/income-tax-calculator/"
        title="Income Tax Calculator FY 2026-27 — EMICalcs"
        width="100%" height="760"
        style="max-width:680px;border:0;border-radius:16px;overflow:hidden"
        loading="lazy"></iframe>
<p>Free <a href="https://emicalcs.com/income-tax-calculator/" target="_blank" rel="noopener">Income Tax Calculator FY 2026-27</a> by EMICalcs</p>

Setiap atribut punya tugasnya:

  • title — memberi nama frame untuk pembaca layar. Tanpanya, teknologi bantu hanya mengumumkan “frame” dan tidak ada yang lain, dan audit aksesibilitas menggagalkan halaman.
  • width="100%" dengan max-width di style — memenuhi kolom sempit di ponsel tanpa meluap di kolom lebar di desktop.
  • height tetap — halaman yang meng-embed tidak bisa membaca tinggi konten frame lintas origin, jadi nilai yang ditulis tetap adalah satu-satunya cara menghindari pergeseran tata letak saat memuat. Atur sekali per widget.
  • loading="lazy" — menunda permintaan sampai frame digulir mendekati viewport, sehingga widget di bagian bawah artikel panjang tidak membebani pemuatan awal.
  • border:0; border-radius; overflow:hidden — menghapus border inset default dan memotong sudut agar widget terlihat menyatu dengan halaman Anda.

Baris kredit sengaja diletakkan di luar iframe. Semua yang ada di dalam frame milik dokumen yang di-frame — tautannya adalah tautan penyedia, di URL penyedia — sehingga tautan di dalam frame bukan bagian dari halaman Anda bagi pembaca maupun crawler mesin pencari. Jika Anda ingin mencantumkan sumber, atau penyedia memintanya, letakkan paragraf biasa di samping frame di HTML Anda sendiri, seperti di atas.

sandbox: Apa yang Perlu Diizinkan untuk Widget Kalkulator

Atribut sandbox adalah perlindungan milik pihak yang meng-embed. Tambahkan tanpa nilai dan halaman yang di-frame tidak mendapat apa-apa: tanpa skrip, tanpa formulir, tanpa pop-up, tanpa menavigasi jendela Anda, dan origin buram yang menonaktifkan cookie dan penyimpanannya sendiri. Lalu tambahkan kembali hanya yang dibutuhkan widget:

html
<iframe src="https://emicalcs.com/embed/loan-emi-calculator/"
        sandbox="allow-scripts allow-forms allow-same-origin allow-popups"
        title="Loan EMI Calculator — EMICalcs"
        width="100%" height="760" loading="lazy"></iframe>

allow-scripts dan allow-forms adalah minimum untuk apa pun yang interaktif. allow-same-origin membuat halaman yang di-frame mempertahankan origin-nya sendiri sehingga penyimpanan dan cookie-nya berfungsi — pada embed lintas origin ini aman, karena “origin-nya” tetap milik penyedia, bukan milik Anda. allow-popups hanya diperlukan jika widget membuka tautan di tab baru, seperti tautan kredit di dalam embed EMICalcs.

Yang tidak boleh Anda lakukan adalah menggabungkan allow-scripts dengan allow-same-origin pada frame yang menunjuk ke origin Anda sendiri. Skrip di dalam frame lalu bisa menjangkau ke atas dan menghapus atribut sandbox-nya sendiri, dan Anda tidak men-sandbox apa pun.

Mengapa Tidak Ada Solusi di Sisi yang Meng-embed

Pencarian “iframe menolak untuk terhubung” menghasilkan tiga solusi sementara yang populer. Semuanya buruk, dan ada baiknya tahu persis alasannya.

  • Ekstensi browser yang menghapus X-Frame-Options — hanya berfungsi di browser Anda sendiri. Setiap pengunjung situs Anda tetap melihat kotak abu-abu, dan Anda sementara itu telah mematikan perlindungan clickjacking di setiap situs yang Anda kunjungi.
  • Mem-proxy halaman melalui server Anda sendiri — Anda mengambil HTML pihak ketiga di sisi server dan menyajikannya dari origin Anda, sehingga header tidak pernah sampai ke browser. Ini merusak tautan relatif, cookie, login, dan apa pun yang digerakkan skrip; Anda ikut bertanggung jawab atas konten mereka; dan biasanya melanggar ketentuan penyedia. Situs yang memergoki Anda akan memblokir IP server Anda.
  • Layanan screenshot atau “web-to-image” — Anda mendapat gambar statis, bukan halaman yang berfungsi. Cukup untuk thumbnail pratinjau, tidak berguna untuk kalkulator.

Header adalah pernyataan pemilik situs, ditegakkan oleh browser, tentang apa yang boleh terjadi pada halamannya. Satu-satunya jalan yang sah adalah dua yang sudah dibahas: pemilik membuka path embed, atau Anda menautkan keluar. Penyedia yang ingin di-embed membuatnya mudah — yang baik menerbitkan snippet, menjaga URL tetap stabil, dan hanya membuka path yang aman dibuka.

Verifikasi Header Setelah Setiap Perubahan

Header frame diatur di file konfigurasi lalu dilupakan, dan CDN, reverse proxy, atau plugin keamanan yang bermaksud baik dapat menambah, menghapus, atau menggandakannya kapan saja. Setelah deploy, periksa dari luar jaringan Anda:

bash
# The locked pages should show SAMEORIGIN and/or frame-ancestors 'self'
curl -sI https://example.com/ | grep -i -E 'x-frame-options|content-security-policy'

# The embed path should show ONLY frame-ancestors, with the sources you intended
curl -sI https://example.com/embed/widget/ | grep -i -E 'x-frame-options|content-security-policy'

# Error pages should carry the header too
curl -sI https://example.com/this-does-not-exist | grep -i -E 'x-frame-options|content-security-policy'

Lalu uji seperti yang dilakukan browser: letakkan URL embed di <iframe> pada halaman yang disajikan dari origin yang berbeda — halaman file:// lokal tidak cocok, karena browser memperlakukannya secara khusus — dan buka konsol. Pemuatan bersih berarti tidak ada baris Refused to display atau Refused to frame.

Jika situs berada di belakang Cloudflare atau CDN lain, salinan cache atau aturan di edge bisa membawa header berbeda dari origin Anda. HTTP Header Checker meminta URL dari server kami, di luar browser dan jaringan Anda, dan menampilkan X-Frame-Options dan Content-Security-Policy beserta vonis frame (SAMEORIGIN atau DENY, lewat CSP frame-ancestors, atau tidak dikirim): cara cepat menangkap aturan CDN yang diam-diam menambahkan kembali SAMEORIGIN ke path embed Anda.

Gejala → Penyebab → Solusi

Gunakan tabel ini untuk langsung menuju solusi tanpa membaca ulang seluruh panduan:

Yang Anda lihatArtinyaSolusi
Kotak abu-abu “menolak untuk terhubung”, tetapi URL termuat di tabX-Frame-Options atau frame-ancestors memblokir frameHanya pemilik situs yang bisa mengubahnya — gunakan path embed mereka atau tautkan keluar
Konsol: Refused to display … 'X-Frame-Options' to 'sameorigin'Header klasik; hanya frame satu origin yang diizinkanDi situs yang di-frame, buka path embed dengan frame-ancestors * atau daftar mitra
Konsol: Refused to frame … violates … frame-ancestorsDaftar izin CSP tidak menyertakan origin AndaTambahkan origin Anda ke sumber frame-ancestors situs yang di-frame
Kemarin masih jalan, hari ini rusak, tanpa perubahan kodeCDN atau plugin keamanan mulai menyisipkan SAMEORIGINPeriksa dengan curl; kecualikan path embed di aturan CDN atau plugin
Dasbor Anda sendiri tidak bisa me-frame halaman Anda sendiriKetidakcocokan subdomain atau skema (www vs domain apex, http vs https)Gunakan frame-ancestors 'self' https://example.com https://*.example.com (wildcard tidak mencakup domain polos)
Embed berfungsi, tetapi HSTS atau nosniff hilang di path ituPewarisan add_header Nginx menjatuhkannyaDeklarasikan ulang setiap header di dalam blok location
ERR_CONNECTION_REFUSED saat membuka URL langsungKegagalan jaringan yang sebenarnya, bukan kebijakan frameLihat ERR_CONNECTION_REFUSED dan port checker

Jika URL juga gagal di tabnya sendiri, frame hanyalah pengalih perhatian. Telusuri lapisan jaringan secara berurutan — DNS, port, TLS, header — dengan panduan pengujian endpoint publik sebelum menyentuh header frame apa pun.

Lihat setiap header keamanan yang dikirim sebuah URL

Periksa X-Frame-Options, Content-Security-Policy, HSTS, dan lainnya untuk halaman mana pun, diambil dari server kami, sehingga ekstensi browser atau proxy di jaringan Anda tidak bisa mengubah yang Anda lihat. Gratis, tanpa daftar.

Sumber

  1. RFC 7034: HTTP Header Field X-Frame-Options, IETF
  2. CSP Level 3: frame-ancestors, W3C
  3. HTML Standard: the X-Frame-Options header, WHATWG
  4. ngx_http_headers_module (add_header, add_header_inherit), nginx

Pertanyaan yang Sering Diajukan

Apakah X-Frame-Options sudah usang?

Secara fungsi ia sudah digantikan oleh directive CSP frame-ancestors, yang diprioritaskan browser setiap kali kedua header ada. Namun ia tidak sia-sia: setiap browser saat ini masih menghormati X-Frame-Options ketika frame-ancestors tidak ada, dan ia melindungi sejumlah kecil klien lama yang lebih tua dari CSP Level 2. Saran praktisnya adalah kirim keduanya dan jaga agar konsisten — SAMEORIGIN bersama frame-ancestors 'self'.

Apa arti X-Frame-Options: DENY?

DENY memberi tahu browser bahwa halaman tidak boleh dirender di dalam elemen frame, iframe, embed, atau object di halaman mana pun — termasuk halaman di situs yang sama. Ini pengaturan paling ketat dan tepat untuk formulir login, halaman pembayaran, dan panel admin, yang tidak punya alasan sah untuk di-embed dan clickjacking-nya akan serius.

Apa bedanya DENY dan SAMEORIGIN?

DENY memblokir semua frame. SAMEORIGIN hanya mengizinkan frame oleh halaman dengan origin yang persis sama — skema, host, dan port yang sama — dan memblokir yang lain. SAMEORIGIN adalah default seluruh situs yang masuk akal karena menghentikan clickjacking pihak ketiga sambil tetap membiarkan situs Anda me-frame halamannya sendiri; DENY untuk segelintir halaman yang tidak boleh di-frame sama sekali.

Bagaimana cara melewati X-Frame-Options untuk meng-embed sebuah situs?

Dari sisi yang meng-embed, tidak bisa. Header diatur oleh situs yang ingin Anda frame dan ditegakkan oleh browser pengunjung Anda; tidak ada atribut iframe, flag sandbox, atau trik sisi klien yang mengubahnya. Ekstensi yang menghapus header hanya memengaruhi browser Anda sendiri, dan mem-proxy halaman melalui server Anda merusaknya dan biasanya melanggar ketentuan penyedia. Jalur yang sah adalah memakai endpoint embed resmi jika penyedia menawarkannya, atau menautkan ke halaman itu.

Bagaimana cara mengatur X-Frame-Options ke DENY?

Tambahkan sebagai header respons HTTP di tingkat web server agar mencakup setiap halaman, termasuk halaman error. Di Nginx: add_header X-Frame-Options "DENY" always; di Apache: Header always set X-Frame-Options "DENY". Padukan dengan Content-Security-Policy: frame-ancestors 'none' untuk browser modern. Ia tidak bisa diatur dengan tag meta — hanya header HTTP yang berfungsi.

Mengapa iframe saya menampilkan “menolak untuk terhubung” padahal situs berfungsi di tab baru?

Karena tidak ada yang salah dengan koneksinya. Situs mengembalikan halaman secara normal, tetapi dengan header X-Frame-Options atau frame-ancestors yang melarang perenderan di dalam halaman lain. Chrome menampilkan kotak abu-abu “menolak untuk terhubung” yang sama untuk ini seperti untuk kegagalan jaringan sungguhan, itulah yang membingungkan; pesan konsol “Refused to display … in a frame” adalah petunjuknya.

Bisakah saya mengatur X-Frame-Options atau frame-ancestors di tag meta?

Tidak. Keduanya harus dikirim sebagai header respons HTTP. Browser harus tahu kebijakan frame sebelum memutuskan apakah akan merender dokumen sama sekali, dan tag meta datang terlalu terlambat. frame-ancestors diabaikan secara eksplisit di CSP meta http-equiv, dan X-Frame-Options di tag meta diabaikan oleh setiap browser.

Apakah frame-ancestors * membuat situs saya tidak aman?

Hanya untuk respons yang mengirimnya. Header dievaluasi per dokumen, sehingga mengirim frame-ancestors * di path /embed/ khusus membiarkan sisa situs terlindungi penuh oleh SAMEORIGIN atau frame-ancestors 'self'. Risikonya terbatas pada apa yang bisa didapat penyerang dengan me-frame halaman embed itu sendiri — yang, untuk widget tanpa status, tanpa cookie sesi, dan tanpa aksi sensitif, adalah nol.

Mengapa X-Frame-Options: ALLOW-FROM tidak berfungsi?

ALLOW-FROM hanya pernah diimplementasikan oleh Internet Explorer, Edge asli (versi 12 sampai 18), dan Firefox, yang menghapusnya di versi 70. Chrome dan Safari tidak pernah mendukungnya. Browser modern menganggap header yang berisi ALLOW-FROM tidak valid dan mengabaikannya sepenuhnya, sehingga halaman bisa di-frame siapa saja. Gunakan directive CSP frame-ancestors, yang mendukung daftar origin yang diizinkan secara layak.

Header mana yang menang jika X-Frame-Options dan frame-ancestors sama-sama diatur?

frame-ancestors. Standar HTML meminta browser mengabaikan X-Frame-Options setiap kali CSP yang diberlakukan memuat frame-ancestors (CSP Level 2 sudah merekomendasikannya), dan semua browser saat ini melakukannya; kebijakan Report-Only tidak dihitung. Hanya klien yang terlalu tua untuk memahami CSP yang kembali ke X-Frame-Options, itulah sebabnya ia masih layak dikirim — selama kedua header sepakat.

Tentang penulis

Shaik Vahid

Pendiri DNS Robot. Vahid bertahun-tahun bekerja di dukungan web hosting, memperbaiki domain, record DNS, sertifikat SSL, dan pengiriman email untuk pelanggan. Ia membangun alat-alat DNS Robot dan menulis panduan ini dari error yang benar-benar dialami orang.

Cek HTTP Header

Analisis header respons HTTP dan penilaian header keamanan