使用限制性内容安全策略将iframe注入页面

我想创build一个浏览器扩展,它创build一个侧边栏.Chrome没有一stream的侧边栏,所以我们必须在页面中放置一个iframe。 但是,由于内容安全策略,这在许多页面上都会中断。 例如,GitHub使用CSP,它不允许来自其他站点的iframe被embedded其中。 例如,如果您尝试将capitalone.com网站放在GitHub上的iframe中,您将得到以下结果:

拒绝框架“ 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,尽pipe有任何内容安全策略:

根据CSP处理模型,[20] CSP不应该干扰用户安装的浏览器插件或扩展的操作。 CSP的这一特性有效地允许任何插件或扩展插入脚本到网站,不pipe脚本的来源如何,从而免除CSP策略。

除了我在做什么之外,还有其他一些方法可以注入iframe吗?

在Chrome中无法插入外部iframe是一个错误( crbug.com/408932 )。

如果要在外部网站中embedded外部框架,则必须将其加载到与扩展件一起打包的框架中。

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如果您不想在每个子帧中插入帧, "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页面,则混合内容策略将阻止加载框架。

http://example.com/replacehttps://robwu.nl/ ,在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

您的示例应该可以在Chrome中使用,但是它目前并不是因为一个错误: https : //code.google.com/p/chromium/issues/detail?id = 408932 。 Rob W的答案包含了一个很好的解决问题的办法。

罗布W的答案是正确的。 你可以按照这个https://transitory.technology/browser-extensions-and-csp-headers/ 。 我已成功使其在我的Chrome扩展https://github.com/onmyway133/github-chat工作;

请注意,我使用Chrome 59,所以我可以使用大部分ES6function

在清单中声明

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

在window.onload事件中创build一个iframe

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