如何绕过window.opener跨域安全性

时间:2022-08-23 10:29:42

I just found out that window.opener is not available in a window opened via window.open if 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正在关闭它,但我不知道如何。我看到网址从他们改为Facebook,然后关闭。

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

从第三方重定向回我的网站后,我运行:

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.

社交注册不适用于iframe中的Google,FB等。我相信他们出于安全原因不允许他们。

5 个解决方案

#1


30  

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.

反过来做。从主(开启者)窗口跟踪子弹出窗口的状态,您可以很容易地知道子窗口何时被导航回您的域,因此您可以再次“与”对话。但是不要单独关闭子窗口。让开启窗口从子窗口获取结果然后关闭它。

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:

<!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测试。

#2


9  

Due to security reason, window.opener is removed when redirecting to a different domain. The browser does not bother to restore the window.opener when 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 data and close normally.

在打开的窗口中,只需存储数据并正常关闭。

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 close event:

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

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 closed property of the openedWindow

3)解决方法:在父页面中使用计时器来检查opensWindow的已关闭属性

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

   }
},1000);

4) Another solution using localStorage as 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:

你的opensWindow代码:

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

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

#3


1  

  1. From your iframe, webpage, on yoursite.com ... open a new window on yoursite.com
  2. 从您的iframe,网页,在yoursite.com上...在yoursite.com上打开一个新窗口

  3. The window redirects itself to Google, Twitter, whatever
  4. 该窗口将自己重定向到Google,Twitter等等

  5. Once done, the OAuth redirect returns the window to a page on yoursite.com
  6. 完成后,OAuth重定向会将窗口返回到yoursite.com上的页面

  7. The new window, because it has the same origin as the page that opened it, can communicate via window.open
  8. 新窗口,因为它与打开它的页面具有相同的原点,可以通过window.open进行通信

#4


1  

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传递命令,甚至可以使用库来执行此操作并在执行命令后删除命令,并发布返回值。

#5


-1  

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 :

在我的公司,我们有不同的域名,并且内部网站点必须获取我们的公共网站(最终摆脱重复数据的维护)。灵感来自Ben Vinegar,我来到这个解决方案简单的解决方案,避免:

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

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

local '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>"; }
  ?>

#1


30  

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.

反过来做。从主(开启者)窗口跟踪子弹出窗口的状态,您可以很容易地知道子窗口何时被导航回您的域,因此您可以再次“与”对话。但是不要单独关闭子窗口。让开启窗口从子窗口获取结果然后关闭它。

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:

<!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测试。

#2


9  

Due to security reason, window.opener is removed when redirecting to a different domain. The browser does not bother to restore the window.opener when 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 data and close normally.

在打开的窗口中,只需存储数据并正常关闭。

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 close event:

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

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 closed property of the openedWindow

3)解决方法:在父页面中使用计时器来检查opensWindow的已关闭属性

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

   }
},1000);

4) Another solution using localStorage as 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:

你的opensWindow代码:

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

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

#3


1  

  1. From your iframe, webpage, on yoursite.com ... open a new window on yoursite.com
  2. 从您的iframe,网页,在yoursite.com上...在yoursite.com上打开一个新窗口

  3. The window redirects itself to Google, Twitter, whatever
  4. 该窗口将自己重定向到Google,Twitter等等

  5. Once done, the OAuth redirect returns the window to a page on yoursite.com
  6. 完成后,OAuth重定向会将窗口返回到yoursite.com上的页面

  7. The new window, because it has the same origin as the page that opened it, can communicate via window.open
  8. 新窗口,因为它与打开它的页面具有相同的原点,可以通过window.open进行通信

#4


1  

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传递命令,甚至可以使用库来执行此操作并在执行命令后删除命令,并发布返回值。

#5


-1  

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 :

在我的公司,我们有不同的域名,并且内部网站点必须获取我们的公共网站(最终摆脱重复数据的维护)。灵感来自Ben Vinegar,我来到这个解决方案简单的解决方案,避免:

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

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

local '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>"; }
  ?>