You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If we have a reference to another window (a popup or iframe), and that window comes from the same origin, then we can do everything with it.
27
27
28
-
Otherwise, we can only change its location. Please note: not *read*, but modify it, redirect it to another place. That's possible, because such action does not reveal any data. Also such windows windows may exchange messages. Soon about that later.
28
+
If it comes from another origin, then we can only change its location. Please note: not *read* the location, but *modify* it, redirect it to another place. That's safe, because the URL may contain sensitive parameters, so reading it from another origin is prohibited, but changing is not.
29
+
30
+
Also such windows windows may exchange messages. Soon about that later.
29
31
30
32
````warn header="Exclusion: subdomains may be same-origin"
31
33
32
34
There's an important exclusion in the same-origin policy.
33
35
34
-
If windows share the same second-level domain, for instance `john.site.com`, `peter.site.com` and `site.com`, and assign to `document.domain` their common second-level domain `site.com`, then limitations are removed.
36
+
If windows share the same second-level domain, for instance `john.site.com`, `peter.site.com` and `site.com`, we can use JavaScript to assign to `document.domain` their common second-level domain `site.com`. Then these windows are treated as having the same origin.
35
37
36
38
In other words, all such documents (including the one from `site.com`) should have the code:
37
39
@@ -40,49 +42,51 @@ document.domain = 'site.com';
40
42
```
41
43
42
44
Then they can interact without limitations.
45
+
46
+
That's only possible for pages with the same second-level domain.
43
47
````
44
48
45
-
## Managing iframes
49
+
## Accessing an iframe contents
46
50
47
-
An `<iframe>` is a two-faced beast. From one side it's a tag, just like `<script>` or `<img>`. From another side it's a window-in-window.
51
+
An `<iframe>` is a two-faced beast. From one side it's a tag, just like `<script>` or `<img>`. From the other side it's a window-in-window.
48
52
49
-
The embedded window has a separate `window` and `document` objects, scripts and so on.
53
+
The embedded window has a separate `document` and `window` objects.
50
54
51
-
We can access them:
55
+
We can access them like using the properties:
52
56
53
57
-`iframe.contentWindow` is a reference to the window inside the `<iframe>`.
54
-
-`iframe.contentDocument` is a reference to the document inside it.
58
+
-`iframe.contentDocument` is a reference to the document inside the `<iframe>`.
55
59
56
-
When we access an embedded window, the browser checks if the iframe has the same origin. If that's not so then the access to almost everything is denied.
60
+
When we access an embedded window, the browser checks if the iframe has the same origin. If that's not so then the access is denied (with exclusions noted above).
57
61
58
-
For instance:
62
+
For instance, here's an `<iframe>` from another origin:
// ...but we can change it (and thus load something else into the iframe)!
83
87
iframe.contentWindow.location='/'; // works
84
88
85
-
iframe.onload=null; // run this code only once
89
+
iframe.onload=null; //clear the handler, to run this code only once
86
90
};
87
91
</script>
88
92
```
@@ -98,7 +102,7 @@ The `iframe.onload` event is actually the same as `iframe.contentWindow.onload`.
98
102
...But `iframe.onload` is always available, while `iframe.contentWindow.onload` needs the same origin.
99
103
```
100
104
101
-
And here's an example with the same origin:
105
+
And now an example with the same origin. We can do anything with the embedded window:
102
106
103
107
```html run
104
108
<iframe src="/" id="iframe"></iframe>
@@ -111,7 +115,7 @@ And here's an example with the same origin:
111
115
</script>
112
116
```
113
117
114
-
### Wait until the iframe loads
118
+
### Please wait until the iframe loads
115
119
116
120
When an iframe is created, it immediately has a document. But that document is different from the one that finally loads into it!
117
121
@@ -126,6 +130,7 @@ Here, look:
126
130
iframe.onload=function() {
127
131
let newDoc =iframe.contentDocument;
128
132
*!*
133
+
// the loaded document is not the same as initial!
129
134
alert(oldDoc == newDoc); // false
130
135
*/!*
131
136
};
@@ -134,9 +139,9 @@ Here, look:
134
139
135
140
That's actually a well-known pitfall for novice developers. We shouldn't work with the document immediately, because that's the *wrong document*. If we set any event handlers on it, they will be ignored.
136
141
137
-
...But the `onload` event triggers when the whole iframe with all resources is loaded. What if we want to act sooner, on `DOMContentLoaded`?
142
+
...But the `onload` event triggers when the whole iframe with all resources is loaded. What if we want to act sooner, on `DOMContentLoaded` of the embedded document?
138
143
139
-
We can try to catch the moment when a new document appears, and then setup necessary handlers, like this:
144
+
That's not possible if the iframe comes from another origin. But for the same origin we can try to catch the moment when a new document appears, and then setup necessary handlers, like this:
140
145
141
146
```html run
142
147
<iframesrc="/"id="iframe"></iframe>
@@ -148,19 +153,19 @@ We can try to catch the moment when a new document appears, and then setup neces
clearInterval(timer); // cancel setInterval, don't need it any more
157
162
}, 100);
158
163
</script>
159
164
```
160
165
161
166
Let me know in comments if you know a better solution here.
162
167
163
-
###window.frames
168
+
## window.frames
164
169
165
170
An alternative way to get a window object for `<iframe>` -- is to get it from the named collection `window.frames`:
166
171
@@ -202,16 +207,18 @@ if (window == top) { // current window == window.top?
202
207
}
203
208
```
204
209
205
-
### The sandbox attribute
210
+
## The sandbox attribute
211
+
212
+
The `sandbox` attribute allows to forbid certain actions inside an `<iframe>`, to run an untrusted code. It "sandboxes" the iframe by treating it as coming from another origin and/or applying other limitations.
206
213
207
-
The `sandbox` attribute allows to run untrusted content inside an `<iframe>`. It "sandboxes" the iframe by treating it as coming from another origin and forbidding certain actions.
214
+
By default, for `<iframe sandbox src="...">` the "default set" of restrictions is applied to the iframe. But we can provide a space-separated list of "excluded" limitations as a value of the attribute, like this: `<iframe sandbox="allow-forms allow-popups">`. The listed limitations are not applied.
208
215
209
-
There are many restrictions. By default, for `<iframe sandbox src="...">` all of them are applied. But if we specify them in a value of the attribute, like this: `<iframe sandbox="allow-forms allow-popups">`, then they are lifted.
216
+
In other words, an empty `"sandbox"` attribute puts the strictest limitations possible, but we can put a space-delimited list of those that we want to lift.
210
217
211
-
In other words, an empty `"sandbox"` attribute puts the strictest limitations possible, but we can put a space-delimited list of those that we want to lift:
218
+
Here's a list of limitations:
212
219
213
220
`allow-same-origin`
214
-
: By default `"sandbox"` forces the browser to treat the `iframe` as coming from another origin, even if it's`src` points to the same site. This option removes that feature.
221
+
: By default `"sandbox"` forces the "different origin" policy for the iframe. In other words, it makes the browser to treat the `iframe` as coming from another origin, even if its`src` points to the same site. With all implied restrictions for scripts. This option removes that feature.
215
222
216
223
`allow-top-navigation`
217
224
: Allows the `iframe` to change `parent.location`.
@@ -227,13 +234,15 @@ In other words, an empty `"sandbox"` attribute puts the strictest limitations po
227
234
228
235
See [the manual](mdn:/HTML/Element/iframe) for more.
229
236
230
-
The example below demonstrates a sandboxed iframe with some JavaScript and a form. Neither one works:
237
+
The example below demonstrates a sandboxed iframe with the default set of restrictions: `<iframe sandbox src="...">`. It has some JavaScript and a form.
238
+
239
+
Please note that nothing works. So the default set is really harsh:
231
240
232
241
[codetabs src="sandbox" height=140]
233
242
234
243
235
244
```smart
236
-
The purpose of the `"sandbox"` attribute is to add restrictions. It cannot remove them. In particular, it can't relax same-origin restrictions if the iframe comes from another origin.
245
+
The purpose of the `"sandbox"` attribute is only to *add more* restrictions. It cannot remove them. In particular, it can't relax same-origin restrictions if the iframe comes from another origin.
237
246
```
238
247
239
248
## Cross-window messaging
@@ -249,18 +258,16 @@ The window that wants to send a message calls [postMessage](mdn:api/Window.postM
249
258
Arguments:
250
259
251
260
`data`
252
-
: The data to send. Can be any object, the data is cloned using the "structured cloning algorithm". IE supports only strings, so we can`JSON.stringify` complex objects.
261
+
: The data to send. Can be any object, the data is cloned using the "structured cloning algorithm". IE supports only strings, so we should`JSON.stringify` complex objects to support that browser.
253
262
254
263
`targetOrigin`
255
-
: Allow only a window from the given origin to get the message.
256
-
257
-
The `targetOrigin` is a safety measure. If the target window comes from another origin, we can't read it's `location`. We can't be sure which site is open in it right now, the user could navigate away.
264
+
: Specifies the origin for the target window, so that only a window from the given origin will get the message.
258
265
259
-
Specifying`targetOrigin`ensures that the window only receives the data if it's still at that site. Good when the data is secure.
266
+
The`targetOrigin`is a safety measure. Remember, if the target window comes from another origin, we can't read it's `location`. So we can't be sure which site is open in the intended window right now: the user could navigate away.
260
267
261
-
If we don't want that check, we can set `targetOrigin` to `*`.
268
+
Specifying `targetOrigin` ensures that the window only receives the data if it's still at that site. Good when the data is sensitive.
262
269
263
-
For instance:
270
+
For instance, here `win` will only receive the message if it has a document from the origin `http://example.com`:
264
271
265
272
```html no-beautify
266
273
<iframesrc="http://example.com"name="example">
@@ -269,18 +276,32 @@ For instance:
269
276
let win =window.frames.example;
270
277
271
278
win.postMessage("message", "http://example.com");
272
-
// win.postMessage("message", "*");
273
279
</script>
274
280
```
275
281
282
+
If we don't want that check, we can set `targetOrigin` to `*`.
283
+
284
+
```html no-beautify
285
+
<iframesrc="http://example.com"name="example">
286
+
287
+
<script>
288
+
let win =window.frames.example;
289
+
290
+
*!*
291
+
win.postMessage("message", "*");
292
+
*/!*
293
+
</script>
294
+
```
295
+
296
+
276
297
### onmessage
277
298
278
-
To receive a message, the window should have a handler on the `message` event.
299
+
To receive a message, the target window should have a handler on the `message` event. It triggers when `postMessage` is called (and `targetOrigin` check is successful).
279
300
280
301
The event object has special properties:
281
302
282
303
`data`
283
-
: The data from `postMessage`
304
+
: The data from `postMessage`.
284
305
285
306
`origin`
286
307
: The origin of the sender, for instance `http://javascript.info`.
@@ -315,23 +336,23 @@ There's totally no delay between `postMessage` and the `message` event. That hap
315
336
316
337
To call methods and access the content of another window, we should first have a reference to it.
317
338
318
-
For popups:
339
+
For popups we have two properties:
319
340
-`window.open` -- opens a new window and returns a reference to it,
320
341
-`window.opener` -- a reference to the opener window from a popup
321
342
322
-
For iframes:
323
-
-`window.frames`is a collection of nested window objects,
343
+
For iframes, we can access parent/children windows using:
344
+
-`window.frames`-- a collection of nested window objects,
324
345
-`window.parent`, `window.top` are the references to parent and top windows,
325
346
-`iframe.contentWindow` is the window inside an `<iframe>` tag.
326
347
327
-
Then if they come from the same origin (host, port, protocol), then windows can do whatever they want with each other.
348
+
If windows share the same origin (host, port, protocol), then windows can do whatever they want with each other.
328
349
329
350
Otherwise, only possible actions are:
330
351
- Change the location of another window (write-only access).
331
352
- Post a message to it.
332
353
333
354
Exclusions are:
334
-
- Windows share the same main domain: `a.site.com` and `b.site.com`. Then setting `document.domain='site.com'` in both of them puts them into "same origin".
355
+
- Windows that share the same second-level domain: `a.site.com` and `b.site.com`. Then setting `document.domain='site.com'` in both of them puts them into the "same origin" state.
335
356
- If an iframe has a `sandbox` attribute, it is forcefully put into the "different origin" state, unless the `allow-same-origin` is specified in the attribute value. That can be used to run untrusted code in iframes from the same site.
336
357
337
358
The `postMessage` interface allows two windows to talk with security checks:
0 commit comments