从Chrome扩展访问的iframe(Accessing iframe from chrome ex

2019-06-18 23:51发布

我正在开发一个Chrome扩展,并撞上了一个大问题。

我使用的内容脚本注入在一个网站上我的JavaScript代码。 该网站有一个iframe中。 我可以改变iframe的源代码,但似乎没有得到iframe的contentWindow财产的任何访问。 我需要它在当前位置CARRET插入文本。

所以基本上这个代码工作完全在页面的上下文:

$("#iframe1").contentWindow.document.execCommand("InsertHTML", false, 'test text');

但是,当我尝试在我的Chrome扩展程序的上下文中运行我得到这个错误:

TypeError: Cannot read property 'document' of undefined

什么奇怪的是,我可以访问iframe的HTML。 所以这个代码在Chrome扩展完美的作品:

$("#iframe1").contents().find('div').html('test')

我试图把“all_frames”:真正的清单文件,但没有运气:(

Answer 1:

要理解为什么你的代码不能正常工作,我包括我以前的答案的一个片段 :

内容脚本没有一个网页的全球任何访问window对象。 对于内容的脚本,应用如下:

  • window变量并不是指页面的全局对象。 相反,它指的是一个新的背景下,“层”在页面上。 该页面的DOM是完全无障碍。 #执行环境

给定组成的文件<iframe id="frameName" src="http://domain/"></iframe>

  • 访问受限制的帧的内容同源策略页面; 扩展的权限不放松的政策。
  • frames[0]frames['frameName']通常指的是在框架的包含全局window对象)是undefined
  • var iframe = document.getElementById('frameName');
    • iframe.contentDocument返回一个document含有帧的对象,因为内容的脚本可以访问一个页面的DOM。 此属性为null时,同根同源的政策适用。
    • iframe.contentDocument.defaultView (指的是window与所述文档相关联的对象)是不确定的
    • iframe.contentWindow不确定的

解决方案同源框

在你的情况,无论是下面方法:

// jQuery:
$("#iframe1").contents()[0].execCommand( ... );

// VanillaJS
document.getElementById("iframe1").contentDocument.execCommand( ... );

// "Unlock" contentWindow property by injecting code in context of page
var s = document.createElement('script');
s.textContent = 'document.getElementById("iframe1").contentWindow.document.execCommand( ... );';
document.head.appendChild(s);

通用解决方案

通用解决方案是使用"all_frames": true清单中的文件,使用这样的:

if (window != top) {
    parent.postMessage({fromExtension:true}, '*');
    addEventListener('message', function(event) {
        if (event.data && event.data.inserHTML) {
            document.execCommand('insertHTML', false, event.data.insertHTML);
        }
    });
} else {
    var test_html = 'test string';
    // Explanation of injection at https://stackoverflow.com/a/9517879/938089 :
    // Run code in the context of the page, so that the `contentWindow`
    //  property becomes accessible
    var script = document.createElement('script');
    script.textContent = '(' + function(s_html) {
        addEventListener('message', function(event) {
            if (event.data.fromExtension === true) {
                var iframe = document.getElementById('iframe1');
                if (iframe && (iframe.contentWindow === event.source)) {
                    // Window recognised, post message back
                    iframe.contentWindow.postMessage({insertHTML: s_html}, '*');
                }
            }
        });
    } + ')(' + JSON.stringify(test_html) + ');';
    (document.head||document.documentElement).appendChild(script);
    script.parentNode.removeChild(script);
}

这个演示是仅用于教育目的, 不要在一个真正的扩展使用演示 。 为什么? 由于它采用postMessage来传递消息左右。 这些事件也可以由客户端,这会导致安全泄漏(:任意HTML注射XSS)生成。

以替代postMessage是Chrome的消息API。 对于一个演示,看到这个答案 。 您将无法比较window对象虽然。 你可以做的是依靠window.name属性。 该window.name属性被自动设置为iframe的价值name (只有一次,被加载的iframe时)属性。



文章来源: Accessing iframe from chrome extension