C'est ainsi:
Pour le partage entre les sous-domaines d'un superdomaine donné (par exemple, example.com), il existe une technique que vous pouvez utiliser dans cette situation. Il peut être appliqué à localStorage
, IndexedDB
, SharedWorker
, BroadcastChannel
, etc., qui offrent tous des fonctionnalités partagées entre les pages de même origine, mais pour une raison quelconque ne respectent aucune modification document.domain
qui permettrait de les utiliser le superdomaine leur origine directement.
(1) Choisissez un domaine "principal" auquel les données doivent appartenir: c'est-à-dire que https://example.com ou https://www.example.com contiendra vos données de stockage local. Disons que vous choisissez https://example.com .
(2) Utilisez localStorage normalement pour les pages de ce domaine choisi.
(3) Sur toutes les pages https://www.example.com (l' autre domaine), utilisez javascript pour définir document.domain = "example.com";
. Créez ensuite également caché <iframe>
, et de naviguer à une page sur le choix https://example.com domaine ( Peu importe ce que la page , aussi longtemps que vous pouvez insérer un très petit extrait de javascript là - bas. Si vous lors de la création du site, créez simplement une page vide spécialement à cet effet. Si vous écrivez une extension ou un script utilisateur de style Greasemonkey et que vous n'avez donc aucun contrôle sur les pages de example.comserveur, choisissez simplement la page la plus légère que vous puissiez trouver et insérez-y votre script. Une sorte de page "non trouvée" conviendrait probablement).
(4) Le script de la page iframe masquée n'a besoin que de (a) défini document.domain = "example.com";
et (b) d'avertir la fenêtre parente lorsque cela est fait. Après cela, la fenêtre parente peut accéder à la fenêtre iframe et à tous ses objets sans restriction! Ainsi, la page iframe minimale est quelque chose comme:
<!doctype html>
<html>
<head>
<script>
document.domain = "example.com";
window.parent.iframeReady(); // function defined & called on parent window
</script>
</head>
<body></body>
</html>
Si vous écrivez un script utilisateur, vous ne voudrez peut-être pas ajouter des fonctions accessibles de l'extérieur, telles que iframeReady()
votre unsafeWindow
, donc un meilleur moyen de notifier le script utilisateur de la fenêtre principale peut être d'utiliser un événement personnalisé:
window.parent.dispatchEvent(new CustomEvent("iframeReady"));
Ce que vous détecteriez en ajoutant un écouteur pour l'événement "iframeReady" personnalisé à la fenêtre de votre page principale.
(REMARQUE: vous devez définir document.domain = "example.com" même si le domaine de l'iframe est déjà example.com : l'attribution d'une valeur à document.domain définit implicitement le port de l'origine sur null, et les deux ports doivent correspondre pour l'iframe et son parent doit être considéré comme ayant la même origine. Voir la note ici: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin )
(5) Une fois que le caché iframe a informé sa fenêtre parent qu'il est prêt, le script dans la fenêtre parent peut simplement utiliser iframe.contentWindow.localStorage
, iframe.contentWindow.indexedDB
, iframe.contentWindow.BroadcastChannel
, au iframe.contentWindow.SharedWorker
lieu de window.localStorage
, window.indexedDB
, etc ... et tous ces objets seront étendus à l'élu https: // example.com origin - ils auront donc la même origine partagée pour toutes vos pages!
La partie la plus délicate de cette technique est que vous devez attendre que l'iframe se charge avant de continuer. Vous ne pouvez donc pas simplement commencer à utiliser localStorage dans votre gestionnaire DOMContentLoaded, par exemple. Vous pouvez également ajouter une gestion des erreurs pour détecter si l'iframe masqué ne se charge pas correctement.
De toute évidence, vous devez également vous assurer que l'iframe caché n'est pas supprimé ou parcouru pendant la durée de vie de votre page ... OTOH Je ne sais pas quel en serait le résultat, mais très probablement de mauvaises choses se produiraient.
Et, une mise en garde: le réglage / la modification document.domain
peut être bloqué à l'aide de l'en- Feature-Policy
tête, auquel cas cette technique ne sera pas utilisable comme décrit.
Cependant, il existe une généralisation beaucoup plus compliquée de cette technique, qui ne peut pas être bloquée par Feature-Policy
, et qui permet également à des domaines totalement indépendants de partager des données, des communications et des travailleurs partagés (c'est-à-dire pas seulement des sous-domaines d'un super-domaine commun). @Mayank Jain l'a déjà décrit dans sa réponse, à savoir:
L'idée générale est que, tout comme ci-dessus, vous créez une iframe cachée pour fournir l'origine correcte pour l'accès; mais au lieu de simplement saisir directement les propriétés de la fenêtre iframe, vous utilisez un script à l'intérieur de l'iframe pour faire tout le travail, et vous communiquez entre l'iframe et votre fenêtre principale uniquement en utilisant postMessage()
et addEventListener("message",...)
.
Cela fonctionne car postMessage()
peut être utilisé même entre des fenêtres d'origine différente. Mais c'est aussi beaucoup plus compliqué car vous devez tout faire passer par une sorte d'infrastructure de messagerie que vous créez entre l'iframe et la fenêtre principale, plutôt que d'utiliser simplement les API localStorage, IndexedDB, etc. directement dans le code de votre fenêtre principale.