SecurityError: Orijinli bir karenin çapraz orijinli bir kareye erişmesini engelledi


555

<iframe>HTML sayfamda bir yükleme yapıyorum ve Javascript kullanarak içindeki öğelere erişmeye çalışıyorum, ancak kodumu yürütmeye çalıştığımda aşağıdaki hatayı alıyorum:

SecurityError: Blocked a frame with origin "http://www.<domain>.com" from accessing a cross-origin frame.

Lütfen çerçevedeki öğelere erişebilmem için bir çözüm bulmama yardım eder misiniz?

Bu kodu test etmek için kullanıyorum, ancak boşuna:

$(document).ready(function() {
    var iframeWindow = document.getElementById("my-iframe-id").contentWindow;

    iframeWindow.addEventListener("load", function() {
        var doc = iframe.contentDocument || iframe.contentWindow.document;
        var target = doc.getElementById("my-target-id");

        target.innerHTML = "Found it!";
    });
});

Yanıtlar:


820

Aynı menşe politikası

Sen olamaz bir erişmek <iframe>bunu eğer JavaScript kullanarak farklı kökenli olan, büyük bir güvenlik açığı olacaktır. İçin aynı kökenli ilke tarayıcılar komut farklı bir kökene sahip bir çerçeve erişmeye çalışıyor engellemek .

Adresin aşağıdaki bölümlerinden en az biri korunmazsa orijin farklı kabul edilir:

<protocol>://<hostname>:<port>/...

Bir çerçeveye erişmek istiyorsanız, protokol , ana makine adı ve bağlantı noktası alan adınızla aynı olmalıdır.

NOT: Internet Explorer'ın bu kurala tam olarak uymadığı bilinmektedir, ayrıntılar için buraya bakın.

Örnekler

Aşağıdaki URL’lere erişmeye çalışırken neler olacağı aşağıda açıklanmıştır: http://www.example.com/home/index.html

URL                                             RESULT 
http://www.example.com/home/other.html       -> Success 
http://www.example.com/dir/inner/another.php -> Success 
http://www.example.com:80                    -> Success (default port for HTTP) 
http://www.example.com:2251                  -> Failure: different port 
http://data.example.com/dir/other.html       -> Failure: different hostname 
https://www.example.com/home/index.html:80   -> Failure: different protocol
ftp://www.example.com:21                     -> Failure: different protocol & port 
https://google.com/search?q=james+bond       -> Failure: different protocol, port & hostname 

Geçici çözüm

Aynı köken ilkesi, komut dosyalarının farklı bir kökene sahip sitelerin içeriğine erişmesini engellemesine rağmen, her iki sayfaya da sahipsenizwindow.postMessagemessage , aşağıdaki gibi iki sayfa arasında ileti göndermek için bu sorunu ve göreceli etkinliğini kullanarak bu sorunu çözebilirsiniz :

  • Ana sayfanızda:

    let frame = document.getElementById('your-frame-id');
    frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.com');

    İkinci argüman , hedefin kökeni hakkında hiçbir tercih belirtmemek postMessage()olabilir '*'. Başka bir siteye gönderdiğiniz verileri ifşa etmekten kaçınmak için her zaman mümkün olduğunda bir hedef menşe sağlanmalıdır.

  • In sizin <iframe>(ana sayfada bulunan):

    window.addEventListener('message', event => {
        // IMPORTANT: check the origin of the data! 
        if (event.origin.startsWith('http://your-first-site.com')) { 
            // The data was sent from your site.
            // Data sent with postMessage is stored in event.data:
            console.log(event.data); 
        } else {
            // The data was NOT sent from your site! 
            // Be careful! Do not use it. This else branch is
            // here just for clarity, you usually shouldn't need it.
            return; 
        } 
    }); 

Bu yöntem, her iki yönde de uygulanabilir , ana sayfada da bir dinleyici oluşturur ve çerçeveden yanıtlar alır. Aynı mantık, pop-up'larda ve temelde ana sayfa tarafından oluşturulan herhangi bir yeni pencerede (örn. Kullanarak window.open()), herhangi bir fark olmadan da uygulanabilir.

Aynı kaynak politikasını devre dışı bırakılması için tarayıcınızda

Bu konu hakkında bazı iyi cevaplar var (onları sadece googling buldum), bu yüzden bunun mümkün olduğu tarayıcılar için göreceli cevabı bağlayacağım. Ancak, lütfen unutmayın aynı kaynak politikası devre dışı sadece etkileyecektir sizin tarayıcınızı . Ayrıca, aynı kökenli güvenlik ayarları devre dışı bırakılmış bir tarayıcı çalıştırmak, web siteleri arası kaynaklara herhangi bir erişim sağlar, bu nedenle çok güvensizdir ve ne yaptığınızı tam olarak bilmiyorsanız ASLA yapılmamalıdır (örn. Geliştirme amaçları) .


27
1 , 2 bulduğum diğer yanıtlar , CORS / öğelerinin iFramesAccess-Control-Allow-Origin için geçerli olmadığını, yalnızca XHR'ler, Fontlar, WebGL ve için geçerli olduğunu gösterircanvas.drawImage . postMessageTek seçenek olduğuna inanıyorum .
SnappieT

369
Javascript tilde "~" operatörü ilk kez gördüm. Ne yaptığını da bilmeyen herkes için: -1'i 0'a dönüştürür, bu da indexOf'un sonucuna "! = -1" yapmanızı sağlar. Şahsen, diğer programcıların tilde koymayı unutmaktan gelebilecek hataları anlaması ve bundan kaçınması için "! = -1" kullanmaya devam edeceğimi düşünüyorum. (Ama her zaman yeni bir şeyler öğrenmek güzel.)
Redzarf

4
@SabaAhang sadece kontrol edin iframe.srcve site alan adınızın ana bilgisayar adından farklıysa, bu kareye erişemezsiniz.
Marco Bonelli

17
@Snuggs tamamen yanlış, sayının ~2 tamamlayıcısını döndürür, böylece nolur -n-1, yani sadece -1olacak 0(olarak yorumlanır false) ve diğer herhangi bir değer testi geçecektir. IE 0 = -(-1)-1değil -(-1+1).
Marco Bonelli

2
@ user2568374 location.ancestorOrigins[0], ana çerçevenin konumudur. Çerçeveniz başka bir sitenin içinde çalışıyorsa ve bunu kullanarak event.origin.indexOf(location.ancestorOrigins[0])kontrol ediyorsanız, etkinliğin kaynağının her zaman olacak olantrue ebeveynin kare adresini içerip içermediğini kontrol edersiniz, bu nedenle herhangi bir kökene sahip herhangi bir ebeveynin çerçevenize erişmesine izin veriyorsunuz ve bu açıkçası yapmak istediğiniz bir şey değil. Ayrıca, yukarıdaki yorumlarda açıkladığım gibi, kötü bir uygulama. document.referrer
Marco Bonelli

55

Tamamlayıcı Marco Bonelli cevap: kullandığını çerçeve / iframe'lerden arasındaki etkileşim en iyi şimdiki yolu window.postMessage, tüm tarayıcılar tarafından desteklenen


21
Bu bağlantı soruyu cevaplayabilse de, cevabın temel kısımlarını buraya eklemek ve bağlantıyı referans olarak sağlamak daha iyidir. Bağlantı verilen sayfa değişirse, yalnızca bağlantı yanıtları geçersiz olabilir. - Yorumdan
Alessandro Cuttin

9
Kabul etmiyorum, @AlessandroCuttin. İşlerin nasıl yapıldığını açıklamak window.postMessagesadece daha önce başvurduğum kabul edilen cevabı çoğaltacaktır. Ayrıca, cevabımın kattığı temel değer, tam olarak dış belgelere gönderme yapmaktır.
Geert

5
Kabul edilen cevabı düzenleyebilir ve buraya ekleyebiliyorsanız daha iyi olduğunu düşünüyorum
Martin Massera

12
window.postMessage, yalnızca hem üst sayfaya (HTML sayfamız) hem de alt öğeye (diğer alan adı iframe) erişebiliyorsak kullanabiliriz.Aksi takdirde "OLASI OLAMAZ", her zaman bir hata atar "Yakalanmayan DOMException: Bir çerçeve engellendi "< alanadiniz.com.tr >" menşei, bir çapraz menşe kareye erişmekten. "
VIJAY P

19

Etki alanının web sunucusunu http://www.<domain>.comyapılandırma için kontrol edin. X-Frame-Options ClickJacking saldırılarını önlemek için tasarlanmış bir güvenlik özelliğidir.

ClickJacking nasıl çalışır?

  1. Kötü sayfa tam olarak kurban sayfasına benziyor.
  2. Ardından kullanıcıları kullanıcı adlarını ve şifrelerini girmeleri için kandırdı.

Teknik olarak kötülerin iframekurban sayfasına kaynak olan bir vardır.

<html>
    <iframe src='victim_domain.com'/>
    <input id="username" type="text" style="display: none;/>
    <input id="password" type="text" style="display: none;/>
    <script>
        //some JS code that click jacking the user username and input from inside the iframe...
    <script/>
<html>

Güvenlik özelliği nasıl çalışır?

Web sunucusu isteği önlemek istiyorsanız bir dahilinde işlenecek iframeeklenti x kare-seçenekleri

X-Frame-Seçenekler DENY

Seçenekler:

  1. SAMEORIGIN // HTML kodumu iframe içinde yalnızca kendi alanımın kullanmasına izin ver.
  2. DENY // HTML’imin iframe içinde oluşturulmasına izin verme
  3. "ALLOW-FROM https://example.com/ " // belirli alan adının HTML’mi iframe içinde oluşturmasına izin ver

Bu IIS yapılandırma örneğidir:

   <httpProtocol>
       <customHeaders>
           <add name="X-Frame-Options" value="SAMEORIGIN" />
       </customHeaders>
   </httpProtocol>

Sorunun çözümü

Web sunucusu güvenlik özelliğini etkinleştirdiyse, istemci tarafı SecurityError'a gerektiği gibi neden olabilir.


1
X-Frame-Options'ın burada uygulandığını düşünmüyorum - Konuk (katıştırılmış) sayfa tarafından tanımlanan X-Frame-Options, üst öğenin sayfayı yüklemeyi reddetmesine neden olabilir, ancak bildiğim kadarıyla javascript'i etkilemez erişimi - X-Frame-Options ile bile: *, farklı bir konuk sayfanın
Noah Gilmore

13

Benim için 2 yönlü bir el sıkışma uygulamak istedim, yani:
- ana pencere iframe'den daha hızlı yüklenecek
- iframe hazır olur olmaz ana pencereyle konuşmalıdır
- ebeveyn iframe mesajını almaya ve tekrarlamaya hazır

bu kod, [CSS custom property]
kodu kullanılarak iframe'deki beyaz etiketi ayarlamak için kullanılır :
iframe

$(function() {
    window.onload = function() {
        // create listener
        function receiveMessage(e) {
            document.documentElement.style.setProperty('--header_bg', e.data.wl.header_bg);
            document.documentElement.style.setProperty('--header_text', e.data.wl.header_text);
            document.documentElement.style.setProperty('--button_bg', e.data.wl.button_bg);
            //alert(e.data.data.header_bg);
        }
        window.addEventListener('message', receiveMessage);
        // call parent
        parent.postMessage("GetWhiteLabel","*");
    }
});

ebeveyn

$(function() {
    // create listener
    var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
    var eventer = window[eventMethod];
    var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
    eventer(messageEvent, function (e) {
        // replay to child (iframe) 
        document.getElementById('wrapper-iframe').contentWindow.postMessage(
            {
                event_id: 'white_label_message',
                wl: {
                    header_bg: $('#Header').css('background-color'),
                    header_text: $('#Header .HoverMenu a').css('color'),
                    button_bg: $('#Header .HoverMenu a').css('background-color')
                }
            },
            '*'
        );
    }, false);
});

doğal olarak kökenleri ve metni sınırlandırabilirsiniz, bu çalışması kolay kod ile
ben bu examlpe yararlı buldum: [ PostMessage ile Web
Alanları Arası Mesajlaşma]


iframe içindeki belgenin üst sayfadan sonra JS'sini yürüttüğü safari ile ilgili bir sorunla ilgileniyorum. hangisi krom ve firefox'un tam tersidir - kodunuzu iOS'ta Safari'de test ettiniz mi? btw post "*" değerinin ikinci parametresine sahip mesaj oldukça güvenli değil, her zaman alan adı belirtmelisiniz
sKopheK

İlk kod bloğunuz, üst öğedeki iframe'de mi yoksa iframe'e yüklenen sayfada mı?
Demonic218

0

Bunun üzerinde etkili olabilecek Java Spring'e özgü yapılandırma eklemek istiyorum.

Web sitesinde veya Ağ Geçidi uygulamasında bir contentSecurityPolicy ayarı var

İlkbaharda WebSecurityConfigurerAdapter alt sınıfının uygulanmasını bulabilirsiniz

contentSecurityPolicy("
script-src 'self' [URLDomain]/scripts ; 
style-src 'self' [URLDomain]/styles;
frame-src 'self' [URLDomain]/frameUrl...

...

.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)

Burada güvenli harici içerik tanımlamazsanız tarayıcı engellenir.


0

Iframe'in içeriği üzerinde kontrolünüz varsa - yani, sadece Amazon Mechanical Turk gibi bir çapraz kökenli kurulumda yüklüyse - bu sorunu <body onload='my_func(my_arg)'>iç html özelliğiyle atlayabilirsiniz.

Örneğin, iç html için thishtml parametresini kullanın (yes - thistanımlanır ve iç gövde öğesinin üst penceresine başvurur):

<body onload='changeForm(this)'>

İç HTML'de:

    function changeForm(window) {
        console.log('inner window loaded: do whatever you want with the inner html');
        window.document.getElementById('mturk_form').style.display = 'none';
    </script>

-24
  • Başlat menüsünü aç
  • Windows + R yazın veya "Çalıştır" ı açın
  • Aşağıdaki komutu yürütün.

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security


3
Hızlı ve kirli testler için iyi!
user1068352

6
Hızlı ve kirli bir test olmayan her şey için korkunç… ve kabul edilen cevapta zaten ele alın.
Quentin

2
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.