用于绕过同源策略以访问嵌套 iframe 的用户脚本

Userscript to bypass same-origin policy for accessing nested iframes

在下面的 HTML 模型中,嵌套的 iframe 来自不同的子域。这会导致诸如 error: Permission denied to access 属性 "document"

之类的消息
<html>
<head>
    <title></title>
</head>
<body>
    <div>
        <iframe id="outer_iframe_1" src="https://subdomain1.example.com"></iframe>
    </div>
    <div>
        <iframe id="outer_iframe_2" src="https://subdomain2.example.com">
        <div>
            <iframe id="inner_iframe_2" src="https://subdomain4.example.com"></iframe>
        </div>
        </iframe>
    </div>
    <div>
        <iframe id="outer_iframe_3" src="https://subdomain3.example.com"></iframe>
    </div>
</body>
</html>

我打算使用用户脚本获取和修改嵌套 iframe(例如 inner_frame_2)中的值,因此应该可以绕过同源策略。但是 GM_xmlhttpRequest 的示例似乎依赖于 GET/POST 请求,而我只想处理这些 iframe 中已经加载的页面数据。

我是不是误解了GM_xmlhttpRequest,还是我应该采取另一种方法?

我认为你能做到的唯一方法是使用这样的 window.postMessage() method to send messages with data from iframes to the top window. To catch each iframe inside Greasemonkey script see on ; you'll have to use the GM @match 指令:

// @match        http://subdomain1.example.com/*

// @match        *.example.com/*

然后可以查看当前window是否是置顶window,and/or查看document.domain判断iframe:

// ==UserScript==
// @name         New Userscript
// @match        http://main-domain.something
// @match        *.example.com/*
// ==/UserScript==

(function() {
    'use strict';

    if (window.top === window.self) {
        // Here we are at the top window and we setup our message event listener
    }
    else {
        // Here we get inside the iframes.
        // We can address and check each iframe url with document.domain
    }
})();

我们需要将 "message" 的事件挂接到顶部 window 以处理从 iframe 接收到的每条消息和数据:

window.addEventListener("message", function(event) {
    // do something with the event.data
}, false);

并且我们可以使用 document.domain 来识别 iframe;对 iframe 元素进行我们需要的任何操作;检索我们想要的所有数据并将消息发送到顶部 window:

window.top.postMessage({
    // data object we send to the top window
}, "*");

我创建了一个演示来尝试这个,它工作得很好。我的顶级 window URL 是 http://zikro.gr/dbg/gm/iframes/main.php,子域类似于 http://subdomain1.zikro.gr/。顶部 window HTML 与我的 iframe 网址和 GM 脚本相同:

// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        http://zikro.gr/dbg/gm/iframes/main.php
// @match        *.zikro.gr/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    if (window.top === window.self) {
        // Here we are at the top window and we setup our message event listener
        document.body.style.backgroundColor = "#f00"; // Just a UI change to identify the top window
        window.addEventListener("message", function(event) {
            window.console.log("This is data from '" + event.data.title +
                               "'; with message '" + event.data.message +
                               "'; with data '" + event.data.data +"'" +
                               "'; from domain '" + event.data.domain + "'");
        }, false);
    }
    else {
        // Here we get inside the iframes.
        // We can address and check each iframe url with document.domain

        document.body.style.backgroundColor = "#0f0"; // Just a UI change to identify the iframe window

        // We change something inside the iframe
        var dataDiv = document.getElementsByTagName('div')[0];
        dataDiv.innerHTML += " with a change!";

        // And we post a message to the top window with all the data we want inside an object
        window.top.postMessage({
            title: document.title,
            domain: document.domain,
            message: "Hello from, iframe - " + document.title,
            data: dataDiv.innerText
        }, "*");
    }

})();

并为那些没有安装 Greasemonkey/Tampermoney 的用户提供屏幕截图来测试:

PS: 直接在 iframe 标签内添加元素是无效的:

<iframe id="outer_iframe_2" src="https://subdomain2.example.com">
<div>
    <iframe id="inner_iframe_2" src="https://subdomain4.example.com"></iframe>
</div>
</iframe>

这不是您问题的直接答案,但这是为那些想要使用 javascript 操纵网页以进行数据处理的人准备的。

PhantomJS 等软件专为 "browser automation" 设计,允许完全删除跨源策略。

phantomjs.exe --web-security=no script.js

在您的脚本中,您可以使用

page.open("http://fiddle.jshell.net/9aQv5/show/", function(status) { // Load a webpage
    page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js", function() { // Add support jor jQuery
        page.evaluate(function() { // Run custom script
            console.log($("body").find("iframe").attr("src"));

            console.log($("body").find("iframe").contents().find("iframe").attr("src"));

            console.log($("body").find("iframe").contents().find("iframe").contents().find("#about-puppy-linux").html());
        });
        phantom.exit(0);
    });
});

您得到以下输出:

//fiddle.jshell.net/9aQv5/show/light/
http://www.puppylinux.com/
About Puppy Linux