Javascript, трек iframe, перенаправляющий верхнее окно

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

Есть ли способ отслеживать/выяснить, какой из них (конкретный iframe) вызвал перенаправление верхнего кадра?

Вот песочница (используйте консоль браузера и включите журнал сохранения):

Edit 3v50wqxz66

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

Ответ 1

Мы можем получить доступ к содержимому iframe с помощью somethig, например iframe.contentWindow.document но это возможно, если мы соблюдаем политику одинакового происхождения.

Другой подход может заключаться в создании заголовка Content-Security-Policy например:

<meta http-equiv="Content-Security-Policy" content="frame-src http://example.com">

Этот заголовок на родительской странице предотвращает загрузку сайтов, отличных от http://example.com, в фреймах. Существует также способ сообщить о поведении отправителя сообщения, но, к сожалению, не может быть установлен с <meta> (только он сервер). При таком подходе мы должны выполнить белый список, поэтому я думаю, что, возможно, это не полезно в этом случае. Но, если белый список указан в первый раз, можно установить все доступные сайты, поэтому при перенаправлении iframe браузер откажется его загрузить.

Если это не так, как в случае с одним и тем же происхождением и с возможностью выполнения белого списка, то я думаю, что лучше, чем мы можем сделать, это вызывать событие iframe onunload, к сожалению это событие будет onunload также, когда страница iframe перезагружает не только перенаправление. Я думаю, что это самый близкий подход. Для этого этот код работает.

var srcs = ["iframe2.html","iframe.html","iframe2.html"];


        for (let i = 0; i < srcs.length; i++) {
            var iframe = document.createElement('iframe'); 
                iframe.src = srcs[i]; 
                iframe.name = "i"+i; 
                document.body.appendChild(iframe);
                window["i"+i].onunload = function(){console.log("change "+i)}
        }

Конечно, onunload запускается в первый раз, когда все фреймы загружаются, поэтому перенаправления 2-го 3-го и так далее. Но мы можем исключить этот первый случай.

Здесь полный пример https://codesandbox.io/s/o16yk7mqy, я создал iframe3.html, который не обновляет ни перезагрузку, чтобы четко показать эту точку. Также я создал простой список перенаправления или перезагрузки iframes.

ОБНОВЛЕНИЕ Как я понимаю сейчас, вы хотите установить iframes с свойством песочницы и белый список всего, что вы хотите, но без allow-top-navigation, что-то вроде:

<iframe src="iframe.html" sandbox="allow-script allow-forms allow-popups allow-pointer-lock allow-same-origin"></iframe>
  • Этот пример не позволяет allow-top-navigation https://codesandbox.io/s/lpmv6wr6y9
  • Этот пример здесь https://codesandbox.io/s/4x8v1mojq7 разрешает правдокументальную allow-top-navigation но codesandbox предотвращает перенаправление фрейма, поэтому, если мы попробуем https://4x8v1mojq7.codesandbox.io/, то есть url, созданный с помощью codeandbox, мы может видеть перезагрузку верхнего кадра.

Как я уже сказал в комментариях, по крайней мере Chrome 64.0.3282.167, когда мы делегируем все, кроме разрешенной навигации, когда iframe пытается перенаправить верхний фрейм, он генерирует исключение. В Firefox по-разному по-разному (не менее 58.0.2). Firefox запрещает верхнюю навигацию, но продолжает код.

Итак, как вывод, лучший подход, на мой взгляд, или сочетание sanbox и onunload или просто onunload. Конечно, если это будет возможно, Content-Security-Policy является самым безопасным и более гибким способом. Это зависит от реализации. Это почти невозможно. Я думаю, что не нужно использовать код на стороне сервера, чтобы выполнить идеальное решение. Есть белый список для проверки, как этот API https://developers.google.com/safe-browsing/v4/, и есть черный список для проверки, посмотрите это сообщение https://security.stackexchange.com/questions/32058/look-for-url-blacklists-of-malicious-websites.

Ответ 2

Если у вас есть контроль над всеми вашими фреймами, вы можете реализовать взаимодействие между фреймами с postMessage. Поток:

  1. Кадр хочет выполнить перенаправление - он отправляет сообщение родительскому кадру с запросом на перенаправление.
  2. Родительский кадр выполняет перенаправление и знает, какой кадр вызвал перенаправление.

родитель:

window.addEventListener("message", (event) => {
    // show message source (your frame)
    console.log(event.source);

    const message = event.data;
    console.log('Frame ID: ${message.frameId}');

    if(message.messageType === "redirect") {
        window.location.href = message.redirectUrl;
    }
});

Детский каркас:

function redirect(url) {
    var message = {
        messageType: "redirect",
        frameId: "frame1"
        redirectUrl: url
    }
    window.parent.postMessage(message, "*");
}

Ответ 3

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

window.onbeforeunload = function (e) {
  console.log(e.currentTarget.location.href);
  return 'Stop redirection. Show dialog box.';
};

Ответ 4

Из отдельных iframes вы можете установить cookie, когда происходит перенаправление? Скажем, это произошло из iframe1, вы можете установить cookie как

document.trackFrame = "FrameName=iframe1";  

И как только перенаправление завершится, вы можете попробовать прочитать файл cookie и определить, какой iframe вызвал перенаправление?