จะระบุได้อย่างไรว่าหน้าเว็บกำลังโหลดอยู่ภายใน iframe หรือโดยตรงไปยังหน้าต่างเบราว์เซอร์?


596

ฉันกำลังเขียนแอพ Facebook ที่ใช้ iframe ตอนนี้ฉันต้องการใช้หน้า html เดียวกันเพื่อแสดงผลเว็บไซต์ปกติเช่นเดียวกับเพจ Canvas ภายใน Facebook ฉันต้องการทราบว่าฉันสามารถตรวจสอบว่าหน้าได้รับการโหลดภายใน iframe หรือโดยตรงในเบราว์เซอร์?


2
วิธีที่ดีไม่กี่ (รวมถึงความคิดเห็น): tommcfarlin.com/check-if-a-page-is-in-an-an-iframe
simhumileco

คำตอบ:


1106

เบราว์เซอร์สามารถปิดกั้นการเข้าถึงwindow.topเนื่องจากนโยบายกำเนิดเดียวกัน ข้อบกพร่องของ IE ก็เกิดขึ้นเช่นกัน นี่คือรหัสการทำงาน:

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

topและselfเป็นทั้งwindowวัตถุ (พร้อมด้วยparent) ดังนั้นคุณจะเห็นว่าหน้าต่างของคุณเป็นหน้าต่างด้านบนหรือไม่


4
ดูเหมือนว่าจะทำงานได้ดีใน Firefox ใช้ได้กับเบราว์เซอร์อื่นหรือไม่
akshat

5
มีหน้ากับ iframe ภายใน iframe เพื่อทดสอบจาก iframe ลูกของฉันถ้า
ฝัง

7
@sglessard หากหน้าย่อยและผู้ปกครองมาจากโดเมนที่แตกต่างกัน Firefox จะบ่นสำหรับนโยบายแหล่งกำเนิดเดียวกัน (www.w3.org/Security/wiki/Same_Origin_Policy) และรหัสจะไม่ทำงาน
Gaurang Jadia

18
สิ่งนี้ใช้ได้ใน IE 11, 10 และ 9 สำหรับฉัน นอกจากนี้ยังสามารถใช้งานได้ใน FF และ Opera เช่นเดียวกับ Chrome ฉันไม่ได้พบปัญหาใด ๆ กับมัน
jeremysawesome

4
สำหรับผู้ที่ยังคงโยกล่าสุดในปี 1995 เทคโนโลยีwindow.self !== window.topผลตอบแทนtrueเมื่อเรียกใช้จากภายในเนื้อหาของframe, หรือ iframe
Jeromy French

84

เมื่ออยู่ใน iframe บนต้นกำเนิดเดียวกันกับพาเรนต์window.frameElementเมธอดจะส่งคืนองค์ประกอบ (เช่นiframeหรือobject) ที่ฝังหน้าต่าง nullมิฉะนั้นถ้าการเรียกดูในบริบทระดับบนหรือถ้าผู้ปกครองและกรอบเด็กที่มีต้นกำเนิดที่แตกต่างกันก็จะประเมิน

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

นี่คือมาตรฐาน HTMLพร้อมการสนับสนุนขั้นพื้นฐานในเบราว์เซอร์ที่ทันสมัยทั้งหมด


2
หมายเหตุความพยายามในการอ่านframeElementจะส่งข้อยกเว้น SecurityError ใน iframe แบบข้ามแหล่งอ้างอิงตามW3C ( WHATWGบอกว่าควรคืนค่า null แทน) ดังนั้นคุณอาจต้องการห่อมันไว้ในtry...catchคำสั่ง
Oriol

5
เดินทางnullเข้าและออกจากiframe
OlehZiniak

4
คำอธิบายที่MDNบอกว่า "ถ้าเอกสารที่ฝังอยู่นั้นมีต้นกำเนิดที่แตกต่างกัน (เช่นถูกวางจากโดเมนอื่น) นี่เป็นโมฆะ"
xeophin

เพียงเพื่อผลตอบแทน clerify สิ่งที่ควรจะเป็น: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 ถูกต้อง แต่ฉันต้องการที่จะเพิ่มบันทึกด้านข้าง

ใน IE7 / IE8 เมื่อ Microsoft เพิ่มแท็บลงในเบราว์เซอร์พวกเขาทำสิ่งหนึ่งที่จะทำให้เกิดความเสียหายกับ JS ของคุณหากคุณไม่ระวัง

ลองนึกภาพเค้าโครงหน้านี้:

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

ตอนนี้ในเฟรม "baz" คุณคลิกลิงก์ (ไม่มีเป้าหมายโหลดในเฟรม "baz") มันใช้งานได้ดี

หากหน้าเว็บที่ได้รับการโหลดให้เรียกมันว่า special.html ใช้ JS เพื่อตรวจสอบว่า "มัน" มีเฟรมหลักชื่อ "บาร์" หรือไม่มันจะกลับมาจริง (คาดว่า)

ตอนนี้ให้บอกว่าหน้าพิเศษ.htmlเมื่อมันโหลดตรวจสอบเฟรมหลัก (สำหรับการมีอยู่และชื่อและถ้าเป็น "บาร์" มันจะโหลดตัวเองในเฟรมบาร์เช่น

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

จนถึงตอนนี้ดีมาก ตอนนี้ข้อผิดพลาดมา

ให้บอกว่าแทนที่จะคลิกที่ลิงค์เดิมเช่นปกติและโหลดหน้าพิเศษ.htmlในกรอบ "baz" คุณคลิกกลางหรือเลือกที่จะเปิดในแท็บใหม่

เมื่อแท็บใหม่นั้นโหลด ( โดยไม่มีเฟรมหลักเลย! ) IE จะเข้าสู่วงวนไม่รู้จบของการโหลดหน้าเว็บ! เนื่องจาก IE "คัดลอก" โครงสร้างของเฟรมใน JavaScript ดังนั้นแท็บใหม่จะมีพาเรนต์และพาเรนต์นั้นมีชื่อ "bar"

ข่าวดีก็คือการตรวจสอบ:

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

ในแท็บใหม่นั้นคืนค่าจริงและทำให้คุณสามารถทดสอบเงื่อนไขแปลก ๆ นี้ได้


มีการแก้ไขข้อบกพร่องในระหว่างนี้หรือไม่? ฉันไม่สามารถทำซ้ำได้ใน IE8 ฉันได้รับสิ่งที่ถูกต้องwindow.parentเสมอ
123444555621

1
ไม่แน่ใจ - ฉันจะรันชุดทดสอบกับ IE9 ขึ้นไปอีกครั้งแล้วโพสต์การอัปเดต
scunliffe

18

คำตอบที่ยอมรับไม่ได้สำหรับฉันภายในสคริปต์เนื้อหาของ Firefox 6.0 Extension (Addon-SDK 1.0): Firefox ดำเนินการสคริปต์เนื้อหาในแต่ละ: หน้าต่างระดับบนสุดและใน iframes ทั้งหมด

ภายในสคริปต์เนื้อหาฉันได้รับผลลัพธ์ต่อไปนี้:

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

สิ่งที่แปลกเกี่ยวกับผลลัพธ์นี้ก็คือมันจะเหมือนเดิมเสมอไม่ว่าจะรันโค้ดใน iframe หรือหน้าต่างระดับบนสุดก็ตาม

ในทางกลับกัน Google Chrome ดูเหมือนว่าจะรันสคริปต์เนื้อหาของฉันเพียงครั้งเดียวภายในหน้าต่างระดับบนสุดดังนั้นสิ่งที่กล่าวมาจะไม่ทำงานเลย

สิ่งที่ได้ผลสำหรับฉันในสคริปต์เนื้อหาในเบราว์เซอร์ทั้งสองคือ:

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

โดยไม่ต้องพิมพ์ใน iframe นี้0:0ในหน้าต่างระดับบนสุดที่มีกรอบมันพิมพ์1:1และใน iframe 0:1เพียงของเอกสารมันพิมพ์

สิ่งนี้ทำให้ส่วนขยายของฉันสามารถระบุได้ทั้งในเบราว์เซอร์หากมี iframes ใด ๆ อยู่และนอกจากนี้ใน Firefox หากมีการเรียกใช้ภายใน iframes ใดตัวหนึ่ง


1
ลองหรือdocument.defaultView.self === document.defaultView.top window !== window.topในสคริปต์เนื้อหา add-on SDK ของ Firefox selfวัตถุทั่วโลกเป็นวัตถุที่ใช้ในการสื่อสารกับสคริปต์หลัก
Rob W

13

ฉันไม่แน่ใจว่าตัวอย่างนี้ใช้ได้กับเว็บเบราว์เซอร์รุ่นเก่า แต่ฉันใช้สิ่งนี้กับ IE, Firefox และ Chrome ที่ไม่มีและปัญหา:

var iFrameDetection = (window === window.parent) ? false : true;

6
หรือเพียงแค่!(window===window.parent)
CalculatorFeline

11
หน้าต่าง! == window.parent
Ivan Leonenko

5

ฉันใช้สิ่งนี้:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);

ทำไมคุณทำเช่นนี้: .indexOf("HTMLIFrameElement")?
ลูกา

.indexOf ('foobarbaz')> -1 เป็นวิธีการตรวจสอบ "การจับคู่สตริงย่อย" (เช่นสามารถ 'foobarbaz' พบที่ใดที่หนึ่งในสตริงหรือไม่) แต่ไม่ต้องใช้นิพจน์ทั่วไป มันเทียบเท่ากับ. match (/ foobarbaz /) มันเคยชินกับ :-) ทำงานกับเบราว์เซอร์ที่กว้างขึ้นและยังอาจถูกใช้จนหมดนิสัยหรือเพราะกลัวเกี่ยวกับประสิทธิภาพของเครื่องจักรนิพจน์ทั่วไป
Chuck Kollars

2

ใช้ฟังก์ชั่นจาวาสคริปต์นี้เป็นตัวอย่างในการทำสิ่งนี้ให้สำเร็จ

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;
}

2

สคริปต์ทำลายเฟรมเบราว์เซอร์ที่ดีที่สุดสำหรับตอนนี้

โซลูชันอื่นไม่ทำงานสำหรับฉัน อันนี้ใช้ได้กับเบราว์เซอร์ทั้งหมด:

วิธีหนึ่งในการป้องกันการคลิกแจ็คกิ้งคือการรวมสคริปต์ "ตัวทำลายเฟรม" ไว้ในแต่ละหน้าเว็บที่ไม่ควรทำกรอบ วิธีการต่อไปนี้จะป้องกันเว็บเพจจากการถูกวางกรอบแม้ในเบราว์เซอร์ดั้งเดิมที่ไม่สนับสนุน X-Frame-Options-Header

ในองค์ประกอบ HEAD ของเอกสารให้เพิ่มสิ่งต่อไปนี้:

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

ก่อนอื่นให้ใช้ ID กับองค์ประกอบสไตล์เอง:

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

ด้วยวิธีนี้ทุกอย่างสามารถอยู่ในส่วนหัวของเอกสารและคุณต้องการเพียงหนึ่งวิธี / taglib ใน API ของคุณ

การอ้างอิง: https://www.codemagi.com/blog/post/194


1
กรอบไม่ได้เป็นเพียงภัยคุกคามสิ่งที่เกี่ยวกับการคัดค้าน (หมายถึงการใช้แท็กวัตถุ HTML5 ซึ่งแทนที่แท็ก iframe) .. ฉันคิดว่ามันจะไม่ทำงานกับที่ ..
Raymond Nijland


1

เนื่องจากคุณถูกถามในบริบทของแอพ facebook คุณอาจต้องการพิจารณาตรวจจับสิ่งนี้ที่เซิร์ฟเวอร์เมื่อมีการร้องขอครั้งแรก Facebook จะส่งข้อมูลการสอบถามจำนวนมากรวมถึงคีย์ fb_sig_user หากมีการเรียกใช้จาก iframe

เนื่องจากคุณอาจต้องตรวจสอบและใช้ข้อมูลนี้ในแอปของคุณอยู่ให้ใช้เพื่อกำหนดบริบทที่เหมาะสมในการแสดงผล


1

จริง ๆ แล้วฉันเคยตรวจสอบ window.parent และมันใช้งานได้สำหรับฉัน แต่เมื่อเร็ว ๆ นี้ window เป็นวัตถุแบบวงกลมและมักจะมีคีย์หลัก iframe หรือ iframe

เป็นความคิดเห็นที่แนะนำให้เปรียบเทียบอย่างหนักกับ window.parent ทำงาน ไม่แน่ใจว่าจะใช้งานได้หรือไม่หาก iframe นั้นเป็นหน้าเว็บเดียวกับพ่อแม่

window === window.parent;

ใน chrome ในบริบทหน้าต่างหลักwindow.parent === windowเป็นจริง ดังนั้นคำตอบของคุณไม่ถูกต้อง และการรวบรวมนี้สามารถใช้ตรวจสอบได้ (อย่างน้อยก็ใน Chrome ไม่ได้ทดสอบในเบราว์เซอร์อื่น)
MarkosyanArtur

ไม่ทำงานในบริบทของ iFrame แต่ `ถ้า (หน้าต่าง === window.parent) {` ทำ ฉันไม่ได้ทำเครื่องหมายให้คุณเพราะฉันไม่รู้ว่าทำไมมันไม่ทำงาน
www-0av-Com

-1

มันเป็นโค้ดโบราณที่ฉันใช้ไปสองสามครั้ง:

if (parent.location.href == self.location.href) {
    window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}

ในการเพิ่ม Eneko Alonso: งานนี้(parent.location == self.location)
piotr_cz

@piotr_cz ใช้งานได้เฉพาะในกรณีที่นโยบายต้นทางดั้งเดิมอนุญาตให้เข้าถึงparent.locationได้ มิฉะนั้นจะมีการโยนข้อยกเว้น
Dan

-1

หากคุณต้องการทราบว่าผู้ใช้เข้าถึงแอพของคุณจากแท็บหน้า Facebook หรือผ้าใบตรวจสอบคำขอลงนาม หากคุณไม่ได้รับอาจเป็นผู้ใช้ที่ไม่ได้เข้าถึงจาก facebook เพื่อให้แน่ใจว่าได้ยืนยันโครงสร้างเขตข้อมูล Sign_request และเนื้อหาในฟิลด์

ด้วย php-sdk คุณจะได้รับคำขอที่ลงนามเช่นนี้:

$signed_request = $facebook->getSignedRequest();

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับคำขอลงนามได้ที่นี่:

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

และที่นี่:

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


-1

นี่เป็นวิธีแก้ปัญหาที่ง่ายที่สุดสำหรับฉัน

    <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>

-4
if (window.frames.length != parent.frames.length) { page loaded in iframe }

แต่ถ้า iframe มีจำนวนแตกต่างกันในหน้าและหน้าของคุณที่โหลดคุณใน iframe ทำให้ iframe ในหน้าของคุณไม่มีการรับประกัน 100% สำหรับผลลัพธ์ของรหัสนี้


ไม่ใช่โซลูชันที่หรูหรามากในการพิจารณาว่าหน้าต่างอยู่ใน iframe หรือไม่และไม่มีการรับประกันว่าคุณจะสามารถอ่านจาก parent.frames ได้
Percy

-4

เขียนจาวาสคริปต์นี้ในแต่ละหน้า

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

จากนั้นจะเปลี่ยนเส้นทางไปยังหน้าแรกโดยอัตโนมัติ


4
การเปลี่ยนเส้นทางของคุณจะทำงานเมื่อคุณไม่ใช้เฟรม ดังนั้นฉันจะไม่สามารถนำทางในไซต์ของคุณ ประการที่สองมีเทคนิคเพื่อป้องกันการเปลี่ยนเส้นทางจากหน้าหลัก
Marius Balčytis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.