SecurityError:阻止了具有原点的框架访问跨域框架


555

我正在<iframe>HTML页面中加载,并尝试使用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!";
    });
});

Answers:


818

同源政策

无法<iframe>使用JavaScript 访问其他来源的内容,如果可以的话,这将是一个巨大的安全漏洞。对于同源策略, 浏览器会阻止脚本尝试访问源不同的框架

如果未保留地址的以下至少其中之一,则认为起源是不同的:

<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及其相对message事件在两个页面之间发送消息来解决此问题,如下所示:

  • 在您的主页中:

    let 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())生成任何新窗口,而没有任何区别。

在禁用同源策略您的浏览器

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


27
任何其他的答案,我发现12,表明CORS / Access-Control-Allow-Origin不适用于Iframe,只有XHR时,字体,WebGL和canvas.drawImage。我相信postMessage是唯一的选择。
snappieT 2015年

369
第一次,我在javascript中看到了波浪号“〜”运算符。对于还不知道其作用的其他任何人:它将-1转换为0,这样就不必在indexOf的结果上做“!= -1”。就我个人而言,我认为我将继续使用“!= -1”,因为其他程序员更容易理解并且避免了由于忘记使用波浪号而引起的错误。(但是学习新知识总是很高兴的。)
Redzarf 2015年

4
@SabaAhang只需要检查iframe.src,如果该站点与您的域的主机名不同,则无法访问该框架。
Marco Bonelli,2015年

17
@Snuggs完全错误,~返回数字的2的补数,因此n变为-n-1,表示仅-1将变为0(被解释为false),而其他任何值将通过测试。IE浏览器0 = -(-1)-1,不是-(-1+1)
Marco Bonelli

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

55

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


21
尽管此链接可以回答问题,但最好在此处包括答案的基本部分,并提供链接以供参考。如果链接的页面发生更改,仅链接的答案可能会失效。- 评论
亚历山德罗·卡丁

9
我不同意,@ AlessandroCuttin。解释window.postMessage工作方式只会重复我已经引用的已接受答案。此外,我的回答所增加的基本价值就是引用外部文档的价值。
Geert

5
我认为,如果您可以编辑接受的答案并将其添加到那里,那就更好了
Martin Massera'1

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

18

检查域的Web服务器以进行http://www.<domain>.com配置,X-Frame-Options 这是一项旨在防止clickJacking攻击,

clickJacking如何工作?

  1. 邪恶页面看上去与受害者页面完全一样。
  2. 然后,它欺骗了用户输入用户名和密码。

从技术上讲,邪恶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添加x-frame-options中呈现Web服务器请求

X-Frame-Options拒绝

选项包括:

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

这是IIS配置示例:

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

问题的解决方案

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


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

13

对我来说,我想实现2向握手,这意味着:
-父窗口的加载速度比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进行跨域消息传递]


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

您的第一个代码块是在父iframe上还是在加载到iframe的页面上?
Demonic218 '19

0

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

在网站或网关应用程序中,有一个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)

如果您在此处未定义安全的外部网络,浏览器将被阻止。


0

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

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

<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>

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

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


3
适用于快速而肮脏的测试!
user1068352 18-10-16

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

2
即使使用该命令,它也不起作用,因为Chrome避免了以这种方式禁用网络安全性
Metafaniel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.