Ось як:
Для спільного використання між субдоменами даного супердомену (наприклад, example.com) існує техніка, яку ви можете використовувати у цій ситуації. Він може бути застосований до localStorage
, IndexedDB
, SharedWorker
, BroadcastChannel
і т.д., всі з яких мають загальну функціональність між ж походження сторінок, але з якоїсь - то причини не дотримуються будь - яких змін вdocument.domain
які дозволили б їм використовувати супербудинку як їх походження безпосередньо.
(1) Виберіть один «основний» домен, до якого належать дані: тобто https://example.com або https://www.example.com зберігатимуть ваші дані localStorage. Скажімо, ви вибрали https://example.com .
(2) Використовуйте localStorage зазвичай для сторінок вибраного домену.
(3) На всіх https://www.example.com сторінках ( інший домен) використовуйте javascript для встановлення document.domain = "example.com";
. Потім також створіть приховану <iframe>
та перейдіть до якоїсь сторінки у вибраному домені https://example.com ( Не має значення, на якій сторінці , якщо ви можете туди вставити дуже маленький фрагмент javascript. Якщо ви створюючи веб-сайт, просто створіть порожню сторінку спеціально для цього. Якщо ви пишете розширення або користувацький скрипт у стилі Greasemonkey і тому не маєте контролю над сторінками на example.comпросто виберіть найлегшу сторінку, яку ви можете знайти, і вставте в неї свій сценарій. Якась сторінка "не знайдено", мабуть, буде в порядку).
(4) Сценарій на прихованій сторінці iframe повинен мати лише (a) набір document.domain = "example.com";
і (b) повідомляти батьківське вікно, коли це буде зроблено. Після цього батьківське вікно може отримати доступ до вікна iframe та всіх його об’єктів без обмежень! Тож мінімальна сторінка iframe - це щось на зразок:
<!doctype html>
<html>
<head>
<script>
document.domain = "example.com";
window.parent.iframeReady(); // function defined & called on parent window
</script>
</head>
<body></body>
</html>
Якщо ви пишете скрипт користувача, ви, можливо, не захочете додавати зовнішні функції, такі як iframeReady()
до вашого unsafeWindow
, тому натомість кращим способом сповіщення головного вікна може бути використання користувацької події:
window.parent.dispatchEvent(new CustomEvent("iframeReady"));
Що ви виявили б, додавши прослуховувач спеціальної події "iframeReady" у вікно головної сторінки.
(ПРИМІТКА. Вам потрібно встановити document.domain = "example.com", навіть якщо домен iframe вже є example.com : Присвоєння значення document.domain неявно встановлює нульовий порт походження , і обидва порти повинні збігатися для iframe та його батьківщину вважати однаковим. Дивіться примітку тут: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin )
(5) Після того , як прихований IFrame повідомив його батьківське вікно , що він готовий, сценарій в батьківському вікні можна просто використовувати iframe.contentWindow.localStorage
, iframe.contentWindow.indexedDB
, iframe.contentWindow.BroadcastChannel
, iframe.contentWindow.SharedWorker
а window.localStorage
, window.indexedDB
і т.д. ... і всі ці об'єкти будуть область видимості обраної https: // example.com - тому вони матимуть те саме спільне джерело для всіх ваших сторінок!
Найбільш незручна частина цієї техніки полягає в тому, що перед тим, як продовжувати, вам доведеться дочекатися завантаження iframe. Отже, ви не можете просто легко розпочати використання localStorage у своєму обробнику DOMContentLoaded, наприклад. Також, можливо, ви захочете додати деяку обробку помилок, щоб виявити, чи не вдається завантажити приховану рамку.
Очевидно, вам слід також переконатись, що прихований iframe не видаляється та не переміщується протягом усього періоду вашої сторінки ... OTOH, я не знаю, яким буде результат, але дуже ймовірно, що трапляться погані речі.
І, застереження: налаштування / зміна document.domain
може бути заблокована за допомогою Feature-Policy
заголовка, і в цьому випадку ця техніка не буде застосована, як описано.
Однак існує значно більш складне узагальнення цієї методики, яке неможливо заблокувати Feature-Policy
, а це також дозволяє абсолютно не пов’язаним доменам обмінюватися даними, зв’язками та спільними працівниками (тобто не просто субдоменами загального наддомену). @Mayank Jain це вже описав у своїй відповіді, а саме:
Загальна ідея полягає в тому, що, як і вище, ви створюєте прихований iframe для забезпечення правильного джерела доступу; але замість того, щоб просто захоплювати властивості вікна iframe безпосередньо, ви використовуєте сценарій всередині iframe, щоб виконати всю роботу, і ви спілкуєтесь між iframe та вашим головним вікном лише за допомогою postMessage()
та addEventListener("message",...)
.
Це працює, оскільки postMessage()
його можна використовувати навіть між вікнами різного походження. Але це також значно складніше, тому що ви повинні передавати все через якусь інфраструктуру обміну повідомленнями, яку ви створюєте між iframe та головним вікном, а не просто використовуючи API localStorage, IndexedDB тощо. Безпосередньо в коді вашого головного вікна.