SecurityError:阻止了一个具有源的框架访问跨源框架

IT技术 javascript jquery security iframe same-origin-policy
2021-01-07 16:27:55

我正在<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!";
    });
});
6个回答

同源策略

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

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

协议://主机名端口/...

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

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

例子

这是尝试从以下网址访问以下网址时会发生的情况 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事件在两个页面之间发送消息来解决此问题,如下所示:

  • 在您的主页中:

    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()也可以实现,没有任何区别。

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

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

我发现的任何其他答案12 都表明 CORS/Access-Control-Allow-Origin不适用于 iFrame,仅适用于XHR、字体、WebGL 和canvas.drawImage. 我相信postMessage是唯一的选择。
2021-02-11 16:27:55
@ccppjava 你不需要 ===,你已经知道变量类型是字符串,所以 === 在这里没用。
2021-02-16 16:27:55
@user2568374location.ancestorOrigins[0]是父框架的位置。如果您的框架在另一个站点内运行并且您检查使用event.origin.indexOf(location.ancestorOrigins[0])您正在检查事件的来源是否包含父级的框架地址,true地址始终为,因此您允许任何具有任何来源的父级访问您的框架,并且这显然不是你想做的事情。此外,这document.referrer也是不好的做法,正如我在上面的评论中已经解释的那样。
2021-02-18 16:27:55
@SabaAhang 只需检查iframe.src,如果该站点与您域的主机名不同,那么您将无法访问该框架。
2021-02-19 16:27:55
@user2568374这是一个糟糕的主意如果你检查event.origin.indexOf(location.ancestorOrigins[0])你基本上允许任何父框架访问你的框架,正如你想象的那样,这是一个非常糟糕的主意。
2021-03-06 16:27:55

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

window.postMessage 仅当我们能够访问父元素(我们的 HTML 页面)和子元素(其他域 iframe)时才可以使用。否则“没有可能”,它总是会抛出错误“未捕获的 DOMException:阻止了框架来自访问跨域框架的源“< yourdomainname.com >”。
2021-02-26 16:27:55

检查域的 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 DENY

选项是:

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

这是 IIS 配置示例:

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

问题的解答

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

这个答案实际上并没有回答这个问题,这个问题没有问这是否安全。
2021-02-14 16:27:55
我不认为 X-Frame-Options 在这里适用 - 来宾(嵌入式)页面定义的 X-Frame-Options 会导致父页面拒绝加载页面,但据我所知它不会影响 javascript访问 - 即使使用 X-Frame-Options: *,我认为您无法使用 javascript 访问不同来源访客页面的 DOM
2021-02-22 16:27:55

对我来说,我想实现 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 进行跨域消息传递]

我正在处理 safari 的一个问题,其中 iframe 中的文档执行其 JS 晚于父页面,这导致消息在 iframe 中的文档侦听消息之前发送;这与 chrome 和 firefox 所做的完全相反-您是否在 ios 上的 safari 中测试了您的代码?顺便说一句,第二个参数值为“*”的 postMessage 不太安全,您应该始终指定域
2021-02-08 16:27:55
您的第一个代码块是在父级的 iframe 上还是在加载到 iframe 的页面上?
2021-02-09 16:27:55

我想添加可以对此产生影响的 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)

如果您没有在此处定义安全的外部内容,浏览器将被阻止。