javascript 我如何绕过 window.opener 跨域安全

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18625733/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 12:39:07  来源:igfitidea点击:

How do I get around window.opener cross-domain security

javascriptcross-domain

提问by Dave Stein

I just found out that window.openeris not available in a window opened via window.openif the new URL is cross-domain, in IE. How do I detect window opener in IE

我刚刚发现,如果新 URL 是跨域的,则在 IE 中window.opener通过打开的窗口中不可用window.open如何在 IE 中检测开窗器

This will happen if the window starts in my domain, leaves it, and then comes back to my domain. I am attempting to have a social signup ( facebook, google, etc ) in the popup. When it completes it should close the new window and redirect the opener.

如果窗口在我的域中启动,离开它,然后返回到我的域,就会发生这种情况。我试图在弹出窗口中进行社交注册(facebook、google 等)。完成后,它应该关闭新窗口并重定向开启程序。

I know that Soundcloud is pulling this off, but I have no idea how. I see the URL change from theirs to Facebook, and then close.

我知道 Soundcloud 正在实现这一目标,但我不知道如何实现。我看到 URL 从他们的更改为 Facebook,然后关闭。

After redirecting back to my site from 3rd party I run this:

从第 3 方重定向回我的网站后,我运行以下命令:

var data = {
  type : 'complete',
  destination : '<?= $destination; ?>'
};
if ( window.opener ) {
  window.opener.postMessage( JSON.stringify( data ), '*' );
  window.close();
}
else {
  alert( "Unable to find window" );
}

It alerts out in IE, even though the window was originally my domain, which then redirected to FB, then redirected back to me. I thought may since I open my site and redirect immediately from PHP that may be an issue. However even when I opened my site, did window.location.href = 'facebookssite.com'it still complained when returning.

它在 IE 中发出警报,即使窗口最初是我的域,然后重定向到 FB,然后重定向回我。我想可能因为我打开我的网站并立即从 PHP 重定向,这可能是一个问题。然而,即使我打开我的网站,window.location.href = 'facebookssite.com'返回时它仍然抱怨。

NOTE

笔记

Social signups do not work for google, FB, etc within an iframe. I believe they disallow them for security reasons.

社交注册不适用于 .google、FB 等iframe。我相信他们出于安全原因不允许他们。

回答by noseratio

Do it the other way around. Track the state of the child popup window from the main (opener) window, and you could easily know when the child window has been navigated back to you domain, so you could "talk" to it again. But don't close the child window by itself. Let the opener window obtain the result from the child window and then close it.

反过来做。从主(打开器)窗口跟踪子弹出窗口的状态,您可以轻松知道子窗口何时导航回您的域,以便您可以再次与它“对话”。但不要自行关闭子窗口。让 opener 窗口从子窗口获取结果然后关闭它。

For example, main.html:

例如,main.html

<!DOCTYPE html>
<head>
<title>main</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<script>
window.addEventListener("message", function(ev) {
    if (ev.data.message === "deliverResult") {
        alert("result: " + ev.data.result);
        ev.source.close();
    }
});

function Go() {
    var child = window.open("child.html", "_blank", "height=200,width=200");

    var leftDomain = false;
    var interval = setInterval(function() {
        try {
            if (child.document.domain === document.domain)
            {
                if (leftDomain && child.document.readyState === "complete")
                {
                    // we're here when the child window returned to our domain
                    clearInterval(interval);
                    alert("returned: " + child.document.URL);
                    child.postMessage({ message: "requestResult" }, "*");
                }
            }
            else {
                // this code should never be reached, 
                // as the x-site security check throws
                // but just in case
                leftDomain = true;
            }
        }
        catch(e) {
            // we're here when the child window has been navigated away or closed
            if (child.closed) {
                clearInterval(interval);
                alert("closed");
                return; 
            }
            // navigated to another domain  
            leftDomain = true;
        }
    }, 500);
}
</script>
</head>
<body>
<button onclick="Go()">Go</button>
</body>

child.html:

孩子.html

<!DOCTYPE html>
<head>
<title>child</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<script>
window.addEventListener("message", function(ev) {
    if (ev.data.message === "requestResult") {
        // ev.source is the opener
        ev.source.postMessage({ message: "deliverResult", result: true }, "*");
    }   
});
</script>
</head>
<body>
<a href="http://www.example.com">Go to example.com</a>
Then click the browser Back button when ready.
</body>

Tested with IE10.

用IE10测试。

回答by Khanh TO

Due to security reason, window.openeris removed when redirecting to a different domain. The browser does not bother to restore the window.openerwhen you're back. In your case, you could try:

由于安全原因,window.opener在重定向到不同域时被删除。window.opener当您回来时,浏览器不会费心恢复。在你的情况下,你可以尝试:

1) Do your authentication inside an iframe if possible instead of using redirect.

1) 如果可能,请在 iframe 内进行身份验证,而不是使用重定向。

2) In your case, I see that you need to post the data back to the parent window. You could try this instead:

2)在您的情况下,我看到您需要将数据发布回父窗口。你可以试试这个:

In your opened window, just store your dataand close normally.

在您打开的窗口中,只需存储data并正常关闭即可。

var data = {
  type : 'complete',
  destination : '<?= $destination; ?>'
};

window.hasData = true;
window.data = data;
window.close();

Your parent window has access to your opened window and can handle its closeevent:

您的父窗口可以访问您打开的窗口并可以处理其close事件:

openedWindow.beforeunload = function (){
    //here you could access this.data or openedWindow.data because you're on the same domain
    if (this.hasData){
    }
    //Reason we have this check is because the beforeunload event fires whenever the user leaves your page for any reason including close, submit, clicking a link, ...
}

3) A workaround: Use a timer in your parent page to check for the closedproperty of the openedWindow

3)解决方法:使用你的父页面的定时器来检查closed的性能openedWindow

setInterval(function(){
   if (openedWindow.closed){

   }
},1000);

4) Another solution using localStorageas you're on the same domain. You parent page can listen to the event

4) 另一个使用localStorage 的解决方案,因为您在同一个域中。您的父页面可以收听事件

window.addEventListener("storage", function(event){

}, true);

Your openedWindow code:

你的openWindow代码:

var data = {
  type : 'complete',
  destination : '<?= $destination; ?>'
};

if (localStorage){
   localStorage.setItem(JSON.stringify(data));
}
window.close();

回答by Gregory Magarshak

Use localStorage or IndexedDB to communicate between windows that are showing documents from the same domain but which don't have a reference to each other.

使用 localStorage 或 IndexedDB 在显示来自同一域但彼此没有引用的文档的窗口之间进行通信。

Simply have a high-speed timer checking for the data, saving another piece of data to acknowledge receipt and the other window can find it and close.

只需让一个高速计时器检查数据,保存另一条数据以确认收到,另一个窗口可以找到它并关闭。

In short - you use localStorage to pass commands and can even have a library to do this and delete the commands once they are executed, and post the return values.

简而言之 - 您使用 localStorage 来传递命令,甚至可以有一个库来执行此操作并在命令执行后删除它们,并发布返回值。

回答by Ben Vinegar

  1. From your iframe, webpage, on yoursite.com ... open a new window on yoursite.com
  2. The window redirects itself to Google, Twitter, whatever
  3. Once done, the OAuth redirect returns the window to a page on yoursite.com
  4. The new window, because it has the same origin as the page that opened it, can communicate via window.open
  1. 从您的 iframe、网页、yoursite.com 上……在 yoursite.com 上打开一个新窗口
  2. 窗口将自己重定向到 Google、Twitter 等
  3. 完成后,OAuth 重定向会将窗口返回到 yoursite.com 上的页面
  4. 新窗口,因为与打开它的页面同源,所以可以通过 window.open 进行通信

回答by Jordi

In my company we've different domains and there's the case where the intranet's site must get the our public website (to finally get rid of the maintenance of duplicated data). Inspired in Ben Vinegar i've come to this solution simple solution avoiding the :

在我的公司,我们有不同的域,并且有这样的情况,Intranet 的站点必须获得我们的公共网站(最终摆脱对重复数据的维护)。受到 Ben Vinegar 的启发,我来到了这个解决方案简单的解决方案,避免了:

Call to domain webpage (in my case with the same name as the external one)

调用域网页(在我的情况下与外部网页同名)

local 'getInfo.php'

本地' getInfo.php'

<?php 
      $idSp = (isset($_GET['idSp'])?$_GET['idSp']:null);
      echo file_get_contents('http://192.168.1.10/folder/getInfo.php?idSp='.$idSp);
 ?>

External 'getInfo.php' return

外部' getInfo.php'返回

 <?php  
    echo '<script>window.opener.manageDisplay('.$getRes.','.$isOK.');</script>';
    if($auto_close){ echo "<script>window.close();</script>"; }
  ?>