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

 SecurityError: Blocked a frame with origin "http://www.<domain>.com" from accessing a cross-origin frame.
 


您能帮我找到一个解决方案,以便我可以访问框架中的元素吗?

我正在使用此代码进行测试,但没有用:

$(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并不严格遵守此规则,请参见此处。
示例
这是尝试从http://www.example.com/home/index.html访问以下URL时会发生的情况
 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及其相对的message事件在两个页面之间发送消息来解决此问题,如下所示:


在您的主页中:
const frame = document.getElementById('your-frame-id');
frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.com');

postMessage()的第二个参数可以是'*',表示没有公关关于目的地的起点。在可能的情况下,应始终提供目标来源,以避免泄露发送到任何其他站点的数据。


在您的<iframe>(包含在主页中)中:
window.addEventListener('message', event => {
    // IMPORTANT: check the origin of the data! 
    if (event.origin.startsWith('http://your-first-site.com')) { 
        // 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()),没有任何区别。
在浏览器中禁用同源策略
关于此主题已经有了一些不错的答案(我刚刚找到了它们),因此,对于可能的浏览器,我将链接相对答案。但是,请记住,禁用同源策略只会影响您的浏览器。此外,运行禁用了同源安全设置的浏览器会授予任何网站访问跨域资源的权限,因此,这是非常不安全的,如果您不确切知道自己在做什么(例如,出于开发目的),则永远不要这样做。 >
Google Chrome浏览器
Mozilla Firefox
Safari
Opera
Microsoft Edge:不可能

Microsoft Internet Explorer

>

评论


我找到的其他任何答案1、2都表明CORS / Access-Control-Allow-Origin不适用于iFrame,仅适用于XHR,Fonts,WebGL和canvas.drawImage。我相信postMessage是唯一的选择。

–snappieT
15年1月14日在12:12



如果来源是:yousite.com.mysite.com怎么办?我们应该改用===吗?

–ccppjava
15年8月3日,11:04

@ccppjava不需要===,您已经知道变量类型是字符串,因此===在这里没有用。

– Marco Bonelli
2015年8月3日在16:22

@SabaAhang仅检查iframe.src,如果该站点与您的域的主机名不同,则您将无法访问该框架。

– Marco Bonelli
2015年10月17日在9:34

@ user2568374 location.ancestorOrigins [0]是父框架的位置。如果您的框架在另一个站点中运行,并且您使用event.origin.indexOf(location.ancestorOrigins [0])进行检查,则您正在检查事件的来源是否包含父级的框架地址,该地址始终为真,因此您允许任何有任何起源的父母访问您的框架,这显然不是您想要做的。而且,正如我在上面的评论中已经解释的那样,document.referrer也是不好的做法。

– Marco Bonelli
18年5月22日在13:39

#2 楼

补充Marco Bonelli的回答:当前,在框架/ iframe之间进行交互的最佳方式是使用window.postMessage,所有浏览器均支持该功能

评论


仅当我们能够同时访问父级(我们的HTML页面)和子级元素(其他域iframe)时,才能使用window.postMessage。否则,“ THERE IS NO POSSIBILITY”,它将始终引发错误“ Uncaught DOMException:Blocked frame”源“ ”访问跨域框架。

– VIJAY P
17年2月1日在18:35



#3 楼

检查域的Web服务器以获取http://www.<domain>.comX-Frame-Options配置
这是一项旨在防止clickJacking攻击的安全功能,

clickJacking的工作原理是什么?


邪恶页面看起来与受害者页面完全一样。
然后,它欺骗用户输入用户名和密码。

从技术上讲,邪恶页面带有iframe,其中包含受害者页面的来源。

<html>
    <iframe src='victim_domain.com'/>
    <input id="username" type="text" style="display: none;/>
    <input id="password" type="text" style="display: none;/>
    <script>
        //some JS code that click jacking the user username and input from inside the iframe...
    <script/>
<html>


安全功能如何工作

如果要防止在iframe中呈现Web服务器请求,请添加x-frame-options


X框架选项DENY


选项为:


SAMEORIGIN //仅允许我自己的域将我的HTML呈现在iframe中。
拒绝//不允许将我的HTML呈现在任何iframe中
“ ALLOW-FROM https://example.com/” //允许特定域将我的HTML呈现在iframe中

这是IIS配置示例:

   <httpProtocol>
       <customHeaders>
           <add name="X-Frame-Options" value="SAMEORIGIN" />
       </customHeaders>
   </httpProtocol>


解决方案问题

如果Web服务器激活了安全功能,则可能会导致客户端安全错误。

评论


我认为X-Frame-Options在这里不适用-访客(嵌入式)页面定义的X-Frame-Options可能导致父级拒绝加载该页面,但据我所知,它不会影响javascript访问-即使使用X-Frame-Options:*,我认为您也无法使用javascript访问其他原始来宾页面的DOM

–诺亚·吉尔摩(Noah Gilmore)
19年11月5日14:54

#4 楼

对我来说,我想实现两向握手,这意味着:
-父窗口的加载速度比iframe快
-iframe在其父窗口准备就绪后应立即与之对话
-父级已准备好接收iframe消息并重播

此代码用于使用[CSS自定义属性]在iframe中设置白色标签
代码:iframe

$(function() {
    window.onload = function() {
        // create listener
        function receiveMessage(e) {
            document.documentElement.style.setProperty('--header_bg', e.data.wl.header_bg);
            document.documentElement.style.setProperty('--header_text', e.data.wl.header_text);
            document.documentElement.style.setProperty('--button_bg', e.data.wl.button_bg);
            //alert(e.data.data.header_bg);
        }
        window.addEventListener('message', receiveMessage);
        // call parent
        parent.postMessage("GetWhiteLabel","*");
    }
});


父母

$(function() {
    // create listener
    var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
    var eventer = window[eventMethod];
    var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
    eventer(messageEvent, function (e) {
        // replay to child (iframe) 
        document.getElementById('wrapper-iframe').contentWindow.postMessage(
            {
                event_id: 'white_label_message',
                wl: {
                    header_bg: $('#Header').css('background-color'),
                    header_text: $('#Header .HoverMenu a').css('color'),
                    button_bg: $('#Header .HoverMenu a').css('background-color')
                }
            },
            '*'
        );
    }, false);
});


当然,您可以限制原点和文本,这是易于使用的代码
我发现此示例很有帮助:[使用postMessage进行跨域消息传递]

评论


我正在处理Safari的问题,即iframe中的文档比父页面晚执行其JS,这导致消息的发送早于iframe中的文档正在侦听消息的时间;与chrome和firefox的功能完全相反-您是否在ios的Safari中测试过代码? btw postMessage的第二个参数值为“ *”不是很安全,您应该始终指定domain

– sKopheK
18-3-22在15:51



您的第一段代码是在父级的iframe上还是在加载到iframe的页面上?

– Demonic218
19年2月15日在9:45

#5 楼

我想添加特定于Java Spring的配置,以对此产生影响。

在Web站点或网关应用程序中,有一个contentSecurityPolicy设置

在Spring中,您可以找到WebSecurityConfigurerAdapter的实现。子类

contentSecurityPolicy("
script-src 'self' [URLDomain]/scripts ; 
style-src 'self' [URLDomain]/styles;
frame-src 'self' [URLDomain]/frameUrl...


...

.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)


如果您没有定义安全的外部设备,浏览器将被阻止contenet在这里。

#6 楼

如果您可以控制iframe的内容-也就是说,如果仅将iframe的内容加载到跨域设置中(例如在Amazon Mechanical Turk上),则可以使用内部html的<body onload='my_func(my_arg)'>属性来避免此问题。

例如,对于内部html,请使用this html参数(是-已定义this,它引用内部主体元素的父窗口):

<body onload='changeForm(this)'>

在内部html中:

    function changeForm(window) {
        console.log('inner window loaded: do whatever you want with the inner html');
        window.document.getElementById('mturk_form').style.display = 'none';
    </script>


#7 楼

尝试嵌入iframe,然后使用Brave打开网站时遇到了此错误。当我将相关站点更改为“ Shields Down”时,错误消失了。显然,这不是一个完整的解决方案,因为任何其他使用Brave访问该网站的人都会遇到同样的问题。要真正解决它,我需要执行此页面上列出的其他事情之一。但是至少我现在知道问题出在哪里。

#8 楼


打开开始菜单
键入Windows + R或打开“运行
执行以下命令。

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security

评论


可怕的是没有快速而肮脏的测试……已经在接受的答案中解决了。

–昆汀
19 Mar 26 '19在11:23

即使使用该命令,它也不起作用,因为Chrome避免了以这种方式禁用网络安全性

– Metafaniel
19年7月3日在15:56