Bagaimana cara mengidentifikasi apakah halaman web dimuat di dalam iframe atau langsung ke jendela browser?

597

Saya sedang menulis aplikasi facebook berbasis iframe. Sekarang saya ingin menggunakan halaman html yang sama untuk membuat situs web normal serta halaman kanvas dalam facebook. Saya ingin tahu apakah saya dapat menentukan apakah halaman telah dimuat di dalam iframe atau langsung di browser?

akshat
sumber
2
Beberapa cara yang bagus (termasuk komentar): tommcfarlin.com/check-if-a-page-is-in-an-iframe
simhumileco

Jawaban:

1108

Browser dapat memblokir akses ke window.topkarena kebijakan asal yang sama . Bug IE juga terjadi. Ini kode kerjanya:

function inIframe () {
    try {
        return window.self !== window.top;
    } catch (e) {
        return true;
    }
}

topdan selfkeduanya windowobjek (bersama dengan parent), jadi Anda melihat apakah jendela Anda adalah jendela teratas.

Greg
sumber
4
Ini sepertinya berfungsi baik di Firefox. Apakah itu berfungsi di browser lain juga?
akshat
5
Memiliki halaman dengan iframe di dalam iframe, untuk menguji dari iframe anak saya jika iframe orang tua saya tertanam di halaman, saya menggunakan if (parent === top)
sglessard
7
@sglessard Jika halaman anak dan orang tua berasal dari domain yang berbeda maka Firefox akan mengadu karena Kebijakan Asal yang Sama (www.w3.org/Security/wiki/Same_Origin_Policy) dan kode tidak akan berfungsi
Gaurang Jadia
18
Ini berfungsi di IE 11, 10, dan 9 untuk saya. Juga berfungsi di FF dan Opera serta, tentu saja, Chrome. Saya belum mengalami masalah dengan itu.
jeremysawesome
4
Bagi mereka yang masih goyang teknologi terbaru pada 1995, window.self !== window.topkembali trueketika dijalankan dari dalam isi frame, atau iframe .
Jeromy French
84

Ketika dalam iframe dengan asal yang sama dengan induknya, window.frameElementmetode mengembalikan elemen (misalnya iframeatau object) di mana jendela tertanam. Kalau tidak, jika menjelajah dalam konteks tingkat atas, atau jika kerangka induk dan anak memiliki asal yang berbeda, itu akan dievaluasi null.

window.frameElement
  ? 'embedded in iframe or object'
  : 'not embedded or cross-origin'

Ini adalah Standar HTML dengan dukungan dasar di semua browser modern.

Konstantin Smolyanin
sumber
2
Catatan yang mencoba membaca frameElementakan melemparkan pengecualian SecurityError dalam iframe lintas asal, menurut W3C ( WHATWG mengatakan itu harus mengembalikan null sebagai gantinya). Jadi, Anda mungkin ingin membungkusnya dalam sebuah try...catchpernyataan.
Oriol
5
masuk nulldan keluar dariiframe
OlehZiniak
4
Deskripsi di MDN mengatakan bahwa "jika dokumen yang disematkan memiliki asal yang berbeda (seperti telah ditemukan dari domain yang berbeda), ini adalah nol."
xeophin
Hanya untuk menjelaskan apa yang harus dikembalikan:Returns the element (such as <iframe> or <object>) in which the window is embedded, or null if the element is either top-level or is embedded into a document with a different script origin; that is, in cross-origin situations.
Art3mix
26

RoBorg benar, tetapi saya ingin menambahkan catatan tambahan.

Di IE7 / IE8 ketika Microsoft menambahkan Tab ke browser mereka, mereka merusak satu hal yang akan menyebabkan kekacauan dengan JS Anda jika Anda tidak hati-hati.

Bayangkan tata letak halaman ini:

MainPage.html
  IframedPage1.html   (named "foo")
  IframedPage2.html   (named "bar")
    IframedPage3.html (named "baz")

Sekarang dalam bingkai "baz" Anda mengklik tautan (tanpa target, memuat dalam bingkai "baz") itu berfungsi dengan baik.

Jika halaman yang dimuat, mari kita menyebutnya special.html, gunakan JS untuk memeriksa apakah "itu" memiliki kerangka induk bernama "bar" itu akan mengembalikan true (diharapkan).

Sekarang katakanlah bahwa halaman special.html ketika dimuat, periksa kerangka induk (untuk keberadaan dan namanya, dan jika "bilah", ia memuat ulang dirinya sendiri dalam bingkai bilah. Misalnya

if(window.parent && window.parent.name == 'bar'){
  window.parent.location = self.location;
}

Sejauh ini bagus. Sekarang tiba bug.

Katakanlah daripada mengklik tautan asli seperti biasa, dan memuat halaman special.html dalam bingkai "baz", Anda mengekliknya di tengah atau memilih untuk membukanya di Tab baru.

Saat itu, tab baru dimuat ( tanpa bingkai induk sama sekali! ) IE akan memasuki lingkaran tanpa akhir pemuatan halaman! karena IE "menyalin" struktur frame dalam JavaScript sehingga tab baru TIDAK memiliki orangtua, dan orangtua itu MEMILIKI nama "bar".

Berita baiknya, adalah:

if(self == top){
  //this returns true!
}

di tab baru itu mengembalikan true, dan dengan demikian Anda dapat menguji kondisi aneh ini.

scunliffe
sumber
Apakah bug telah diperbaiki sementara itu? Saya tidak dapat mereproduksi di IE8. Saya selalu mendapatkan yang benar window.parent.
user123444555621
1
Tidak yakin - Saya akan menjalankan suite pengujian saya terhadap IE9 dan di bawah lagi dan memposting pembaruan.
scunliffe
18

Jawaban yang diterima tidak berfungsi untuk saya di dalam skrip konten dari Ekstensi Firefox 6.0 (Addon-SDK 1.0): Firefox mengeksekusi skrip konten di masing-masing: jendela tingkat atas dan di semua iframe.

Di dalam skrip konten saya mendapatkan hasil berikut:

 (window !== window.top) : false 
 (window.self !== window.top) : true

Yang aneh tentang output ini adalah selalu sama terlepas apakah kode dijalankan di dalam iframe atau jendela tingkat atas.

Di sisi lain Google Chrome tampaknya hanya menjalankan script konten saya sekali dalam jendela tingkat atas, sehingga di atas tidak akan berfungsi sama sekali.

Apa yang akhirnya berhasil bagi saya dalam skrip konten di kedua browser adalah ini:

 console.log(window.frames.length + ':' + parent.frames.length);

Tanpa iframe ini tercetak 0:0, di jendela tingkat atas berisi satu frame yang dicetak 1:1, dan hanya dalam iframe dokumen yang dicetaknya 0:1.

Ini memungkinkan ekstensi saya untuk menentukan di kedua browser apakah ada iframe yang ada, dan juga di Firefox jika dijalankan di dalam salah satu iframe.

magnoz
sumber
1
Coba document.defaultView.self === document.defaultView.topatau window !== window.top. Dalam skrip konten add-on SDK Firefox, selfobjek global adalah objek yang digunakan untuk berkomunikasi dengan skrip utama.
Rob W
13

Saya tidak yakin bagaimana contoh ini bekerja untuk browser Web yang lebih lama, tetapi saya menggunakan ini untuk IE, Firefox dan Chrome tanpa dan mengeluarkan:

var iFrameDetection = (window === window.parent) ? false : true;
portal TheAnGeLs
sumber
6
Atau cukup!(window===window.parent)
CalculatorFeline
11
window! == window.parent
Ivan Leonenko
5

Saya menggunakan ini:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
mikewolf78
sumber
Mengapa Anda melakukan ini .indexOf("HTMLIFrameElement"):?
Luke
.indexOf ('foobarbaz')> -1 adalah cara untuk memeriksa "kecocokan substring" (yaitu, apakah 'foobarbaz' dapat ditemukan di suatu tempat di dalam string?), tetapi tanpa menggunakan ekspresi reguler. Secara logis setara dengan .match (/ foobarbaz /). Ini (digunakan untuk :-) bekerja pada browser yang lebih luas, dan masih dapat digunakan karena kebiasaan atau karena kekhawatiran tentang kinerja mesin ekspresi reguler.
Chuck Kollars
2

Gunakan fungsi javascript ini sebagai contoh tentang cara melakukannya.

function isNoIframeOrIframeInMyHost() {
// Validation: it must be loaded as the top page, or if it is loaded in an iframe 
// then it must be embedded in my own domain.
// Info: IF top.location.href is not accessible THEN it is embedded in an iframe 
// and the domains are different.
var myresult = true;
try {
    var tophref = top.location.href;
    var tophostname = top.location.hostname.toString();
    var myhref = location.href;
    if (tophref === myhref) {
        myresult = true;
    } else if (tophostname !== "www.yourdomain.com") {
        myresult = false;
    }
} catch (error) { 
  // error is a permission error that top.location.href is not accessible 
  // (which means parent domain <> iframe domain)!
    myresult = false;
}
return myresult;
}
Rolf
sumber
2

Terbaik untuk sekarang Legacy Browser Frame Breaking Script

Solusi lain tidak berhasil untuk saya. Ini berfungsi di semua browser:

Salah satu cara untuk mempertahankan diri terhadap clickjacking adalah dengan memasukkan skrip "frame-breaker" di setiap halaman yang tidak boleh dibingkai. Metodologi berikut akan mencegah halaman web dibingkai bahkan di browser lama, yang tidak mendukung Header X-Frame-Options-Header.

Dalam elemen KEPALA dokumen, tambahkan berikut ini:

<style id="antiClickjack">body{display:none !important;}</style>

Pertama-tama terapkan ID ke elemen style itu sendiri:

<script type="text/javascript">
   if (self === top) {
       var antiClickjack = document.getElementById("antiClickjack");
       antiClickjack.parentNode.removeChild(antiClickjack);
   } else {
       top.location = self.location;
   }
</script>

Dengan cara ini, semuanya bisa ada dalam HEAD dokumen dan Anda hanya perlu satu metode / taglib di API Anda.

Referensi: https://www.codemagi.com/blog/post/194

Albert Olivé
sumber
1
framing bukan satu-satunya ancaman, bagaimana dengan keberatan (artinya menggunakan tag objek HTML5 yang menggantikan tag iframe) .. saya pikir ini tidak akan berhasil melawan itu ..
Raymond Nijland
2
if ( window.location !== window.parent.location ) 
{
      // The page is in an iframe   
} 
else 
{     
      // The page is not in an iframe   
}
William
sumber
1

Karena Anda bertanya dalam konteks aplikasi facebook, Anda mungkin ingin mempertimbangkan untuk mendeteksi ini di server ketika permintaan awal dibuat. Facebook akan memberikan banyak data querystring termasuk kunci fb_sig_user jika dipanggil dari iframe.

Karena Anda mungkin perlu memeriksa dan menggunakan data ini di aplikasi Anda, gunakan untuk menentukan konteks yang tepat untuk di-render.

HectorMac
sumber
1

Saya sebenarnya terbiasa memeriksa window.parent dan itu bekerja untuk saya, tetapi belakangan ini jendela adalah objek siklik dan selalu memiliki kunci induk, iframe atau tidak iframe.

Seperti komentar menyarankan membandingkan dengan window.parent bekerja keras. Tidak yakin apakah ini akan berfungsi jika iframe persis sama dengan laman web sebagai induk.

window === window.parent;
Jabran Saeed
sumber
di chrome dalam konteks jendela utama window.parent === windowadalah benar. Jadi jawaban Anda salah. Dan perbandingan ini dapat digunakan untuk memeriksa (setidaknya dalam chrome, tidak mengujinya di browser lain).
MarkosyanArtur
TIDAK BEKERJA dalam konteks iFrame, tetapi `if (window === window.parent) {` tidak. Saya tidak menandai Anda karena saya tidak tahu mengapa itu tidak berhasil
www-0av-Com
-1

Ini adalah kode kuno yang saya gunakan beberapa kali:

if (parent.location.href == self.location.href) {
    window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}
Kesalahan601
sumber
Untuk menambah Eneko Alonso: ini berfungsi(parent.location == self.location)
piotr_cz
@piotr_cz, hanya berfungsi jika kebijakan asal yang sama mengizinkan akses parent.location. Kalau tidak, pengecualian dilemparkan
Dan
-1

Jika Anda ingin tahu apakah pengguna mengakses aplikasi Anda dari tab halaman facebook atau dari kanvas untuk memeriksa Permintaan yang Ditandatangani. Jika Anda tidak mendapatkannya, mungkin pengguna tidak mengakses dari facebook. Untuk memastikan konfirmasikan struktur bidang signed_request dan konten bidang.

Dengan php-sdk Anda bisa mendapatkan Permintaan yang Ditandatangani seperti ini:

$signed_request = $facebook->getSignedRequest();

Anda dapat membaca lebih lanjut tentang Permintaan yang Ditandatangani di sini:

https://developers.facebook.com/docs/reference/php/facebook-getSignedRequest/

dan di sini:

https://developers.facebook.com/docs/reference/login/signed-request/

Joao Belchior
sumber
-1

Ini berakhir menjadi solusi paling sederhana bagi saya.

    <p id="demofsdfsdfs"></p>

<script>

if(window.self !== window.top) {

//run this code if in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "in frame";

}else{

//run code if not in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "no frame";
}

</script>
Alex Roseland
sumber
-4
if (window.frames.length != parent.frames.length) { page loaded in iframe }

Tetapi hanya jika jumlah iframe berbeda di halaman Anda dan halaman yang memuat Anda di iframe. Jangan buat iframe di halaman Anda untuk mendapatkan jaminan 100% dari hasil kode ini

Vova Popov
sumber
Bukan solusi yang sangat elegan untuk menentukan apakah jendela di dalam iframe atau tidak, dan tidak ada jaminan Anda akan dapat membaca dari parent.frames juga.
Percy
-4

Tuliskan javascript ini di setiap halaman

if (self == top)
  { window.location = "Home.aspx"; }

Maka secara otomatis akan diarahkan ke halaman rumah.

shibin
sumber
4
Redirect Anda akan berfungsi saat Anda tidak berada di bingkai. Jadi saya tidak akan bisa menavigasi di situs Anda. Kedua, ada teknik untuk mencegah pengalihan dari halaman induk.
Marius Balčytis