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
|
---
title: Window.postMessage
slug: Web/API/Window/postMessage
tags:
- API
- DOM
- Méthode
- Reference
- postMessage
translation_of: Web/API/Window/postMessage
---
<div>{{ ApiRef() }}</div>
<div></div>
<p>La méthode <strong><code>window.postMessage</code></strong> permet une communication inter-domaine en toute sécurité. Normalement, les scripts de différentes pages sont autorisés à accéder les uns aux autres si et seulement si les pages depuis lesquelles ils sont exécutés ont des URL de même <a href="/en-US/docs/Glossary/Origin">origine</a>, c'est-à-dire avec le même protocole (généralement <code>http</code> ou <code>https</code>), le même numéro de port (<code>80</code> étant le port par défaut pour <code>http</code>), et le même nom d'hôte (à condition que <a href="/en-US/docs/DOM/document.domain" title="DOM/document.domain">document.domain</a> soit initialisé à la même valeur par les deux pages). <code>window.postMessage</code> fournit un mécanisme contrôlé pour contourner cette restriction d'une manière sécurisée si bien utilisée.</p>
<p>La méthode <code>window.postMessage</code>, quand elle est appelée, provoque l'envoi d'un {{domxref("MessageEvent")}} à la fenêtre ciblée une fois que tout script en attente a terminé son exécution (par exemple, les gestionnaires d'évènements restants si <code>window.postMessage</code> est appelée depuis un gestionnaire d'évènement, des timeouts en attente enregistrées auparavant, etc.) Le {{domxref("MessageEvent")}} est de type <code>message</code>, a une propriété <code>data</code> qui est initialisée à la valeur du premier argument passé à<code> window.postMessage</code>, une propriété <code>origin</code> correspondant à l'origine du document principal de la fenêtre appelant <code>window.postMessage</code> au moment où <code>window.postMessage</code> a été appelée, et une propriété <code>source</code> qui est la fenêtre depuis laquelle <code>window.postMessage</code> est appelée. (les autres propriétés standard d'évènement sont présentes avec leurs valeurs attendues).</p>
<h2 id="Syntax" name="Syntax">Syntaxe</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>Une référence à une autre fenêtre ; une telle référence peut être obtenue, par exemple, <em>via</em> la propriété <code>contentWindow</code> d'un élément <code>iframe</code>, l'objet retourné par <a href="/fr/docs/DOM/window.open" title="DOM/window.open">window.open</a>, ou par index nommé ou numérique de <a href="/fr/docs/Web/API/window.frames" title="DOM/window.frames">window.frames</a>.</dd>
<dt><code><em>message</em></code></dt>
<dd>La donnée à envoyer à l'autre fenêtre. Elle est sérialisée en utilisant <a href="/fr/docs/Web/Guide/API/DOM/The_structured_clone_algorithm" title="DOM/The structured clone algorithm">l'algorithme de clônage structuré</a>. Cela signifie que vous pouvez passer sereinement une large variété d'objets de données à la fenêtre de destination sans avoir à les sérialiser vous-mêmes. [1]</dd>
<dt><code><em>targetOrigin</em></code></dt>
<dd>Indique quelle doit être l'origine de <code>otherWindow</code> pour l'évènement à envoyer, soit comme la chaîne littérale <code>"*"</code> (signifiant pas de préférence) soit comme une URI. Si, au moment où l'évènement est inscrit pour être envoyé, le protocole, le nom d'hôte ou le port du document de <code>otherWindow</code> ne correspond pas à ceux contenus dans <code>targetOrigin</code>, l'évènement ne sera pas envoyé ; il ne le sera que si les trois correspondent. Ce mécanisme permet de contrôler où les messages sont envoyés ; par exemple, si <code>postMessage</code> était utilisé pour transmettre un mot de passe, il serait absolument vital que cet argument soit une URI dont l'origine est la même que le récepteur prévu du message contenant le mot de passe, afin de prévenir l'interception du mot de passe par une tierce-partie malicieuse. <strong>Fournissez toujours une <code>targetOrigin</code> spécifique, jamais <code>*</code>, si vous savez où le document de l'autre fenêtre est censé se trouver. Ne pas fournir une cible spécifique expose les données que vous envoyez à tout site malicieux à l'écoute.</strong></dd>
<dt><code><em><strong>transfer</strong></em></code> {{optional_Inline}}</dt>
<dd>Séquence d'objets {{domxref("Transferable")}} qui sera transmise avec le message. La possession de ces objets est cédée à la destination et ils ne sont plus utilisables du côté de l'expéditeur.</dd>
</dl>
<h2 id="The_dispatched_event" name="The_dispatched_event">L'évènement envoyé</h2>
<p><code>otherWindow</code> peut surveiller les messages envoyés en exécutant le JavaScript suivant :</p>
<pre class="brush: js">window.addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
if (event.origin !== "http://example.org:8080")
return;
// ...
}
</pre>
<p>Les propriétés du message envoyé sont :</p>
<dl>
<dt><code>data</code></dt>
<dd>L'objet passé depuis l'autre fenêtre.</dd>
<dt><code>origin</code></dt>
<dd>L'<a href="/en-US/docs/Origin" title="Origin">origine</a> de la fenêtre qui a envoyé le message au moment où <code>postMessage</code> a été appelée. Des exemples typiques d'origines sont <code><span class="nowiki">https://example.org</span></code> (sous-entendu port <code>443</code>), <code><span class="nowiki">http://example.net</span></code> (sous-entendu port <code>80</code>), et <code><span class="nowiki">http://example.com:8080</span></code>. Notez qu'il n'est pas garanti que cette origine soit l'origine actuelle ou future de cette fenêtre, qui peut avoir été naviguée vers une adresse différente depuis l'appel à <code>postMessage</code>.</dd>
<dt><code>source</code></dt>
<dd>Une référence à l'objet <code><a href="/fr/docs/DOM/window" title="DOM/window">window</a></code> qui a envoyé le message ; vous pouvez utiliser ceci pour établir une communication dans les deux sens entre deux fenêtres ayant différentes origines.</dd>
</dl>
<dl>
</dl>
<h2 id="Security_concerns" name="Security_concerns">Précautions de sécurité</h2>
<p><strong>Si vous ne prévoyez pas de recevoir de messages depuis d'autres sites, n'ajoutez pas de gestionnaire d'évènement pour les évènements <code>message</code>.</strong> C'est un moyen sûr d'éviter les problèmes de sécurité.</p>
<p>Si vous prévoyez de recevoir des messages depuis d'autres sites, <strong>vérifiez toujours l'identité de l'expéditeur</strong> à l'aide des propriétés <code>origin</code> et si possible <code>source</code>. Toute fenêtre (y compris, par exemple, <code><span class="nowiki">http://evil.example.com</span></code>) peut envoyer un message à toute autre fenêtre, et vous n'avez aucune garantie qu'un expéditeur inconnu ne va pas envoyer de message malicieux. Cependant, même si vous vérifiez l'identité, vous devriez <strong>toujours vérifier la syntaxe du message reçu</strong>. Dans le cas contraire, une faille de sécurité dans le site auquel vous faites confiance peut ouvrir une vulnérabilité XSS dans votre propre site.</p>
<p><strong>Spécifiez toujours explicitement une origine de destination, jamais <code>*</code>, quand vous utilisez <code>postMessage</code> pour envoyer des données à d'autres fenêtres.</strong> Un site malicieux peut changer l'adresse de la fenêtre à votre insu, et ainsi intercepter les données envoyées à l'aide de <code>postMessage</code>.</p>
<h2 id="Example" name="Example">Exemple</h2>
<pre class="brush: js">/*
* Dans les scripts de la fenêtre A, avec A sur <http://example.com:8080>:
*/
var popup = window.open(...popup details...);
// Quand la popup est chargée, si pas bloquée par un bloqueur de popups:
// Ceci ne fait rien, en supposant que la fenêtre n'a pas changé d'adresse.
popup.postMessage("The user is 'bob' and the password is 'secret'",
"https://secure.example.net");
// Ceci va planifier l'envoi d'un message à la popup, en supposant que
// la fenêtre n'a pas changé d'adresse.
popup.postMessage("hello there!", "http://example.org");
function receiveMessage(event)
{
// Faisons-nous confiance à l'expéditeur de ce message ? (il pourrait être
// différent de la fenêtre que nous avons ouverte au départ, par exemple).
if (event.origin !== "http://example.org")
return;
// event.source est la popup
// event.data est "hi there yourself! the secret response is: rheeeeet!"
}
window.addEventListener("message", receiveMessage, false);
</pre>
<pre class="brush: js">/*
* Dans les scripts de la popup, sur <http://example.org>:
*/
// Appelée quelques instants après que postMessage a été appelée
function receiveMessage(event)
{
// Faisons-nous confiance à l'expéditeur de ce message ?
if (event.origin !== "http://example.com:8080")
return;
// event.source est window.opener
// event.data est "hello there!"
// Supposant que vous avez vérifié l'origine du message reçu
// (ce que vous devriez faire en toutes circonstances),
// un moyen pratique de répondre à un message est d'appeler postMessage
// sur event.source et fournir event.origin comme targetOrigin.
event.source.postMessage("hi there yourself! the secret response " +
"is: rheeeeet!",
event.origin);
}
window.addEventListener("message", receiveMessage, false);
</pre>
<h3 id="Notes" name="Notes">Notes</h3>
<p>Toute fenêtre peut accéder à cette méthode sur toute autre fenêtre, à tout moment, peu importe l'adresse du document dans la fenêtre, pour y envoyer un message. Par conséquent, tout gestionnaire d'évènement utilisé pour recevoir des messages <strong>doit</strong> d'abord vérifier l'identité de l'expéditeur du message, en utilisant les propriétés <code>origin</code> et si possible <code>source</code>. Cela ne peut pas être minimisé : <strong>ne pas vérifier les propriétés <code>origin</code> et si possible <code>source</code> permet des attaques inter-site.</strong></p>
<p>De même qu'avec les scripts exécutés de manière asynchrone (timeouts, evènements générés par l'utilisateur), il n'est pas possible pour l'appelant à <code>postMessage</code> de détecter quand un gestionnaire d'évènement écoutant des évènements envoyés par <code>postMessage</code> lance une exception.</p>
<p>La valeur de la propriété <code>origin</code> de l'évènement envoyé n'est pas affectée par la valeur actuelle de <code>document.domain</code> dans la fenêtre appelante.</p>
<p>Pour les noms d'hôte IDN uniquement, la valeur de la propriété <code>origin</code> n'est pas systématiquement Unicode ou punycode ; pour la plus grande compatibilité, testez à la fois les valeurs IDN et punycode quand vous utilisez cette propriété si vous attendez des messages de sites IDN. Cette valeur sera systématiquement IDN à l'avenir, mais pour l'instant vous devriez gérer à la fois les formes IDN et punycode.</p>
<p>La valeur de la propriété <code>origin</code> quand la fenêtre expéditrice contient une URL <code>javascript:</code> ou <code>data:</code> est l'origin du script qui a chargé cette URL.</p>
<h3 id="Utiliser_window.postMessage_dans_les_extensions_Non-standard_inline">Utiliser window.postMessage dans les extensions {{Non-standard_inline}}</h3>
<p><code>window.postMessage</code> est disponible depuis le JavaScript exécuté en code chrome (par exemple dans les extensions et le code privilégié), mais la propriété <code>source</code> de l'évènement envoyé est toujours <code>null</code> par mesure de sécurité. (Les autres propriétés ont leurs valeurs usuelles.) L'argument <code>targetOrigin</code> pour un message envoyé à une fenêtre située à une URL<code> chrome:</code> est actuellement mal interprété, si bien que la seule valeur qui conduit à l'envoi d'un message est <code>"*"</code>. Comme cette valeur n'est pas sûre quand la fenêtre ciblée peut être naviguée n'importe où par un site malicieux, il est recommandé de ne pas utiliser <code>postMessage</code> pour communiquer avec des pages <code>chrome:</code> pour l'instant ; utilisez une méthode différente (comme une query string quand la fenêtre est ouverte) pour communiquer avec des fenêtres chrome. Enfin, poster un message à une page à une URL <code>file:</code> requiert actuellement que l'argument <code>targetOrigin</code> soit <code>"*"</code>. <code>file://</code> ne peut pas être utilisé comme restriction de sécurité ; cette restriction pourrait être modifiée à l'avenir.</p>
<h2 id="Spécifications">Spécifications</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col"><strong>Spécification</strong></th>
<th scope="col"><strong>Status</strong></th>
<th scope="col"><strong>Comment</strong>aire</th>
</tr>
<tr>
<td>{{SpecName('HTML WHATWG', "#dom-window-postmessage", "window.postMessage")}}</td>
<td>{{Spec2('HTML WHATWG')}}</td>
<td>Pas de changement depuis {{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>Définition initiale.</td>
</tr>
</tbody>
</table>
<h2 id="Compatibilité_des_navigateurs">Compatibilité des navigateurs</h2>
<p>{{Compat("api.Window.postMessage")}}</p>
<h2 id="Voir_aussi">Voir aussi</h2>
<ul>
<li><a href="/en-US/docs/DOM/document.domain" title="DOM/document.domain">Document.domain</a></li>
<li><a href="/en-US/docs/Web/API/CustomEvent" title="/en-US/docs/Web/API/CustomEvent">CustomEvent</a></li>
<li><a href="/en-US/docs/Code_snippets/Interaction_between_privileged_and_non-privileged_pages" title="/en-US/docs/Code_snippets/Interaction_between_privileged_and_non-privileged_pages">Interaction entre les pages privilégiées et non privilégiées</a></li>
</ul>
|