Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

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.

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.

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.

NOTE

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

like image 738
Dave Stein Avatar asked Sep 05 '13 00:09

Dave Stein


People also ask

Does iframe have its own window?

In action: iframeAn <iframe> tag hosts a separate embedded window, with its own separate document and window objects.

What is postMessage in Javascript?

postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.

What is cross domain communication?

To enable cross-domain communication for these web applications, UCWA 2.0 exposes an HTML iframe that allows web applications to securely interact with UCWA 2.0 resources that are located on another domain. The cross-domain iframe communicates with the web application by way of the HTML5 postMessage method.

What is window opener?

opener. The Window interface's opener property returns a reference to the window that opened the window, either with open() , or by navigating a link with a target attribute. In other words, if window A opens window B , B. opener returns A .


Video Answer


3 Answers

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:

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

like image 108
noseratio Avatar answered Oct 16 '22 05:10

noseratio


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:

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

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

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

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

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

}, true);

Your openedWindow code:

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

if (localStorage){
   localStorage.setItem(JSON.stringify(data));
}
window.close();
like image 17
Khanh TO Avatar answered Oct 16 '22 05:10

Khanh TO


  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
like image 1
Ben Vinegar Avatar answered Oct 16 '22 06:10

Ben Vinegar