SecurityError: Memblokir bingkai dengan asal dari mengakses bingkai asal-silang

556

Saya memuat <iframe>di halaman HTML saya dan mencoba mengakses elemen di dalamnya menggunakan Javascript, tetapi ketika saya mencoba untuk mengeksekusi kode saya, saya mendapatkan kesalahan berikut:

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

Bisakah Anda membantu saya menemukan solusi agar saya dapat mengakses elemen dalam bingkai?

Saya menggunakan kode ini untuk pengujian, tetapi sia-sia:

$(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!";
    });
});
mubashermubi
sumber

Jawaban:

821

Kebijakan asal yang sama

Anda tidak dapat mengakses <iframe>dengan asal yang berbeda menggunakan JavaScript, itu akan menjadi kelemahan keamanan yang sangat besar jika Anda bisa melakukannya. Untuk browser kebijakan asal yang sama, blokir skrip yang mencoba mengakses bingkai dengan asal yang berbeda .

Asal dianggap berbeda jika setidaknya salah satu bagian alamat berikut ini tidak dikelola:

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

Protokol , nama host , dan port harus sama dengan domain Anda, jika Anda ingin mengakses sebuah bingkai.

CATATAN: Internet Explorer diketahui tidak sepenuhnya mengikuti aturan ini, lihat di sini untuk detailnya.

Contohnya

Inilah yang akan terjadi ketika mencoba mengakses URL berikut dari 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 

Penanganan masalah

Meskipun kebijakan yang sama-asal memblokir skrip untuk mengakses konten situs dengan asal yang berbeda, jika Anda memiliki kedua halaman, Anda dapat mengatasi masalah ini menggunakan window.postMessagedan messagekejadian relatifnya untuk mengirim pesan antara dua halaman, seperti ini:

  • Di halaman utama Anda:

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

    Argumen kedua untuk postMessage()dapat '*'menunjukkan tidak ada preferensi tentang asal tujuan. Asal target harus selalu disediakan bila memungkinkan, untuk menghindari pengungkapan data yang Anda kirim ke situs lain.

  • Di <iframe>(terkandung di halaman utama) Anda:

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

Metode ini dapat diterapkan di kedua arah , membuat pendengar di halaman utama juga, dan menerima tanggapan dari bingkai. Logika yang sama juga dapat diimplementasikan dalam pop-up dan pada dasarnya setiap jendela baru yang dihasilkan oleh halaman utama (misalnya menggunakan window.open()) juga, tanpa perbedaan apa pun.

Menonaktifkan kebijakan yang sama-asal pada browser Anda

Sudah ada beberapa jawaban bagus tentang topik ini (saya baru saja menemukan mereka googling), jadi, untuk browser yang memungkinkan, saya akan menautkan jawaban relatif. Namun, harap diingat bahwa menonaktifkan kebijakan asal yang sama hanya akan memengaruhi browser Anda . Selain itu, menjalankan peramban dengan pengaturan keamanan asal-sama yang dinonaktifkan memberikan akses situs web apa pun ke sumber daya lintas-asal, sehingga sangat tidak aman dan TIDAK PERNAH dilakukan jika Anda tidak tahu persis apa yang Anda lakukan (mis. Tujuan pengembangan) .

Marco Bonelli
sumber
27
Jawaban lain yang saya temukan 1 , 2 , menyarankan bahwa CORS / Access-Control-Allow-Origintidak berlaku untuk iFrames, hanya untuk XHRs, Fonts, WebGL dancanvas.drawImage . Saya percaya postMessageadalah satu-satunya pilihan.
TEPAT
369
Pertama kali saya melihat operator tilde "~" dalam javascript. Untuk siapa pun yang juga tidak tahu apa fungsinya: itu mengkonversi -1 ke 0, yang menghemat Anda harus melakukan "! = -1" pada hasil indexOf. Secara pribadi, saya pikir saya akan terus menggunakan "! = -1" karena lebih mudah bagi programmer lain untuk memahami dan menghindari bug yang datang dari lupa memasukkan tilde. (Tapi selalu menyenangkan untuk mempelajari sesuatu yang baru.)
Redzarf
4
@ SaabaAhang cukup periksa iframe.src, dan jika situs itu berbeda dari nama host domain Anda, maka Anda tidak dapat mengakses bingkai itu.
Marco Bonelli
18
@Snuggs benar-benar salah, ~mengembalikan komplemen angka 2, sehingga nmenjadi -n-1, artinya hanya -1akan menjadi 0(yang ditafsirkan sebagai false), dan nilai lain apa pun akan lulus ujian. Yaitu 0 = -(-1)-1tidak -(-1+1).
Marco Bonelli
2
@ user2568374 location.ancestorOrigins[0]adalah lokasi bingkai induk. Jika bingkai Anda berjalan di dalam situs lain dan Anda memeriksa menggunakan event.origin.indexOf(location.ancestorOrigins[0])Anda memeriksa apakah asal acara berisi alamat bingkai induk, yang selalu akan menjaditrue , oleh karena itu Anda mengizinkan setiap orangtua dengan asal mana pun untuk mengakses bingkai Anda, dan ini jelas bukan sesuatu yang ingin Anda lakukan. Lagipula, document.referreritu juga praktik buruk, seperti yang sudah saya jelaskan di komentar di atas.
Marco Bonelli
55

Melengkapi jawaban Marco Bonelli: cara terbaik saat ini untuk berinteraksi antara frame / iframe yang digunakan window.postMessage, didukung oleh semua browser

Geert
sumber
21
Meskipun tautan ini dapat menjawab pertanyaan, lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini dan memberikan tautan untuk referensi. Jawaban hanya tautan dapat menjadi tidak valid jika halaman tertaut berubah. - Dari Ulasan
Alessandro Cuttin
9
Saya tidak setuju, @AlessandroCuttin. Menjelaskan cara window.postMessagekerjanya hanya akan menggandakan jawaban yang diterima yang sudah saya referensi. Selain itu, nilai penting yang ditambahkan oleh jawaban saya persis dengan referensi dokumentasi eksternal.
Geert
5
Saya pikir ini lebih baik jika Anda dapat mengedit jawaban yang diterima dan menambahkannya di sana
Martin Massera
12
window.postMessage yang dapat kita gunakan hanya jika kita dapat mengakses kedua orangtua (halaman HTML kita) dan elemen anak-anak (iframe domain lain). Jika tidak "TIDAK ADA KEMUNGKINAN", itu akan selalu menimbulkan kesalahan "Uncaught DOMException: Memblokir bingkai dengan origin "< yourdomainname.com >" dari mengakses bingkai asal-silang. "
VIJAY P
19

Periksa server web domain untuk mengetahui http://www.<domain>.comkonfigurasi. X-Frame-Options Ini adalah fitur keamanan yang dirancang untuk mencegah serangan clickJacking,

Bagaimana cara kerja clickJacking?

  1. Halaman jahat terlihat persis seperti halaman korban.
  2. Kemudian itu menipu pengguna untuk memasukkan nama pengguna dan kata sandi mereka.

Secara teknis kejahatan memiliki iframesumber dengan halaman korban.

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

Cara kerja fitur keamanan

Jika Anda ingin mencegah permintaan server web untuk di-render dalam iframeadd x-frame-options

X-Frame-Options MENYANGKAL

Opsinya adalah:

  1. SAMAORIGIN // hanya izinkan domain saya membuat HTML saya di dalam iframe.
  2. DENY // jangan izinkan HTML saya di-render di dalam iframe apa pun
  3. "ALLOW-FROM https://example.com/ " // izinkan domain tertentu untuk merender HTML saya di dalam iframe

Ini adalah contoh konfigurasi IIS:

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

Solusi untuk pertanyaan itu

Jika server web mengaktifkan fitur keamanan, itu dapat menyebabkan SecurityError sisi klien sebagaimana mestinya.

Shahar Shokrani
sumber
1
Saya tidak berpikir bahwa X-Frame-Options berlaku di sini - X-Frame-Options ditentukan oleh halaman tamu (tertanam) dapat menyebabkan orang tua menolak untuk memuat halaman, tetapi sejauh yang saya tahu itu tidak mempengaruhi javascript akses - bahkan dengan X-Frame-Options: *, saya tidak berpikir Anda akan dapat mengakses DOM halaman tamu asal yang berbeda dengan javascript
Noah Gilmore
13

Bagi saya, saya ingin menerapkan jabat tangan 2 arah, yang berarti:
- jendela induk akan memuat lebih cepat dari iframe
- iframe harus berbicara ke jendela induk segera setelah siap
- induk siap menerima pesan iframe dan memutar ulang

kode ini digunakan untuk mengatur label putih di iframe menggunakan kode [CSS custom property]
:
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","*");
    }
});

induk

$(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);
});

secara alami Anda dapat membatasi asal dan teks, ini mudah-untuk-bekerja-dengan kode
saya menemukan ujian ini sangat membantu:
[Pesan Lintas Domain Dengan postMessage]

Yakir Manor
sumber
Saya berurusan dengan masalah dengan safari di mana dokumen di iframe mengeksekusi JS lebih lambat dari halaman induk yang menyebabkan pesan dikirim lebih awal dari dokumen di iframe mendengarkan pesan; yang persis berlawanan dengan apa yang dilakukan chrome dan firefox - sudahkah Anda menguji kode Anda di safari pada ios? btw postMessage dengan parameter kedua dari nilai "*" tidak cukup aman, Anda harus selalu menentukan domain
sKopheK
Blok kode pertama Anda, apakah itu di iframe di induknya atau di halaman yang dimuat ke iframe?
Demonic218
0

Saya ingin menambahkan konfigurasi khusus Java Spring yang dapat mempengaruhi ini.

Di situs Web atau aplikasi Gateway ada pengaturan contentSecurityPolicy

di Spring Anda dapat menemukan implementasi subkelas WebSecurityConfigurerAdapter

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

...

.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)

Browser akan diblokir jika Anda belum menentukan konten eksternal yang aman di sini.

ssp
sumber
0

Jika Anda memiliki kontrol atas konten iframe - yaitu, jika hanya dimuat dalam pengaturan asal-silang seperti di Amazon Mechanical Turk - Anda dapat menghindari masalah ini dengan <body onload='my_func(my_arg)'>atribut untuk html dalam.

Misalnya, untuk html dalam, gunakan thisparameter html (ya - thisdidefinisikan dan mengacu pada jendela induk dari elemen tubuh dalam):

<body onload='changeForm(this)'>

Di html dalam:

    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>
Zhanwen Chen
sumber
-25
  • Buka menu mulai
  • Ketik windows + R atau buka "Run
  • Jalankan perintah berikut.

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

sakthi sudhan
sumber
3
Bagus untuk tes cepat dan kotor!
user1068352
6
Mengerikan untuk apa pun yang bukan tes cepat dan kotor ... dan sudah membahas jawaban yang diterima.
Quentin
2
Bahkan dengan perintah, itu tidak berhasil karena Chrome menghindari menonaktifkan keamanan web dengan cara ini
Metafaniel