Почему рамочные выключатели работают в междоменном режиме, и можете ли вы условно использовать рамочные выключатели?

Я недавно изучал фрейм, разбивающий код, и столкнулся с каким-то действительно странным поведением, связанным с та же самая политика происхождения, что у меня возникли проблемы с пониманием.

Предположим, у меня есть страница Breaker.html в домене A и страница Container.html в домене B. Примерный код разлома фрейма в Breaker.html, как показано ниже:

if (top !== self) top.location.href = self.location.href;

Это успешно сломает Breaker.html из Container.html, но я не понимаю, зачем это нужно. Из моего чтения той же политики происхождения, top.location не должен быть доступен вообще, поскольку Container.html находится в другом домене, чем Breaker.html. Даже более странно, кажется, что top.location только для записи:

// Fails if Container.html is on a different domain than Breaker.html
alert(top.location);

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

Итак, у меня есть два вопроса, в основном:

  • Почему код выше этого кода работает вообще?

  • Есть ли способ разорвать фреймы условно или это единственная проверка, которую можно сделать, - это top !== self? (В частности, я хочу иметь возможность читать домен, чтобы я мог предоставить список допустимых доменов, просто проверяя, находится ли я в том же домене или нет, не будет идеальным.)

Ответ 1

В ответ на номер 1: с точки зрения безопасности существует большая разница между доступом для чтения и доступом к записи. Возможность чтения top.location.href является проблемой безопасности. Возможность писать в top.location.href не является.

Что касается ответа на ваш вопрос, я не знаю javascript достаточно хорошо, чтобы быть уверенным, но одна идея заключалась бы в том, чтобы убедиться, что если чтение top.location не выполняется (проверьте исключения), оно находится в другом домене.

Ответ 2

Ответ на вопрос 1 заключается в том, что оператор равенства может использоваться против top.location.href по причинам, связанным с наследием. Breaker.html не может читать top.location.href, но он может сравнить его с другим значением.

Тогда ответ на вопрос 2 не станет, вы должны использовать == == для части, потому что вы не сможете сделать подстроку на top.location.href из перекрестного домена breaker.html.

Я мог ошибаться, но что я понимаю текущий мир iframe.

Ответ 3

Это вопрос номер 2: если вы хотите взять HREF из parent.location(не top.location), вы можете сделать это:

if ((window.top === window.parent) && (history.length==1)) parentHREF=document.referrer;

В основном, что делает этот код:
[1] Проверка, является ли родительский кадр верхней, поскольку вы можете взять только родительский HREF, даже если он не является верхним фреймом.
[2] Проверка того, была ли история iframe пустой, прежде чем загружать ее источник, потому что если нет... document.referrer вернет последний HREF в этой истории фреймов.

После этого вы есть новая проблема: в случае, если значение history.length больше одного, вы можете использовать белый список имен хостов, чтобы проверить, нужно ли его открывать или нет:

if ([location.hostname, 'stackoverflow.com'].indexOf(location.hostname)>=0) hasToBeOpened=true;

Обратите внимание, что у вас есть другая опция: можно использовать целевую страницу, чтобы проверить, открывается ли "первая" страница или нет, используйте этот код:

<head>
<script>
var parentHREF;
if ((window.top === window.parent) && (history.length==1)) parentHREF=document.referrer;
if (/*conditions mentiones above*/) document.write("<META http-equiv='refresh' content='0;URL=http://example.com/go-here.html'>");
</script>
</head>

Выполняя это, первая страница сначала заменит значение истории (в данном случае это первое). Этот код asuming "example.com" является вашим доменом.