Подтвердить что ты не робот

Внедрение iframe на страницу с ограничительной политикой безопасности контента

Я хочу создать расширение для браузера, которое создает боковую панель. Chrome не имеет первоклассной боковой панели, поэтому вместо этого мы должны поместить на страницу iframe. Однако на многих страницах это нарушается из-за политики безопасности содержимого. Например, GitHub использует CSP, который не позволяет вставлять в него фреймы с других сайтов. Например, если вы попытаетесь поместить сайт capitalone.com в iframe на GitHub, вы получите следующее:

Отказался от фрейма " https://www.capitalone.com/ ", поскольку он нарушает следующую директиву Политики безопасности содержимого: "frame-src 'self' render.githubusercontent.com www.youtube.com assets.braintreegateway.com".

Вот простое расширение браузера, чтобы воспроизвести это:

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
  if (changeInfo.status === 'complete') {
   chrome.tabs.executeScript(tabId, { code: 'document.body.innerHTML=\'<iframe style=\"width:600px; height:600px\" src=\"https://www.capitalone.com/\"></iframe>\' + document.body.innerHTML;' }, function() {
     console.log('Iframe injection complete');
   })
  }
}.bind(this));

Тем не менее, согласно Википедии, расширение браузера должно быть способно вставлять iframe, несмотря на любую политику безопасности контента:

Согласно Модели обработки CSP, [20] CSP не должен мешать работе надстроек или расширений браузера, установленных пользователем. Эта функция CSP позволяет любому дополнению или расширению вставлять сценарии в веб-сайты независимо от происхождения этого сценария и, таким образом, освобождается от политик CSP.

Есть ли какой-то другой способ, которым я должен вводить iframe помимо того, что я делаю?

4b9b3361

Ответ 1

Невозможность вставить внешний iframe в Chrome - ошибка (crbug.com/408932).

Если вы хотите встроить внешний фрейм во внешний веб-сайт, он должен быть загружен в фрейм, который поставляется вместе с вашим расширением.

manifest.json

{
    "name": "Embed external site",
    "version": "1",
    "manifest_version": 2,
    "content_scripts": [{
        "js": ["contentscript.js"],
        "matches": ["*://*/*"],
        "all_frames": true
    }],
    "web_accessible_resources": [
        "frame.html"
    ]
}

НЕ используйте chrome.tabs.onUpdated + chrome.tabs.executeScript если вы хотите, чтобы скрипт содержимого всегда вставлялся в документ. Ваша реализация имеет недостатки и может привести к многократному запуску скрипта. Вместо этого вы должны объявить скрипт содержимого в файле манифеста.

(удалите "all_frames": true если вы не хотите вставлять кадр в каждый субкадр.)

contentscript.js

// Avoid recursive frame insertion...
var extensionOrigin = 'chrome-extension://' + chrome.runtime.id;
if (!location.ancestorOrigins.contains(extensionOrigin)) {
    var iframe = document.createElement('iframe');
    // Must be declared at web_accessible_resources in manifest.json
    iframe.src = chrome.runtime.getURL('frame.html');

    // Some styles for a fancy sidebar
    iframe.style.cssText = 'position:fixed;top:0;left:0;display:block;' +
                           'width:300px;height:100%;z-index:1000;';
    document.body.appendChild(iframe);
}

frame.html

<style>
html, body, iframe, h2 {
    margin: 0;
    border: 0;
    padding: 0;
    display: block;
    width: 100vw;
    height: 100vh;
    background: white;
    color: black;
}
h2 {
    height: 50px;
    font-size: 20px;
}
iframe {
    height: calc(100vh - 50px);
}
</style>
<h2>Displaying https://robwu.nl in a frame</h2>
<iframe src="https://robwu.nl/"></iframe>

Важно отметить, что я загрузил сайт https во фрейм. Если вы попытаетесь загрузить сайт HTTP во фрейм, тогда политика смешанного контента будет блокировать загрузку фрейма, если один из родительских фреймов является страницей https.

Замените https://robwu.nl/ на http://example.com/ и рамка останется пустой на страницах https, таких как https://github.com. Одновременно на консоль будет выведено следующее сообщение.

[blocked] The page at 'https://github.com/' was loaded over HTTPS, but ran insecure content from 'http://example.com/': this content should also be loaded over HTTPS

Ответ 2

Ответ Rob W правильный. Вы можете следить за этим https://transitory.technology/browser-extensions-and-csp-headers/. Я успешно работаю над своим расширением Chrome https://github.com/onmyway133/github-chat

Обратите внимание, что я использую Chrome 59, поэтому я могу использовать большинство функций ES6.

Объявить в манифесте

"web_accessible_resources": [
  "iframe.html",
  "scripts/iframe.js"
]

Создать iframe в событии window.onload

let url    = decodeURIComponent(window.location.search.replace('?url=', ''))
let iframe = document.createElement('iframe')
iframe.src = url

iframe.id = 'github-chat-box-iframe-inner'
iframe.style.width = '100%'
iframe.style.height = '350px'
iframe.style.border = '0px'

window.onload = () => {
  document.body.appendChild(iframe)
}

Ответ 3

Ваш пример должен работать в Chrome, но в настоящее время он не из-за ошибки: https://code.google.com/p/chromium/issues/detail?id=408932. Ответ Rob W содержит хорошую работу для решения проблемы.

Ответ 4

Если мы реализуем ответ Rob W, возникают ли какие-либо проблемы при обмене данными между фреймами с помощью postmessage()? Я пытаюсь реализовать это в приложении Gmail, я хочу определить, когда открыт новый поток, и я хочу передать идентификатор потока в документ iframe, загруженный с сервера с несколькими источниками. Любые ответы будут более полезными :)