Communication avec une iframe d'un autre domaine
Vous savez sans doute ce qu’est un widget, ces petits bidules qui envahissent les applications web ou desktop. Là je me suis intéressé à la communication Javascript entre un site et un contenu d’un autre domaine dans une iframe. Concrètement, ça peut servir à une application web qui communique avec ses widgets de manière sécurisée.
Problème
J’ai une application fait en Javascript/html et je veux autoriser l’ajout de modules externes (toujours en Javascript) sans pour autant ouvrir des failles. On opte pour une insertion des modules par iframe. Mais il faut quand même qu’il y ait une intéraction dans tout ce bazar, car si l’application et les modules ne sont pas dans le même domaine, alors le navigateur interdit les échanges Javascript.
Solutions
Utiliser Flash
Première solution de flasheur : utiliser les LocalConnection.
Sauf que j’ai eu une très mauvaise surprise récemment. J’ai découvert que le plugin Flash sur Mac limitait le nombre de connexion par LocalConnection. Et c’est un bug qui date depuis longtemps quand on cherche sur google.
Donc, je zappe puisque dans mon problème, il aurait fallu un LocalConnection pour l’application et un pour chaque module.
Echange d’objets Javascript
C’est la solution que j’ai retenu pour l’instant et que je vais expliquer ici. Merci à Collin Jackson pour son document sur la communication cross-domain.
Dans le PDF, l’auteur explique 2 méthodes différentes tournant autour d’un même principe: faire transiter un objet javascript d’un domaine vers un autre.
Pour qu’une iframe accède au javascript de son parent, il faut que les 2 soient du même domaine. A l’aide d’iframes intermédiaires et la modification de document.domain
, on peut s’arranger pour que les 2 parties gardent une référence d’un objet Javascript appartement à l’autre. Il y a tout de même une restriction au changement de domaine: on ne peut que réduire l’espace de nom.
Par exemple, www.neolao.com
ne peut se changer qu’en neolao.com
, le domaine com
tout seul étant interdit.
Méthode Top Untrusted Access (TUA)
Ca consiste à passer l’objet Javascript de A à B en passant par M et N.
- Ma page principale est www.neolao.com/app.html (A)
- Sur cette dernière, je crée une iframe qui a comme contenu www.neolao.com/mediator.html (M)
- M récupère l’objet Javascript
appObject
contenu dans A simplement en faisantappObject = parent.appObject;
- M change son domaine avec
document.domain = "neolao.com";
- M se rend facilement accessible en se référencant dans A:
parent.mediatorPage = this;
- A crée une iframe qui a comme contenu widget1.neolao.com/widget.html (B)
- B crée aussi une iframe qui a comme contenu widget1.neolao.com/access.html (N)
- N récupère un objet Javascript
widgetObject
contenu dans B:widgetObject = parent.widgetObject;
- N change son domaine:
document.domain = "neolao.com";
- N récupère
appObject
en faisantappObject = top.mediatorPage.appObject;
Après tout ça, N possède appObject
et widgetObject
. Ces 2 objets Javascript n’ont plus qu’à se référencer mutuellement :
widgetObject.appObject = appObject;
appObject.widgetObject = widgetObject;
Et enfin, on peut détruire les iframes intermédiaires, on n’en a plus besoin
Méthode Top Mediator Untrusted (TMU)
Cette fois ci, l’iframe B est contenu dans M et le reste. Le passage des objets se fait de la même façon que la première méthode.
On utilise ce procédé quand on ne peut pas accéder aux DOM ni aux variable du top
.
Variantes
Attention tout de même, on ne peut pas forcément appeler les fonctions contenues dans les objets sans problème. Il y a 2 variantes pour chaque méthodes :
- variante callback : appel de fonctions pour exécuter les actions
- variante polling : modifier une variable String qui va être vérifiée pour exécuter les actions
Et ouais, le polling est inévitable pour certains navigateurs comme Safari ou Opera. Ca sera donc à l’aide d’un setInterval
vérifiant en permanence une variable qu’on va pouvoir exécuter des actions venues d’ailleurs.
Conclusion
Je trouve que les restrictions sont énormes :
- On ne peut pas directement jouer avec des domaines complètement différents, il faut s’arranger autrement.
- Pour une application à widget, il faut des sous domaines différents pour chacun d’entre eux. Donc, une petite manipulation dans les VirtualHost et les DNS est necessaire.
- Certains navigateurs sont trop restrictifs (et d’autres trop permissifs). Du coup, on en arrive à utiliser du polling avec un setInterval pas beau.
Et la surprise pour la fin … j’ai tenté de créer un outil facilitant la communication :
Commentaires