SecurityError:阻止具有原点的帧访问跨源帧

mub*_*ubi 487 javascript iframe jquery same-origin-policy

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

SecurityError: Blocked a frame with origin "http://www.<domain>.com" from accessing a cross-origin frame.
Run Code Online (Sandbox Code Playgroud)

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

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

$(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!";
    });
});
Run Code Online (Sandbox Code Playgroud)

Mar*_*lli 739

同源政策

不要与CORS混淆!

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

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

<protocol>://<hostname>:<port>/path/to/page.html 
Run Code Online (Sandbox Code Playgroud)

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

例子

以下是尝试访问以下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 
Run Code Online (Sandbox Code Playgroud)

解决方法

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

  • 在您的主页面中:

    let frame = document.getElementById('your-frame-id');
    frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.com');
    
    Run Code Online (Sandbox Code Playgroud)
  • 在你的postMessage()(包含在主页面):

    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; 
        } 
    }); 
    
    Run Code Online (Sandbox Code Playgroud)

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

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

关于这个主题已经有了一些很好的答案(我只是发现它们谷歌搜索),因此,对于可能的浏览器,我将链接相关的答案.但请记住,禁用同源策略(或CORS)只会影响您的浏览器.此外,运行具有相同来源安全设置的浏览器会禁止任何网站访问跨源资源,因此它非常不安全,应该仅用于开发目的.

  • 我第一次在javascript中看到了波形符"〜"运算符.对于其他任何不知道它做什么的人:它将-1转换为0,这样你就不必为indexOf的结果做"!= -1".就个人而言,我认为我将继续使用"!= -1",因为它更容易让其他程序员理解并避免因忘记使用波形符而导致的错误.(但是学习新东西总是很好.) (360认同)
  • 我发现的任何其他答案[1](http://stackoverflow.com/a/22413275),[2](http://stackoverflow.com/a/23363050),表明CORS /`访问控制 - Allow-Origin`不适用于iFrames,仅适用于[XHRs,Fonts,WebGL和`canvas.drawImage`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS).我相信`postMessage`是唯一的选择. (22认同)
  • @Snuggs完全错了,`~`返回数字的2的补码,所以`n`变为`-n-1`,意味着只有`-1`将变为'0`(被解释为'false`),任何其他值都将通过测试.IE`0 = - ( - 1)-1`,而不是` - ( - 1 + 1)`. (13认同)
  • @ccppjava 你不需要 ===,你已经知道变量类型是字符串,所以 === 在这里没用。 (3认同)
  • @SabaAhang只检查`iframe.src`,如果该网站与您网域的主机名不同,那么您无法访问该框架. (3认同)
  • 对于简单情况,另一种解决方法是将 GET 参数作为“src”的一部分传递,并通过“location”对象在接收端提取它们,例如“&lt;iframe src='foobar.com/?sCSS=color%3Ared'&gt;” &lt;/iframe&gt;` (2认同)
  • @user2568374 `location.ancestorOrigins[0]` 是父框架的位置。如果您的框架在 *另一个站点* 内运行,并且您使用 `event.origin.indexOf(location.ancestorOrigins[0])` 检查,则您正在检查事件的来源是否包含父级的框架地址,**总是会发生是`true`**,因此您允许具有*任何来源*的*任何父级*访问您的框架,这显然不是您想要做的事情。此外,正如我在上面的评论中已经解释的那样,`document.referrer` 也是不好的做法。 (2认同)
  • @jub0bs 感谢您指出这一点。令人难以置信的是,这样一段代码已经放在那里这么长时间了。更新! (2认同)

Gee*_*ert 52

马可补充波内利的回答是:帧/ I帧之间交互使用的目前最好的方式window.postMessage,浏览器支持

  • 虽然此链接可能会回答这个问题,但最好在此处包含答案的基本部分并提供参考链接.如果链接的页面发生更改,则仅链接的答案可能会无效. - [来自评论](/ review/low-quality-posts/11859436) (19认同)
  • window.postMessage只有当我们能够访问父(我们的HTML页面)和子元素(其他域iframe)时才能使用.否则"没有可能性",它将始终抛出错误"Uncaught DOMException:Blocked a frame来源"<http://yourdomainname.com>"访问跨域框架." (8认同)
  • 我不同意,@ AlessandroCuttin.解释`window.postMessage`如何工作只会复制我已经引用的已接受答案.此外,我的答案添加的基本价值正是引用外部文档的基本价值. (7认同)
  • 如果您可以编辑已接受的答案并将其添加到那里,我认为它会更好 (3认同)

Sha*_*ani 17

检查域的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>
Run Code Online (Sandbox Code Playgroud)

安全功能如何工作

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

X-Frame-Options DENY

选项是:

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

这是IIS配置示例:

   <httpProtocol>
       <customHeaders>
           <add name="X-Frame-Options" value="SAMEORIGIN" />
       </customHeaders>
   </httpProtocol>
Run Code Online (Sandbox Code Playgroud)

问题的解决方案

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

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

Yak*_*nor 8

对我来说,我想实现双向握手,这意味着:
- 父窗口加载速度比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","*");
    }
});
Run Code Online (Sandbox Code Playgroud)

$(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);
});
Run Code Online (Sandbox Code Playgroud)

自然你可以限制起源和文本,这是易于使用的代码
我发现这个检查有用:
[使用postMessage的跨域消息]


归档时间:

查看次数:

822180 次

最近记录:

5 年,10 月 前