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) повлияет только на ваш браузер. Кроме того, запуск браузера с отключенными параметрами безопасности того же источника предоставляет любому веб-сайту доступ к ресурсам из разных источников, так что это очень небезопасно и должно выполняться только в целях разработки.
- Гугл Хром
- Mozilla Firefox
- Apple Safari: не возможно, только CORS.
- Опера: не возможно.
- Microsoft Edge: невозможно.
- Microsoft Internet Explorer: невозможно, только CORS.
Дополняя ответ Марко Бонелли: лучший из существующих способов взаимодействия между фреймами / фреймами использует window.postMessage
поддерживается всеми браузерами
Проверьте веб-сервер домена для http://www.<domain>.com
конфигурация для X-Frame-Options
Это функция безопасности, предназначенная для предотвращения атак clickJacking,
Как работает ClickJacking?
- Злая страница выглядит точно так же, как страница жертвы.
- Затем он обманул пользователей, чтобы ввести их имя пользователя и пароль.
Технически зло имеет 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
Варианты:
- SAMEORIGIN // разрешить только моему собственному домену отображать мой HTML внутри iframe.
- DENY // не позволяем отображать мой HTML внутри любого iframe
- "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