Окно: метод postMessage()
Базовая Широко доступна
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с июля 2015 года.
Метод window.postMessage() безопасно позволяет осуществлять междоменную коммуникацию между объектами Window; например, между страницей и всплывающим окном, которое она создала, или между страницей и iframe, вставленным в неё.
Обычно скрипты на разных страницах могут обращаться друг к другу только в том случае, если страницы имеют один и тот же источник (также известный как «политика одного источника»). window.postMessage() предоставляет управляемый механизм для безопасного обхода этого ограничения (если он используется правильно).
Кроме того, скрипт, осуществляющий доступ, должен предварительно получить объект окна целевого документа. Это можно сделать с помощью методов, таких как window.open() для всплывающих окон или iframe.contentWindow для iframe.
В общем случае, одно окно может получить ссылку на другое (например, через targetWindow = window.opener), а затем отправить событие MessageEvent с targetWindow.postMessage(). Затем получающее окно свободно может обработать это событие по мере необходимости. Аргументы, переданные в window.postMessage() (т.е., «сообщение»), доступны получающему окну через объект события.
Синтаксис
postMessage(message) postMessage(message, targetOrigin) postMessage(message, targetOrigin, transfer) postMessage(message, options)
Параметры
message-
Данные, которые будут отправлены другому окну. Данные сериализуются с помощью алгоритма структурированного клонирования. Это значит, что вы можете безопасно передавать разнообразные объекты данных целевому окну без необходимости их самостоятельной сериализации.
targetOriginНеобязательно-
Указывает источник получающего окна, необходимого для получения события. Для отправки события источник должен точно совпадать (включая схему, имя хоста и порт). Если опущено, по умолчанию используется источник вызывающего метода. Этот механизм позволяет контролировать, куда отправляются сообщения; например, если
postMessage()использовался для передачи пароля, было бы крайне важно, чтобы этот аргумент был URI, источник которого совпадает с предполагаемым получателем сообщения, содержащего пароль, чтобы предотвратить перехват пароля злоумышленником.*также может быть предоставлен, что означает, что сообщение может быть отправлено обработчику с любым источником.Примечание: Всегда указывайте конкретный
targetOrigin, а не*, если вы знаете, где должен находиться документ другого окна. Отсутствие конкретного целевого источника может раскрыть данные злоумышленному сайту. transferНеобязательно-
Необязательный массив массивов передаваемых объектов для передачи владения. Владение этими объектами передается стороне получателя, и они больше недоступны на стороне отправителя. Эти передаваемые объекты должны быть прикреплены к сообщению; в противном случае они будут перемещены, но фактически не будут доступны на стороне получателя.
optionsНеобязательно-
Необязательный объект, содержащий следующие свойства:
transferНеобязательно-
Имеет то же значение, что и параметр
transfer. targetOriginНеобязательно-
Имеет то же значение, что и параметр
targetOrigin.
Возвращаемое значение
Ничего (undefined).
Отправленное событие
Объект window может слушать отправленные сообщения, выполняя следующий JavaScript:
window.addEventListener(
"message",
(event) => {
if (event.origin !== "http://example.org:8080") return;
// …
},
false,
);
Свойства отправленного сообщения:
data-
Объект, переданный из другого окна.
origin-
Источник окна, отправившего сообщение в момент вызова
postMessage. Эта строка является конкатенацией протокола и "://", имени хоста, если оно существует, и ":" с номером порта, если порт присутствует и отличается от стандартного порта для данного протокола. Примеры типичных источников —https://example.org(что подразумевает порт443),http://example.net(что подразумевает порт80) иhttp://example.com:8080. Обратите внимание, что этот источник не гарантирует текущего или будущего источника этого окна, которое может перейти на другую страницу с момента вызоваpostMessage. source-
Ссылка на объект
windowокна, отправившего сообщение; это позволяет наладить двустороннее общение между двумя окнами с разными источниками.
Вопросы безопасности
Если вы не ожидаете получать сообщения с других сайтов, не добавляйте обработчики событий для событий message. Это совершенно надежный способ избежать проблем с безопасностью.
Если вы ожидаете получать сообщения с других сайтов, всегда проверяйте личность отправителя, используя свойства origin и, возможно, source. Любое окно (включая, например, http://evil.example.com) может отправлять сообщение любому другому окну внутри иерархии iframe сверху вниз каждого iframe ниже текущего документа. Однако после проверки личности вы все равно должны всегда проверять синтаксис полученного сообщения. В противном случае, уязвимость на сайте, которому вы доверяете для отправки только доверенных сообщений, может открыть XSS-уязвимость на вашем сайте.
Всегда указывайте точный целевой источник, а не *, при использовании postMessage для отправки данных другим окнам. Злоумышленный сайт может изменить расположение окна без вашего ведома, и, следовательно, он может перехватить данные, отправленные с помощью postMessage.
Безопасная передача сообщений с использованием совместной памяти
Если postMessage() выбрасывает исключение при использовании с объектами SharedArrayBuffer, вам может потребоваться убедиться, что ваш сайт должным образом изолирован от других сайтов. Доступ к совместной памяти ограничен двумя заголовками HTTP:
-
Cross-Origin-Opener-Policyсо значениемsame-origin(защищает ваш источник от злоумышленников) -
Cross-Origin-Embedder-Policyсо значениемrequire-corpилиcredentialless(защищает жертвы от вашего источника)
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp
Чтобы проверить, была ли междоменная изоляция успешной, вы можете проверить свойство Window.crossOriginIsolated, доступное для контекстов окон и рабочих потоков:
const myWorker = new Worker("worker.js");
if (crossOriginIsolated) {
const buffer = new SharedArrayBuffer(16);
myWorker.postMessage(buffer);
} else {
const buffer = new ArrayBuffer(16);
myWorker.postMessage(buffer);
}
Примеры
/*
* In window A's scripts, with A being on http://example.com:8080:
*/
const popup = window.open(/* popup details */);
// When the popup has fully loaded, if not blocked by a popup blocker:
// This does nothing, assuming the window hasn't changed its location.
popup.postMessage(
"The user is 'bob' and the password is 'secret'",
"https://secure.example.net",
);
// This will successfully queue a message to be dispatched to the popup, assuming
// the window hasn't changed its location.
popup.postMessage("hello there!", "http://example.com");
window.addEventListener(
"message",
(event) => {
// Do we trust the sender of this message? (might be
// different from what we originally opened, for example).
if (event.origin !== "http://example.com") return;
// event.source is popup
// event.data is "hi there yourself! the secret response is: rheeeeet!"
},
false,
);
/*
* In the popup's scripts, running on http://example.com:
*/
// Called sometime after postMessage is called
window.addEventListener("message", (event) => {
// Do we trust the sender of this message?
if (event.origin !== "http://example.com:8080") return;
// event.source is window.opener
// event.data is "hello there!"
// Assuming you've verified the origin of the received message (which
// you must do in any case), a convenient idiom for replying to a
// message is to call postMessage on event.source and provide
// event.origin as the targetOrigin.
event.source.postMessage(
"hi there yourself! the secret response " + "is: rheeeeet!",
event.origin,
);
});
Примечания
Любой скрипт в документе в окне может запросить отправку сообщения в документ в другом окне, объект окна которого он получил, вызвав .postMessage() для этого объекта окна. Соответственно, любой обработчик событий, используемый для получения сообщений, **обязательно** должен сначала проверить идентичность отправителя сообщения, используя свойства origin и возможно source. Это нельзя переоценить: **Отказ от проверки свойств origin и возможно source позволяет проводить атаки типа межсайтового скриптинга.**
Как и в случае с любым асинхронно отправленным скриптом (таймауты, события, сгенерированные пользователем), вызывающий postMessage не может обнаружить, когда обработчик событий, прослушивающий события, отправленные postMessage, вызывает исключение.
После вызова postMessage(), MessageEvent будет отправлен только после завершения всех ожидающих контекстов выполнения. Например, если postMessage() вызывается в обработчике событий, этот обработчик будет выполнен до конца, как и все оставшиеся обработчики для того же события, прежде чем будет отправлен MessageEvent.
Значение свойства origin отправленного события не зависит от текущего значения document.domain в вызывающем окне.
Только для имен хостов IDN значение свойства origin не является согласованно Unicode или punycode; для наибольшей совместимости проверяйте и IDN, и punycode значения при использовании этого свойства, если вы ожидаете сообщения с сайтов IDN. Это значение в конечном итоге будет согласованно IDN, но пока вы должны обрабатывать оба формата IDN и punycode.
Значение свойства origin, когда отправляющее окно содержит javascript: или data: URL, является происхождением скрипта, который загрузил URL.
Использование window.postMessage в расширениях Нестандартно
window.postMessage доступен JavaScript, выполняющемуся в коде браузера (например, в расширениях и привилегированном коде), но свойство source отправленного события всегда null в качестве меры безопасности. (Другие свойства имеют ожидаемые значения.)
Контент-скрипты или скрипты веб-контекста не могут указать targetOrigin для прямого взаимодействия с расширением (либо с фоновым скриптом, либо с контент-скриптом). Скрипты веб- или контент-скрипты *могут* использовать window.postMessage с targetOrigin значения "*" для широковещательной рассылки всем обработчикам, но это не рекомендуется, так как расширение не может быть уверенным в происхождении таких сообщений, и другие обработчики (включая те, которые вы не контролируете) могут их принимать.
Контент-скрипты должны использовать runtime.sendMessage для взаимодействия с фоновым скриптом. Скрипты веб-контекста могут использовать пользовательские события для взаимодействия с контент-скриптами (с случайными именами событий, если это необходимо, чтобы предотвратить перехват гостевой страницы).
Наконец, отправка сообщения на страницу с file: URL в настоящее время требует, чтобы аргумент targetOrigin был "*". file:// не может использоваться как мера безопасности; это ограничение может быть изменено в будущем.
Спецификации
| Спецификация |
|---|
| HTML # dom-window-postmessage-options-dev |
Совместимость с браузерами
| Рабочие столы | Мобильные устройства | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox для Android | Opera Android | Safari на iOS | Samsung Internet | WebView Android | |
postMessage |
2 | 12 | 3["Firefox 8 и выше поддерживает отправкуFile и FileList объектов между окнами. Это разрешено только в том случае, если основной компонент получателя находится в основном компоненте отправителя по соображениям безопасности.", "До Firefox 6 параметр message должен быть строкой. С Firefox 6 параметр message сериализуется с помощью алгоритма структурированного клонирования. Это означает, что вы можете безопасно передать широкий спектр объектов данных в целевое окно, не сериализуя их самостоятельно."] |
9.5 | 4 | 18 | 4["Firefox для Android 8 и выше поддерживает отправкуFile и FileList объектов между окнами. Это разрешено только в том случае, если основной компонент получателя находится в основном компоненте отправителя по соображениям безопасности.", "До Firefox для Android 6 параметр message должен быть строкой. С Firefox для Android 6 параметр message сериализуется с помощью алгоритма структурированного клонирования. Это означает, что вы можете безопасно передать широкий спектр объектов данных в целевое окно, не сериализуя их самостоятельно."] |
10.1 | 3.2 | 1.0 | ≤37 |
options_includeUserActivation_parameter |
72 | 79 | Нет | 60 | Нет | 72 | Нет | 51 | Нет | 11.0 | 72 |
transfer_parameter |
4 | 12 | 20 | ≤15 | 5 | 18 | 20 | ≤14 | 4 | 1.0 | ≤37 |
См. также
Document.domainCustomEvent-
BroadcastChannel- Для междоменного взаимодействия.
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage