首页 文章

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

提问于
浏览
39

我想创建一个创建侧边栏的浏览器扩展 . Chrome没有一流的侧边栏,因此我们必须在页面中添加iframe . 但是,由于内容安全策略,这会在许多页面上中断 . 例如 . GitHub使用CSP,它不允许嵌入来自其他网站的iframe . 例如 . 如果您尝试将capitalone.com网站放在GitHub上的iframe中,您将获得以下内容:

拒绝框架'https://www.capitalone.com/',因为它违反了以下内容安全政策指令:“frame-src'self'recrera.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吗?

3 回答

  • 1

    无法在Chrome中插入外部iframe是一个错误(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 . 您的实现存在缺陷,可能导致脚本多次运行 . 相反,你应该declare the content script in the manifest file .

    (如果您不想在每个子帧中插入帧,请删除 "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 . 同时,以下消息将打印到控制台 .

    [已阻止]“https://github.com/”上的页面是通过HTTPS加载的,但是从“http://example.com/”运行了不安全的内容:此内容也应通过HTTPS加载

  • 3

    Rob W的回答是正确的 . 你可以按照这个https://transitory.technology/browser-extensions-and-csp-headers/ . 我已成功将其在Chrome扩展程序中运行https://github.com/onmyway133/github-chat

    请注意,我使用Chrome 59,因此我可以使用大多数ES6功能

    Declare in manifest

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

    Create an iframe in window.onload event

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

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

相关问题