web-dev-qa-db-fra.com

Comment contourner la sécurité inter-domaines window.opener

Je viens de découvrir que window.opener n'est pas disponible dans une fenêtre ouverte via window.open si la nouvelle URL est interdomaine, dans IE. Comment détecter l'ouvre-fenêtre dans IE

Cela se produira si la fenêtre démarre dans mon domaine, la quitte, puis revient à mon domaine. J'essaie d'avoir une inscription sociale (facebook, google, etc.) dans la fenêtre contextuelle. Une fois terminé, il devrait fermer la nouvelle fenêtre et rediriger l'ouvreur.

Je sais que Soundcloud réussit, mais je ne sais pas comment. Je vois l'URL passer de la leur à Facebook, puis je ferme.

Après avoir redirigé vers mon site depuis un tiers, je lance ceci:

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

Il alerte dans IE, même si la fenêtre était à l'origine mon domaine, qui a ensuite été redirigé vers FB, puis redirigé vers moi. Je pensais que depuis l'ouverture de mon site et la redirection immédiate depuis PHP cela peut être un problème. Cependant, même lorsque j'ai ouvert mon site, window.location.href = 'facebookssite.com' il se plaignait encore à son retour.

[~ # ~] note [~ # ~]

Les inscriptions sociales ne fonctionnent pas pour google, FB, etc. dans un iframe. Je pense qu'ils les interdisent pour des raisons de sécurité.

34
Dave Stein

Faites-le dans l'autre sens. Suivez l'état de la fenêtre contextuelle enfant à partir de la fenêtre principale (ouvre) et vous pouvez facilement savoir quand la fenêtre enfant a été redirigée vers votre domaine, afin que vous puissiez "lui parler" à nouveau. Mais ne fermez pas la fenêtre enfant par elle-même. Laissez la fenêtre d'ouverture obtenir le résultat de la fenêtre enfant, puis fermez-la.

Par exemple, 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>

Testé avec IE10.

36
noseratio

Pour des raisons de sécurité, window.opener est supprimé lors de la redirection vers un autre domaine. Le navigateur ne prend pas la peine de restaurer le window.opener à votre retour. Dans votre cas, vous pouvez essayer:

1) Faites votre authentification dans un iframe si possible au lieu d'utiliser la redirection.

2) Dans votre cas, je vois que vous devez publier les données dans la fenêtre parent. Vous pouvez essayer ceci à la place:

Dans votre fenêtre ouverte, stockez simplement votre data et fermez normalement.

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

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

Votre fenêtre parente a accès à votre fenêtre ouverte et peut gérer son événement 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) Une solution de contournement: utilisez une minuterie dans votre page parent pour vérifier la propriété closed de la openedWindow

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

   }
},1000);

4) Une autre solution utilisant localStorage car vous êtes sur le même domaine. Votre page parent peut écouter l'événement

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

}, true);

Votre code openWindow:

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

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

Utilisez localStorage ou IndexedDB pour communiquer entre des fenêtres qui affichent des documents du même domaine mais qui n'ont pas de référence les uns aux autres.

Ayez simplement une minuterie à grande vitesse pour vérifier les données, enregistrer une autre donnée pour accuser réception et l'autre fenêtre peut la trouver et la fermer.

En bref - vous utilisez localStorage pour passer des commandes et pouvez même avoir une bibliothèque pour ce faire et supprimer les commandes une fois qu'elles sont exécutées et publier les valeurs de retour.

1
Gregory Magarshak
  1. Depuis votre iframe, page Web, sur votresite.com ... ouvrez une nouvelle fenêtre sur votresite.com
  2. La fenêtre se redirige vers Google, Twitter, peu importe
  3. Une fois cela fait, la redirection OAuth renvoie la fenêtre vers une page sur yoursite.com
  4. La nouvelle fenêtre, car elle a la même origine que la page qui l'a ouverte, peut communiquer via window.open
1
Ben Vinegar