SecurityError: заблокирован фрейм с источником от доступа к фрейму кросс-происхождения

Я загружаю <iframe> в моей HTML-странице и пытается получить доступ к элементам внутри нее с помощью Javascript, но когда я пытаюсь выполнить свой код, я получаю следующую ошибку:

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

Не могли бы вы помочь мне найти решение, чтобы я мог получить доступ к элементам в рамке?

Я использую этот код для тестирования, но напрасно:

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

10 ответов

Решение

Политика того же происхождения

Не путать с CORS!

Вы не можете получить доступ к <iframe> с другим происхождением, использующим JavaScript, было бы огромным недостатком безопасности, если бы вы могли это сделать. Для политик с одинаковым источником браузеры блокируют сценарии, пытаясь получить доступ к кадру с другим источником.

Источник считается другим, если не поддерживается хотя бы одна из следующих частей адреса:

<protocol>://<hostname>:<port>/path/to/page.html 

Протокол, имя хоста и порт должны совпадать с вашим доменом, если вы хотите получить доступ к фрейму.

Примеры

Вот что произойдет при попытке получить доступ к следующим URL-адресам из 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.html -> Failure: different protocol 
ftp://www.example.com:21                     -> Failure: different protocol & port 
https://google.com/search?q=james+bond       -> Failure: different hostname & protocol 

Временное решение

Несмотря на то, что политика одного и того же источника блокирует доступ сценариев к содержимому сайтов другого происхождения, если вы владеете обеими страницами, вы можете обойти эту проблему, используя window.postMessage и его родственник message Событие для отправки сообщений между двумя страницами, например:

  • На вашей главной странице:

    var frame = document.getElementById('your-frame-id'); 
    
    frame.contentWindow.postMessage(/*any variable or object here*/, '*'); 
    
  • В вашем <iframe> (содержится на главной странице):

    window.addEventListener('message', function(event) { 
    
        // IMPORTANT: Check the origin of the data! 
        if (~event.origin.indexOf('http://yoursite.com')) { 
            // The data has been sent from your site 
    
            // The data sent with postMessage is stored in event.data 
            console.log(event.data); 
        } else { 
            // The data hasn't been sent from your site! 
            // Be careful! Do not use it. 
            return; 
        } 
    }); 
    

Этот метод может применяться в обоих направлениях, создавая слушателя также на главной странице и получая ответы из фрейма. Та же логика также может быть реализована во всплывающих окнах и в основном в любом новом окне, генерируемом главной страницей (например, с использованием window.open()) а также без разницы.

Отключение политики того же происхождения в вашем браузере

На эту тему уже есть несколько хороших ответов (я просто нашел их в поиске), поэтому для браузеров, где это возможно, я приведу относительный ответ. Однако помните, что отключение политики одного и того же происхождения (или CORS) повлияет только на ваш браузер. Кроме того, запуск браузера с отключенными параметрами безопасности того же источника предоставляет любому веб-сайту доступ к ресурсам из разных источников, так что это очень небезопасно и должно выполняться только в целях разработки.

Дополняя ответ Марко Бонелли: лучший из существующих способов взаимодействия между фреймами / фреймами использует window.postMessage поддерживается всеми браузерами

Проверьте веб-сервер домена для http://www.<domain>.com конфигурация для X-Frame-OptionsЭто функция безопасности, предназначенная для предотвращения атак clickJacking,

Как работает ClickJacking?

  1. Злая страница выглядит точно так же, как страница жертвы.
  2. Затем он обманул пользователей, чтобы ввести их имя пользователя и пароль.

Технически зло имеет iframe с источником на страницу жертвы.

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

Как работает функция безопасности

Если вы хотите, чтобы запрос веб-сервера не обрабатывался в iframe добавить x-frame-options

X-Frame-Options DENY

Варианты:

  1. SAMEORIGIN // разрешить только моему собственному домену отображать мой HTML внутри iframe.
  2. DENY // не позволяем отображать мой HTML внутри любого iframe
  3. "ALLOW-FROM https://example.com/" // разрешить конкретному домену отображать мой HTML внутри iframe

Это пример конфигурации IIS:

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

Решение вопроса

Если веб-сервер активировал функцию безопасности, это может вызвать клиентскую ошибку SecurityError, как и должно быть.

Для меня я хотел реализовать двухстороннее рукопожатие, что означает:
- родительское окно будет загружаться быстрее, чем iframe
- iframe должен поговорить с родительским окном, как только он будет готов
- родитель готов получить сообщение iframe и повторить

этот код используется для установки белой метки в iframe с помощью [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","*");
    }
});

родитель

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

естественно, вы можете ограничить происхождение и текст, это легко работать с кодом
я нашел этот экзамен полезным:
[Междоменный обмен сообщениями с postMessage]

На самом деле есть обходной путь для конкретных сценариев.

Если у вас есть два процесса, работающих в одном домене, но на разных портах, два окна могут взаимодействовать без ограничений. (т.е. localhost:3000& localhost:2000). Чтобы это работало, каждое окно должно изменить свой домен на общий источник:

      document.domain = 'localhost'

Это также работает в том случае, если вы работаете с разными поддоменами в одном домене второго уровня, т.е. john.site.comпытаясь получить доступ peter.site.comили просто site.com

      document.domain = 'site.com'

Явно установив document.domain; браузер будет игнорировать разницу в имени хоста, и окна можно рассматривать как исходящие из «одного и того же источника». Теперь в родительском окне вы можете добраться до iframe: frame.contentWindow.document.body.classList.add('happyDev')

Я столкнулся с этой ошибкой при попытке встроить iframe и затем открыть сайт с помощью Brave. Ошибка исчезла, когда я перешел на "Shields Down" для рассматриваемого сайта. Очевидно, что это не полное решение, поскольку любой, кто посещает сайт с Brave, столкнется с той же проблемой. Чтобы действительно решить эту проблему, мне нужно было бы сделать одно из других действий, перечисленных на этой странице. Но по крайней мере теперь я знаю, в чем проблема.

Если у вас есть контроль над содержимым iframe, то есть если он просто загружается в настройках с несколькими источниками, например, в Amazon Mechanical Turk, вы можете обойти эту проблему с помощью <body onload='my_func(my_arg)'> атрибут для внутреннего html.

Например, для внутреннего html используйте this html параметр (да - this определен и относится к родительскому окну внутреннего элемента тела):

<body onload='changeForm(this)'>

Во внутреннем html:

    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>

Я хотел бы добавить специальную конфигурацию Java Spring, которая может повлиять на это.

В приложении веб-сайта или шлюза есть параметр contentSecurityPolicy

в Spring вы можете найти реализацию подкласса 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)

Браузер будет заблокирован, если вы не укажете здесь безопасный внешний контент.

Мое приложение зависало с SecurityError когда помещено внутрь iframe, Проблема была с JQuery's .animate({scrollTop: top}, 0) применяется на window непосредственно.

Удаление этого LOC решило проблему для нас.

Откройте меню "Пуск"
Наберите windows+R или откройте "Выполнить"
Выполните следующую команду.

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security
Другие вопросы по тегам