1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
---
title: Window.postMessage()
slug: Web/API/Window/postMessage
translation_of: Web/API/Window/postMessage
---
<div>{{ApiRef("HTML DOM")}}</div>
<p><strong><code>Window.postMessage()</code></strong> - этот метод позволяет безопасно отправлять кроссдоменные запросы. Обычно сценариям на разных страницах разрешен доступ друг к другу только если страницы, которые их выполняли, передаются по одному протоколу (обычно это https), номер порта (443 — по умолчанию для https) и хост (modulo {{domxref("Document.domain")}} установленный страницами на одно и тоже значение). <code>window.postMessage()</code> предоставляет контролируемый механизм, чтобы обойти это ограничение способом, который безопасен при правильном использовании.</p>
<p><font face="Open Sans, arial, x-locale-body, sans-serif">При вызове метода </font><code>window.postMessage()</code> он вызывает {{domxref("MessageEvent")}} для отправки в целевом окне, когда завершается любой ожидающий сценарий, который должен быть выполнен (например, оставшиеся обработчики событий, если <code>window.postMessage()</code> вызывается из обработчика событий ранее заданных ожидающих таймаутов). {{domxref("MessageEvent")}} имеет тип <code>message</code>, <code>data-свойство</code> которого устанавливает значение первого аргумента в методе <code>window.postMessage()</code>, свойство <code>origin</code> соответствует адресу основного документа в вызове <code>window.postMessage</code> во время вызова <code>window.postMessage()</code>, свойство <code>source</code> указывает на окно, из которого <code>window.postMessage()</code> вызвали. (Другие стандартные свойства событий имеют ожидаемые значения)</p>
<h2 id="Syntax">Syntax</h2>
<pre class="syntaxbox"><em>otherWindow</em>.postMessage(<em>message</em>, <em>targetOrigin</em>, [<em>transfer</em>]);</pre>
<dl>
<dt><code><em>otherWindow</em></code></dt>
<dd>Ссылка на другое окно; такая ссылка может быть получена, к примеру, при использовании свойства <code>contentWindow</code> элемента <code>iframe</code> , объекта, возвращаемого <a href="/en-US/docs/DOM/window.open">window.open</a>, или по именованному и числовому индексу {{domxref("Window.frames")}}, если вы пытаетесь запустить сообщение из iframe в родительском окне, то родитель также является действительной ссылкой.</dd>
<dt><code><em>message</em></code></dt>
<dd>Данные, которые нужно отправить в другое окно. Данные сериализуются с использованием алгоритма структурированного клона. Это означает, что вы можете безопасно передавать большое количество объектов данных в окно назначения без необходимости их сериализации. [<a href="/en-US/docs/">1</a>]</dd>
<dt><code><em>targetOrigin</em></code></dt>
<dd>Specifies what the origin of <code>otherWindow</code> must be for the event to be dispatched, either as the literal string <code>"*"</code> (indicating no preference) or as a URI. If at the time the event is scheduled to be dispatched the scheme, hostname, or port of <code>otherWindow</code>'s document does not match that provided in <code>targetOrigin</code>, the event will not be dispatched; only if all three match will the event be dispatched. This mechanism provides control over where messages are sent; for example, if <code>postMessage()</code> was used to transmit a password, it would be absolutely critical that this argument be a URI whose origin is the same as the intended receiver of the message containing the password, to prevent interception of the password by a malicious third party. <strong>Always provide a specific <code>targetOrigin</code>, not <code>*</code>, if you know where the other window's document should be located. Failing to provide a specific target discloses the data you send to any interested malicious site.</strong></dd>
<dt><code><em><strong>transfer</strong></em></code> {{optional_Inline}}</dt>
<dd>Is a sequence of {{domxref("Transferable")}} objects that are transferred with the message. The ownership of these objects is given to the destination side and they are no longer usable on the sending side.</dd>
</dl>
<h2 id="The_dispatched_event">The dispatched event</h2>
<p>В <code>otherWindow</code> отправляемые сообщения могут быть прослушаны следующим способом:</p>
<pre class="brush: js">window.addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
if (event.origin !== "http://example.org:8080")
return;
// ...
}
</pre>
<p>Свойства отправляемых сообщений:</p>
<dl>
<dt><code>data</code></dt>
<dd>Объект, переданный из другого окна.</dd>
<dt><code>origin</code></dt>
<dd>The <a href="/en-US/docs/Origin">origin</a> of the window that sent the message at the time <code>postMessage</code> was called. This string is the concatenation of the protocol and "://", the host name if one exists, and ":" followed by a port number if a port is present and differs from the default port for the given protocol. Examples of typical origins are <code class="nowiki">https://example.org</code> (implying port <code>443</code>), <code class="nowiki">http://example.net</code> (implying port <code>80</code>), and <code class="nowiki">http://example.com:8080</code>. Note that this origin is <em>not</em> guaranteed to be the current or future origin of that window, which might have been navigated to a different location since <code>postMessage</code> was called.</dd>
<dt><code>source</code></dt>
<dd>Ссылка на объект <code><a href="/en-US/docs/DOM/window">window</a></code> , который отправил сообщение; может быть использована для установки двустороннего соединения между окнами с разными <code>origins</code>.</dd>
</dl>
<h2 id="Вопросы_безопасности">Вопросы безопасности</h2>
<p><strong>Если вы не ожидаете получения сообщения от других сайтов, не добавляйте никаких слушателей для <code>message</code> событий.</strong> Это гарантированный способ избежать проблем с безопасностью.</p>
<p>Если же вы хотите получать сообщения от других сайтов, то всегда необходимо идентифицировать отправителя, используя <code>origin</code> и возможно <code>source</code> свойства. Любой сайт (включая, например, <code class="nowiki">http://evil.example.com</code>) может отправлять сообщения любым другим, и у вас нет гарантии, что неизвестный отправитель не пошлет вредоносные сообщения. Однако даже если отправитель известен, вам все равно необходимо всегда подтверждать синтаксис получаемого сообщения. Иначе, дыра в безопасности сайта, которому вы доверяете, может открыть дыру для межсайтового скриптинга на вашем сайте.</p>
<p><strong>Всегда конкретизируйте целевой первоисточник, а не просто <code>*</code>, когда вы используете <code>postMessage</code> для отправки данных другим окнам. Вредоносный сайт может изменить локацию окна без вашего ведома и затем перехватить данные, посылаемые с использованием </strong><code>postMessage</code>.</p>
<h2 id="Example">Example</h2>
<pre class="brush: js">/*
* In window A's scripts, with A being on <http://example.com:8080>:
*/
var 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 sent to the popup, assuming
// the window hasn't changed its location.
popup.postMessage("hello there!", "http://example.com");
function receiveMessage(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!"
}
window.addEventListener("message", receiveMessage, false);
</pre>
<pre class="brush: js">/*
* In the popup's scripts, running on <http://example.com>:
*/
// Called sometime after postMessage is called
function receiveMessage(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);
}
window.addEventListener("message", receiveMessage, false);
</pre>
<h3 id="Notes">Notes</h3>
<p>Any window may access this method on any other window, at any time, regardless of the location of the document in the window, to send it a message. Consequently, any event listener used to receive messages <strong>must</strong> first check the identity of the sender of the message, using the <code>origin</code> and possibly <code>source</code> properties. This cannot be overstated: <strong>Failure to check the <code>origin</code> and possibly <code>source</code> properties enables cross-site scripting attacks.</strong></p>
<p>As with any asynchronously-dispatched script (timeouts, user-generated events), it is not possible for the caller of <code>postMessage</code> to detect when an event handler listening for events sent by <code>postMessage</code> throws an exception.</p>
<p>The value of the <code>origin</code> property of the dispatched event is not affected by the current value of <code>document.domain</code> in the calling window.</p>
<p>For IDN host names only, the value of the <code>origin</code> property is not consistently Unicode or punycode; for greatest compatibility check for both the IDN and punycode values when using this property if you expect messages from IDN sites. This value will eventually be consistently IDN, but for now you should handle both IDN and punycode forms.</p>
<p>The value of the <code>origin</code> property when the sending window contains a <code>javascript:</code> or <code>data:</code> URL is the origin of the script that loaded the URL.</p>
<h3 id="Using_window.postMessage_in_extensions_Non-standard_inline">Using window.postMessage in extensions {{Non-standard_inline}}</h3>
<p><code>window.postMessage</code> is available to JavaScript running in chrome code (e.g., in extensions and privileged code), but the <code>source</code> property of the dispatched event is always <code>null</code> as a security restriction. (The other properties have their expected values.) The <code>targetOrigin</code> argument for a message sent to a window located at a <code>chrome:</code> URL is currently misinterpreted such that the only value which will result in a message being sent is <code>"*"</code>. Since this value is unsafe when the target window can be navigated elsewhere by a malicious site, it is recommended that <code>postMessage</code> not be used to communicate with <code>chrome:</code> pages for now; use a different method (such as a query string when the window is opened) to communicate with chrome windows. Lastly, posting a message to a page at a <code>file:</code> URL currently requires that the <code>targetOrigin</code> argument be <code>"*"</code>. <code>file://</code> cannot be used as a security restriction; this restriction may be modified in the future.</p>
<h2 id="Specifications">Specifications</h2>
<table class="standard-table">
<tbody>
<tr>
<th><strong>Specification</strong></th>
<th><strong>Status</strong></th>
<th><strong>Comment</strong></th>
</tr>
<tr>
<td>{{SpecName('HTML WHATWG', "#dom-window-postmessage", "window.postMessage")}}</td>
<td>{{Spec2('HTML WHATWG')}}</td>
<td>No change from {{SpecName('HTML5 Web Messaging')}}</td>
</tr>
<tr>
<td>{{SpecName('HTML5 Web Messaging', '#dom-window-postmessage', 'window.postMessage')}}</td>
<td>{{Spec2('HTML5 Web Messaging')}}</td>
<td>Initial definition.</td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility">Browser compatibility</h2>
<p>{{CompatibilityTable}}</p>
<div id="compat-desktop">
<table class="compat-table">
<tbody>
<tr>
<th><strong>Feature</strong></th>
<th><strong>Chrome</strong></th>
<th><strong>Edge</strong></th>
<th><strong>Firefox (Gecko)</strong></th>
<th><strong>Internet Explorer</strong></th>
<th><strong>Opera</strong></th>
<th><strong>Safari (WebKit)</strong></th>
</tr>
<tr>
<td>Basic support</td>
<td>1.0</td>
<td>{{CompatVersionUnknown}}</td>
<td>{{CompatGeckoDesktop(6.0)}}<sup>[1]</sup><br>
{{CompatGeckoDesktop(8.0)}}<sup>[2]</sup></td>
<td>8.0<sup>[3]</sup><br>
10.0<sup>[4]</sup></td>
<td>9.5</td>
<td>4.0</td>
</tr>
<tr>
<td><code>transfer</code> argument</td>
<td>{{CompatUnknown}}</td>
<td>{{CompatVersionUnknown}}</td>
<td>{{CompatGeckoDesktop(20.0)}}</td>
<td>{{CompatVersionUnknown}}</td>
<td>{{CompatUnknown}}</td>
<td>{{CompatUnknown}}</td>
</tr>
</tbody>
</table>
</div>
<div id="compat-mobile">
<table class="compat-table">
<tbody>
<tr>
<th><strong>Feature</strong></th>
<th><strong>Android</strong></th>
<th><strong>Edge</strong></th>
<th><strong>Firefox Mobile (Gecko)</strong></th>
<th><strong>IE Phone</strong></th>
<th><strong>Opera Mobile</strong></th>
<th><strong>Safari Mobile</strong></th>
</tr>
<tr>
<td>Basic support</td>
<td>{{CompatVersionUnknown}}</td>
<td>{{CompatVersionUnknown}}</td>
<td>{{CompatGeckoDesktop(6.0)}}<sup>[1]</sup><br>
{{CompatGeckoDesktop(8.0)}}<sup>[2]</sup></td>
<td>{{CompatVersionUnknown}}</td>
<td>{{CompatVersionUnknown}}</td>
<td>{{CompatVersionUnknown}}</td>
</tr>
<tr>
<td><code>transfer</code> argument</td>
<td>{{CompatUnknown}}</td>
<td>{{CompatUnknown}}</td>
<td>{{CompatGeckoMobile(20.0)}}</td>
<td>{{CompatNo}}</td>
<td>{{CompatUnknown}}</td>
<td>{{CompatUnknown}}</td>
</tr>
</tbody>
</table>
</div>
<p>[1] Prior to Gecko 6.0 {{geckoRelease("6.0")}}, the <code>message</code> parameter must be a string. Starting in Gecko 6.0 {{geckoRelease("6.0")}}, the <code>message</code> parameter is serialized using <a href="/en-US/docs/DOM/The_structured_clone_algorithm">the structured clone algorithm</a>. This means you can pass a broad variety of data objects safely to the destination window without having to serialize them yourself.</p>
<p>[2] Gecko 8.0 introduced support for sending {{domxref("File")}} and {{domxref("FileList")}} objects between windows. This is only allowed if the recipient's principal is contained within the sender's principal for security reasons.</p>
<p>[3] IE8 and IE9 only support it for {{HTMLElement("frame")}} and {{HTMLElement("iframe")}}.</p>
<p>[4] IE10 has important limitations: see this <a href="http://stackoverflow.com/questions/16226924/is-cross-origin-postmessage-broken-in-ie10">article</a> for details.</p>
<h2 id="See_also">See also</h2>
<ul>
<li>{{domxref("Document.domain")}}</li>
<li>{{domxref("CustomEvent")}}</li>
<li><a href="/en-US/docs/Code_snippets/Interaction_between_privileged_and_non-privileged_pages">Interaction between privileged and non-privileged pages</a></li>
</ul>
|