安全错误:阻止具有源的帧访问跨源帧

我正在加载一个在我的HTML页面中,并尝试使用JavaScript访问其中的元素,但是当我尝试执行我的代码时,我得到以下错误:<iframe>

安全错误:阻止源“http://www.example.com”的帧访问跨域帧。

如何访问框架中的元素?

我正在使用这段代码进行测试,但徒劳无功:

$(document).ready(function() {
    var iframeWindow = document.getElementById("my-iframe-id").contentWindow;

    iframeWindow.addEventListener("load", function() {
        var doc = iframe.contentDocument || iframe.contentWindow.document;
        var target = doc.getElementById("my-target-id");

        target.innerHTML = "Found it!";
    });
});

答案 1

同源策略

你不能使用JavaScript访问具有不同来源的,如果你能做到这一点,那将是一个巨大的安全漏洞。对于同源策略,浏览器会阻止尝试访问具有不同源的帧的脚本<iframe>

如果未维护地址的以下至少一个部分,则认为源不同:

protocol://hostname:port/...

如果要访问帧,协议、主机名和端口必须与您的域相同。

注意:众所周知,Internet Explorer 并不严格遵循此规则,有关详细信息,请参阅此处

例子

以下是尝试从以下位置访问以下 URL 时发生的情况http://www.example.com/home/index.html

URL                                             RESULT
http://www.example.com/home/other.html       -> Success
http://www.example.com/dir/inner/another.php -> Success
http://www.example.com:80                    -> Success (default port for HTTP)
http://www.example.com:2251                  -> Failure: different port
http://data.example.com/dir/other.html       -> Failure: different hostname
https://www.example.com/home/index.html:80   -> Failure: different protocol
ftp://www.example.com:21                     -> Failure: different protocol & port
https://google.com/search?q=james+bond       -> Failure: different protocol, port & hostname

解决方法

即使同源策略阻止脚本访问具有不同源的站点的内容,如果您拥有这两个页面,也可以使用 window.postMessage 及其相对消息事件在两个页面之间发送消息,从而解决此问题,如下所示:

  • 在主页中:

    const frame = document.getElementById('your-frame-id');
    frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.example');
    

    第二个参数可以是指示对目的地的起点没有偏好。应始终尽可能提供目标源,以避免泄露您发送到任何其他站点的数据。postMessage()'*'

  • 在您的(包含在主页中):<iframe>

    window.addEventListener('message', event => {
        // IMPORTANT: check the origin of the data!
        if (event.origin.startsWith('http://your-first-site.example')) {
            // The data was sent from your site.
            // Data sent with postMessage is stored in event.data:
            console.log(event.data);
        } else {
            // The data was NOT sent from your site!
            // Be careful! Do not use it. This else branch is
            // here just for clarity, you usually shouldn't need it.
            return;
        }
    });
    

此方法可以在两个方向上应用,也可以在主页中创建侦听器,并从帧接收响应。同样的逻辑也可以在弹出窗口中实现,基本上也可以在主页生成的任何新窗口中实现(例如使用window.open()),没有任何区别。

在浏览器中禁用同源策略

关于这个主题已经有一些很好的答案(我刚刚发现它们在谷歌搜索中),所以,对于可能这样做的浏览器,我将链接相对答案。但是,请记住,禁用同源策略只会影响您的浏览器。此外,运行禁用了同源安全设置的浏览器会授予任何网站对跨源资源的访问权限,因此这是非常不安全的,如果您不知道自己在做什么(例如开发目的),则永远不应该这样做。


答案 2

补充Marco Bonelli的答案:目前帧/iframe之间交互的最佳方式是使用所有浏览器都支持的window.postMessage