forked from WICG/anonymous-iframe
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.bs
1375 lines (1052 loc) · 55 KB
/
index.bs
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!--
-*- vim: set filetype=html:
-*- vim: set colorcolumn=80:
-*- vim: set tw=80:
!-->
<pre class="metadata">
Title: Anonymous iframe
Status: CG-DRAFT
Group: WICG
URL: https://wicg.github.io/anonymous-iframe/
Repository: WICG/anonymous-iframe
Shortname: anonymous-iframe
Level: 1
Editor: Arthur Sonzogni, Google, [email protected]
Editor: Camille Lamy, Google, [email protected]
Abstract:
Anonymous iframe give developers a way to load documents in third party iframe
using new and ephemeral context. In return, the
[Cross-Origin-Embedder-Policy](https://wicg.github.io/cross-origin-embedder-policy/)
(COEP) embedding rules can be lifted.
This way, developers using COEP can now embed third party iframes that do not.
Indent: 2
Work Status: exploring
Boilerplate: omit conformance
Markup Shorthands: css off, markdown on
WPT Display: inline
WPT Path Prefix: html/anonymous-iframe/
!Tests: <a href=https://github.com/w3c/web-platform-tests/tree/master/html/anonymous-iframe>web-platform-tests html/anonymous-iframe/</a> (<a href=https://github.com/w3c/web-platform-tests/labels/html/anonymous-iframe>ongoing work</a>)
</pre>
<pre boilerplate="copyright">©2022, Google, Inc. All rights reserved.</pre>
<pre class="biblio">
{
"spectre": {
"authors": [
"Paul Kocher",
"Jann Horn",
"Anders Fogh",
"Daniel Genkin",
"Daniel Gruss",
"Werner Haas",
"Mike Hamburg",
"Moritz Lipp",
"Stefan Mangard",
"Thomas Prescher",
"Michael Schwarz",
"Yuval Yarom"
],
"href": "https://spectreattack.com/spectre.pdf",
"title": "Spectre Attacks: Exploiting Speculative Execution"
},
"Cookies": {
"authors": [
"Mike West",
"John Wilander"
],
"title": "Cookies: HTTP State Management Mechanism",
"href": "https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-07"
},
"CHIPS": {
"authors": [
"Dylan Cutler",
"Kaustubha Govind"
],
"title": "CHIPS (Cookies Having Independent Partitioned State)",
"href": "https://github.com/WICG/CHIPS"
},
"COEP-require-corp": {
"authors": [
"Mike West"
],
"href": "https://wicg.github.io/cross-origin-embedder-policy/",
"title": "COEP"
},
"COEP-credentialless": {
"authors": [
"Arthur Sonzogni",
"Camille Lamy",
"Ian Clelland",
"Mike West"
],
"href": "https://wicg.github.io/cross-origin-embedder-policy/",
"title": "COEP: credentialless"
},
"WhyCoopCoep": {
"authors": [
"Eiji Kitamura",
"Demenic Denicola"
],
"href": "https://web.dev/why-coop-coep/",
"title": "Why you need \"cross-origin isolated\" for powerful features"
},
"StoragePartition": {
"title": "Client-Side Storage Partitioning",
"href": "https://privacycg.github.io/storage-partitioning/"
},
"STORAGE": {
"title": "Storage",
"href": "https://storage.spec.whatwg.org/"
},
"SecurityPrivacyQuestionnaire": {
"authors": [
"Theresa O’Connor",
"Pete Snyder",
"Jason Novak",
"Lukasz Olejnik",
"Mike West"
],
"title": "Self-Review Questionnaire: Security and Privacy",
"href": "https://www.w3.org/TR/security-privacy-questionnaire/"
}
}
</pre>
<pre class="anchors">
urlPrefix: https://tc39.es/ecma262/; spec: ECMAScript
text: SharedArrayBuffer; type: interface; url: sec-sharedarraybuffer-objects
urlPrefix: https://html.spec.whatwg.org/C/; spec: html
text: BroadcastChannel; type:dfn; url:broadcasting-to-other-browsing-contexts
text: COEP; type: dfn; url: coep
text: COOP; type: dfn; url: cross-origin-opener-policies
text: Cross-Origin-Embedder-Policy; type: dfn; url: coep
text: Cross-Origin-Opener-Policy; type: dfn; url: cross-origin-opener-policies
text: HTMLIframeElement; type:dfn; url:HTMLIframeElement
text: ServiceWorker; type:dfn; url:service-worker-obj
text: SharedWorker; type:dfn; url:sharedworer
text: about:blank; type:dfn; url:about:blank
text: bc-container-document; type: dfn; url: bc-container-document
text: bc-container; type:dfn; url:bc-container
text: check a navigation response's adherence to its embedder policy; type:dfn; url:check-a-navigation-response's-adherence-to-its-embedder-policy
text: compatible with cross-origin isolation; type: dfn; url:compatible-with-cross-origin-isolation
text: concept-document-bc; type:dfn; url:concept-document-bc
text: concept-document-origin; type:dfn; url:concept-document-origin
text: concept-document-policy-container; type: dfn; url: concept-document-policy-container
text: creating a new browsing context; type:dfn; url:creating-a-new-browsing-context
text: crossOriginIsolated; type:dfn; url:concept-settings-object-cross-origin-isolated-capability
text: embedder-policy-report-only-reporting-endpoint; type: dfn; url: embedder-policy-report-only-reporting-endpoint
text: embedder-policy-report-only-value; type: dfn; url: embedder-policy-report-only-value
text: embedder-policy-reporting-endpoint; type: dfn; url: embedder-policy-reporting-endpoint
text: embedder-policy-value; type:dfn; url:embedder-policy-value
text: entry global object; type:dfn; url:entry-global-object
text: hh-replace; type:dfn; url:hh-replace
text: iframe; type:dfn; url:the-iframe-element
text: initialize the document object; type:dfn; url:initialise-the-document-object
text: is initial about:blank; type:dfn; url:is-initial-about:blank
text: navigation params; type:dfn; url:navigation-params
text: navigation-params-hh; type:dfn; url:navigation-params-hh
text: navigation-params-origin; type:dfn; url:navigation-params-origin
text: policy-container-embedder-policy; type: dfn; url: policy-container-embedder-policy
text: queue a cross-origin embedder policy inheritance violation; type:dfn; url: queue-a-cross-origin-embedder-policy-inheritance-violation
text: still on its initial about:blank document; type:dfn; url:still-on-its-initial-about:blank-document
text: window open steps; type:dfn; url:window-open-steps
text: concept-environment-id; type:dfn; url:concept-environment-id
text: concept-environment-targetting-id; type:dfn; url:concept-environment-targetting-id
text: concept-environment-creation-url; type:dfn; url:concept-environment-creation-url
text: concept-environment-target-browsing-context; type:dfn; url:concept-environment-target-browsing-context
text: navigation-params-reserved-environment; type:dfn; url:navigation-params-reserved-environment
text: environment; type:dfn; url:environment
text: concept-request-reserved-client; type:dfn; url:concept-request-reserved-client
text: concept-environment-active-service-worker; type:dfn; url:concept-environment-active-service-worker
text: origin; type:dfn; url:concept-origin
text: set up a window environment settings object; type:dfn; url:set-up-a-window-environment-settings-object
text: script settings for workers; type:dfn; url:script-:settings-for-workers
text: set up a worklet environment settings object; type:dfn; url:set-up-a-worklet-environment-settings-object
<!--text: A; type:dfn; url:A-->
<!--text: A; type:dfn; url:A-->
urlPrefix: https://fetch.spec.whatwg.org/
text: network partition key; type:dfn; url:network-partition-key
text: concept-response; type:dfn; url:concept-response
urlPrefix: https://storage.spec.whatwg.org/
text: storage key; type:dfn; url:storage-key
urlPrefix: https://dom.spec.whatwg.org/
text: EventTarget; type:dfn; url:interface-eventtarget
urlPrefix: https://github.com/w3c/mediacapture-viewport
text: getViewPortMedia; type:dfn; url:/issues/1
urlPrefix: https://www.w3.org/TR/hr-time/
text: high resolution timers; type:dfn; url:/issues/1#issuecomment-812
urlPrefix: https://webidl.spec.whatwg.org/#LegacyUnenumerableNamedProperties
text: LegacyUnenumerableNamedProperties; type:dfn; url:LegacyUnenumerableNamedProperties
urlPrefix: https://tc39.es/ecma262/#sec-execution-contexts
text: javascript execution context; type:dfn; url:sec-execution-contexts
text: back/forward cache; type:dfn; url:https://web.dev/bfcache/
text: threat model; type:dfn; url:#threat-model
</pre>
<pre class="link-defaults">
spec:fetch; type:dfn; for:/; text:response
spec:html; type:dfn; for:/; text:origin
spec:html; type:dfn; for:Window; text:browsing context
spec:html; type:dfn; for:policy container; text:embedder policy
spec:html; type:dfn; text:environment
spec:url; type:dfn; for:/; text:url
</pre>
<style>
.monkey-patch {
padding: .5em;
border: thin solid #ddd;
border: thin solid 1px;
border-radius: .5em;
margin: .5em calc(-0.5em - 1px);
background-color: rgba(255, 255, 0, 0.03);
backdrop-filter: blur(5px);
box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.05);
}
.brief {
line-height: 10%;
}
.customHighlight {
padding-top:9px ;
padding-bottom:9px ;
background-color: rgba(255,255,0,0.3)
}
</style>
Introduction { #introduction }
============
<em>This section is not normative.</em>
Recommended readings {#recommended-readings}
--------------------
- The [[Spectre]] vulnerability.
- The [[COEP-require-corp]] and [[COEP-credentialless]] headers.
- How and why [=Cross-Origin-Opener-Policy=] ([=COOP=]) and
[=Cross-Origin-Embedder-Policy=] ([=COEP=]) are granting the
[crossOriginIsolated](concept-settings-object-cross-origin-isolated-capability)
capability. See [[WhyCoopCoep]].
A problem {#problem}
=========
<em>This section is not normative.</em>
Deploying [=COEP=] is difficult for some developers, because of third party
iframes. Here is the typical scenario:
1. End users needs performant websites.
2. Some developers get performant websites, by using
multithreading/{{SharedArrayBuffer}} in their top-level document.
3. To mitigate [[Spectre]] attacks, browsers vendors like Chrome, Firefox and
Safari gate {{SharedArrayBuffer}} usage behind the [=crossOriginIsolated=]
capability. This requires deploying both [=COEP=] and [=COOP=]
4. [=COEP=] requirement is recursive: third party iframes are required to
deploy [=COEP=] in order to be embeddable inside a [=COEP=] parent.
5. Waiting for third party to deploy [=COEP=] is painful for developers. This
is often out of their control most of the time.
Beyond performance, there are additionnal features gated behind the
[=crossOriginIsolated=] capability: [=high resolution timers=],
[=getViewportMedia=], etc...
Deploying [=COEP=] is challenging in cases where there's not a single developer
involved, but many. Google Ads, for example, includes third-party content, and
it seems somewhat unlikely that they'll be able to ensure that all the ads
creators will do the work to opt-into being loadable.
Explainer {#explainer}
=========
<em>This section is not normative.</em>
[[COEP-require-corp]] currently tackles data leak attacks by ensuring that
cross-origin resources explicitly opt into being loaded in an environment with
higher risks. This way, servers can protect vulnerable resources by not having
them opt into being loaded in high risk environments.
It would be ideal if we could find an approach that provided robust-enough
protection against accidental cross-process leakage without requiring an
explicit opt-in.
[[COEP-credentialless]] fixed the problem for simple subresources: Instead of
requiring an opt-in from the response, the resource is requested without
credentials. This way, only public resources are potentially leaked to the
attacker. They don't bring any additional value to the attacker.
**Anonymous iframes** are similar, but for `<iframe>`.
Iframes are more difficult to tackle. They not only fetch a resource via a
navigation request, but also create a new context. The new context is able to
fetch data on its own. It can also access data from storage APIs:
[[WebStorage]], [[IndexedDB]], [[web-sql]], [=BroadcastChannel=],
[=SharedWorker=], [=ServiceWorker=], etc
Anonymous iframes is a flag to load documents in iframes, using a new and
ephemeral context. This ensures only a "public" version of the embedded website
can be leaked to the attacker.
What are anonymous iframes? {#proposal-whatis}
---------------------------
Documents can create anonymous iframes by adding an `anonymous` attribute to the
iframe tag:
```html
<iframe anonymous src=”https://example.com”></iframe>
```
This property is stored on the iframe. It is also stored and inherited to new
[=Window=] loaded inside e.g.:
<img alt="anonymous inheritance" src="./resources/inheritance.png"></img>
*Anonymous flag inheritance.*
Similar to sandbox flags, the attribute can be changed programmatically on the
`<iframe>`. It will take effect on new [=Window=] loaded inside. It means the
effect will only take place after an additional navigation.
The state of the anonymous flag is exposed to the [=Window=] through a read-only
constant attribute:
```js
window.anonymous
```
It is true for [=Window=] loaded immediately inside an anonymous iframe, or
deeper below it.
Anonymous iframes and credentials {#proposal-credentials}
---------------------------------
Anonymous iframes cannot use existing credentials and shared storage for their
origin. They are given a blank slate. Unlike sandboxed frames, they can use
storage APIs and register cookies. However, those credentials and storage can
only be shared by documents in anonymous iframes in the page (provided they meet
origin restrictions). They will no longer be accessible once the page has
navigated. Essentially, anonymous iframes are given a temporary [storage
shelf](https://storage.spec.whatwg.org/#storage-shelf) partitioned to anonymous
iframes in the page.
To achieve this, we rely on modifying the [storage
key](https://storage.spec.whatwg.org/#storage-key) used to access shared storage
by anonymous iframes. As part of the [client-side storage partitioning
effort](https://privacycg.github.io/storage-partitioning/) (declined across
[storage
APIs](https://github.com/wanderview/quota-storage-partitioning/blob/main/explainer.md),
[network
state](https://github.com/MattMenke2/Explainer---Partition-Network-State) and
[Cookie State](https://github.com/DCtheTall/CHIPS)), the storage key of an
environment will no longer be its simple origin as currently described in the
spec. Instead it will be a combination of the origin and the top-level site URL.
In an anonymous iframe, we will replace the top-level site URL in the partition
key by a nonce value, determined once per page. This nonce will be recomputed
every time the top-level frame navigates. This ensures that anonymous iframes
cannot share storage keys with non-anonymous iframes. Because the nonce is
changed on every page navigation, anonymous iframes do not share storage across
different pages, or across navigations.
<img alt="nonce in partition-key" src="./resources/partition-key.png"></img>
*Storage and credentials are only shared among anonymous iframes, following normal site/origin access checks.*
<img alt="page's nonce" src="./resources/page-change-nonce.png"></img>
*Storage and credentials created by anonymous iframes are no longer accessible
after the top level frame navigated away because the Storage key for anonymous
iframes will have changed. This applies to top-level history navigations as
well, meaning that when the page navigates away, anything stored by anonymous
iframes can be cleared by the browser, unless the page was stored in a
back-forward cache.*
Popups opened by anonymous iframes are not anonymous. However, we impose that
popups opened by anonymous iframes are opened with rel = noopener set. This is
done to prevent OAuth popup flows from being used in anonymous iframes. See the
<a>threat model</a> part for a discussion on why we impose this restriction.
How do anonymous iframes interact with COEP {#proposal-interactions}
-------------------------------------------
Our proposition is that anonymous iframes are safe enough to embed in a COEP
page, even if they haven’t opted to do so by sending a COEP header. Thus, when
navigating to a document in an anonymous iframe, we do not check whether it has
a COEP and CORP header, even if its parent does not have a COEP of unsafe-none.
This also means that anonymous iframes can be embedded in cross-origin isolated
pages without documents in them having to deploy COEP.
Anonymous iframes and autofill/password managers {#proposal-autofill}
------------------------------------------------
Browsers that implement autofill or password manager functionalities should make
them unavailable in anonymous iframes. The goal of anonymous iframes is to
preserve storage critical to an iframe function, but to avoid users logging into
anonymous iframes. Autofill and password managers make logging in easier, and so
should be avoided to prevent users accidentally logging in. This also allows
anonymous iframes to have a <a>threat model</a> similar to a phishing page (see
the <a>Threat model</a> part of this explainer below)
Alternatives considered {#alternatives}
=======================
<em>This section is not normative.</em>
## Sandboxed iframe ## {#alternatives-sandbox}
Sandboxed iframes without the allow-same-origin flag do not have access to
storage APIs or cookies for their subresource requests. However, the document of
a sandbox iframe can still be requested with credentials, which does not fit the
<a>threat model</a>. We could change sandboxed iframes so that documents are
also requested without credentials.
So why are we proposing introducing a new attribute instead of just using
sandboxed iframes with a new sandbox flag?
First, changing the behavior of sandboxed iframes so that their main resource is
always requested without credentials could break existing websites, as opposed
to introducing a new concept.
Second, we want to minimize the amount of disruption imposed to the content
inside the iframe. Using sandboxed iframes means the iframes cannot use cookies
or storage APIs at all, nor could they access any other frame in the document.
We are worried that this would limit the deployability of the credentialless
solution for opting into crossOriginIsolation. We’re looking to provide
developers with a solution that is as deployable as possible, which is why we’d
rather introduce a new solution that imposes as few restrictions to the iframes
as possible.
We could try to codify these restrictions as a sandbox flag, e.g.
allow-partitioned-storage. This is probably hard to reconcile with the storage
access sandbox flag shipped by Firefox and Safari, especially since a new
sandbox flag would be off by default.
This in turn is another issue with relying on sandboxed iframes for COEP
deployment. Because all flags are off by default, any new flag could impact the
behavior of sandboxed iframes. Not to mention that the syntax is a bit complex
due to the need to add every flag but the allow-same-origin to get all
functionality but access to cookies/storage.
## Opaque origins ## {#alternatives-opaque-origins}
The anonymous iframes model that we propose relies on partitioned storage (see
explainer), using a nonce in the storage key. We have also considered
attributing opaque origins to the anonymous iframes, similar to sandboxed
iframes. This would ensure that the anonymous iframes do not have access to
existing credentials and shared storage since their origin has been changed to
an opaque one.
This solution runs into compatibility issues:
* To allow anonymous iframes to access one another if they are coming from the
same origin we must maintain a mapping of original origin to opaque origin for
each anonymous iframe subtree, which is complex.
* We would probably need to standardize what happens when a frame with an opaque
origin wants to access a storage API since sandboxed iframes with opaque
origins do not have access to storage APIs at all.
* It is not clear how this would interact with other checks pertaining on origin
(e.g. X-Frame-Options, various CSP checks, …) potentially leading to further
breakages.
Tests {#tests}
=====
Status:
[https://wpt.fyi/results/html/anonymous-iframe/](https://wpt.fyi/results/html/anonymous-iframe/)
<!--<wpt>-->
<!--anonymous-iframe-popup.tentative.https.window.js-->
<!--anonymous-window.tentative.https.js-->
<!--cookie-store.tentative.https.window.js-->
<!--cookie.tentative.https.window.js-->
<!--fenced-frame-bypass.tentative.https.window.js-->
<!--fenced-frame.tentative.https.window.js-->
<!--local-storage.tentative.https.window.js-->
<!--require-corp-embed-anonymous-iframe.tentative.https.window.js-->
<!--serviceworker-partitioning.tentative.https.window.js-->
<!--session-storage.tentative.https.window.js-->
<!--sharedworker-partitioning.tentative.https.window.js-->
<!--web-lock.tentative.https.window.js-->
<!--</wpt>-->
Specification {#specification}
=============
Integration with HTML {#spec-html}
---------------------
Note: This corresponds to the following HTML specification change:
[whatwg/html/pull/7695](https://github.com/whatwg/html/pull/7695). <br/>
When merged this section will become obsolete.
### The Iframe attribute ### {#spec-iframe-attribute}
In the [the iframe element](https://html.spec.whatwg.org/#the-iframe-element)
section, define the HTML [=iframe=] <a lt="attr-iframe-anonymous">anonymous</a>
attribute:
<div class="monkey-patch">
The <dfn lt="attr-iframe-anonymous">anonymous</dfn>
attribute, enables loading documents hosted by the <a>iframe</a> with a
new and ephemeral storage partition. It is a boolean value. The default is
false.
</div>
It is exposed to the Javascript [=HTMLIFrameElement=] interface:
<div class="monkey-patch">
<pre class="idl" highlight="idl">
[Exposed=Window]
interface <a>HTMLIFrameElement</a> : <a>HTMLElement</a> {
// [...]
attribute boolean <a lt="dom-iframe-anonymous">anonymous</a>;
// [...]
};
</pre>
<p>The IDL attributes <dfn export lt="dom-iframe-anonymous">anonymous</dfn>,
must <a>reflect</a> the respective content attributes of the same name.</p>
</div>
### The Window attribute ### {#spec-window-attribute}
Add a read-only constant {{Window/anonymous}} attribute
to the [=Window=] object.
<div class="monkey-patch">
<pre class="idl" highlight="idl">
[
Global=<a>Window</a>,
Exposed=<a>Window</a>,
<a>LegacyUnenumerableNamedProperties</a>
]
interface <a>Window</a> : <a>EventTarget</a> {
// ...
readonly attribute boolean <a>anonymous</a>;
// ...
};
</pre>
</div>
### Creating new browsing context ### {#spec-new-browsing-context}
In the <a>creating a new browsing context</a> section:
Add step 5:
<div class="monkey-patch">
5. Let |anonymous| be the result of determining the <a
lt="initial-window-anonymous">initial window anonymous</a> flag, given
|browsingContext|.
</div>
Then later, use it for creating a new [=Window=].
<div class="monkey-patch">
- For the global object, create a new [=Window=] object<span
class="customHighlight">, with <a lt="attr-iframe-anonymous">anonymous</a> set
to |anonymous|.</span>
</div>
### Navigating a browsing context ### {#spec-navigating-browsing-context}
In the <a>navigation params</a> <a>struct</a>, adds the anonymous parameter:
<div class="monkey-patch">
<dl>
<dt><dfn lt="navigation-params-anonymous">anonymous</dfn></dt>
<dd>The anonymous flag to impose on the new [=Window=]</dd>
</dl>
</div>
------
In the <a>navigate</a> algorithm, adds step 18:
<div class="monkey-patch">
18. Let |anonymous| be the result of computing the <a
lt="navigation-anonymous">navigation's anonymous flag</a>, given
|browsingContext|.</p></li>
</div>
Then later in the same algorithm, use this variable to build the <a>navigation
params</a>.
It is also passed as a new argument to the <a>process a navigate fetch</a>
algorithm, which is also used to create a new <a>navigation params</a>.
------
Then, in the <a>initialize the document object</a> algorithm:
When creating a new [=Window=] in the <a>browsing context</a>, pass the
|anonymous| value.
<div class="monkey-patch">
- For the global object, create a new [=Window=] object<span
class="customHighlight">, with |anonymous| to |navigationParams|'s <a
lt="navigation-params-anonymous">anonymous</a>.</span>
</div>
---
The [=Window=] object must not be reused, when it would lead to keeping an
anonymous flag different from what is in the navigation params.
Example: This is useful in this case:
```js
const iframe = document.body.createElement("iframe");
iframe.anonymous = true;
document.body.appendChild(iframe);
iframe.anonymous = false;
iframe.src = "https://example.test";
// Window for about:blank and for https://example.test must be different.
```
<div class="monkey-patch">
- If |browsingContext| is <a>still on its initial about:blank Document</a>, and
|navigationParams|'s <a lt="navigation-params-hh">history handling</a> is "<a
lt="hh-replace">replace</a>", and |browsingContext|'s <a>active document</a>'s
<a lt="concept-document-origin">origin</a> is <a>same origin-domain</a> with
|navigationParams|'s <a lt="navigation-params-origin">origin</a>, <span
class="customHighlight">and |browsingContext|'s <a>active window</a>'s
{{Window/anonymous}} flag matches |navigationParams|'s <a
lt="navigation-params-anonymous">anonymous</a> flag</span>, then do
nothing.</p>
Note: This means that both the <a lt="is initial about:blank">initial
about:blank</a> [=Document=], and the new [=Document=] that is
about to be created, will share the same [=Window=] object.</p>
</div>
<div>
</div>
### Open popup with noopener ### {#spec-popup-noopener}
In the <a>window open steps</a>, adds step 5:
<div class="monkey-patch">
5. If <a>entry global object</a>'s {{Window/anonymous}} flag is true, then set
<var ignore>noopener</var> to true.
</div>
### General section ### {#spec-section}
Add an "Anonymous iframe" sub-section inside [Loading web
pages](https://html.spec.whatwg.org/C/#browsers) section, in between the [Sandboxing
one](https://html.spec.whatwg.org/C/#sandboxing) and the [Sandboxing
one](https://html.spec.whatwg.org/C/#sandboxing) and the [Cross-origin opener
policies](https://html.spec.whatwg.org/C/#cross-origin-opener-policies) ones:
<div class="monkey-patch">
**7.7 Anonymous iframe**
</div>
<div class="monkey-patch">
Each {{iframe}} element has a mutable
<a lt="attr-iframe-anonymous">anonymous</a> flag attribute.
</div>
<div class="monkey-patch">
Each {{Window}} has a constant {{Window/anonymous}} flag.
An <dfn export>anonymous Window</dfn> is a {{Window}}, whose
{{Window/anonymous}} flag is true.
</div>
<div class="monkey-patch">
To compute the <dfn export lt="initial-window-anonymous">initial window
anonymous flag</dfn>, given a new <a lt="concept-document-bc">browsing
context</a> |browsing context|:
<ol class="brief">
<li><p>Set |embedder| be |browsing context|'s <a
lt="bc-container">container</a>.</p>
<li><p>If |embedder| is not an element, return false.</p></li>
<li><p>Otherwise, set |parentWindow| be the |embedder|'s <a>node
document</a>'s <a>relevant global object</a>.</p></li>
<li><p>Return the union of:</p>
<ul class="brief">
<li><p>|parentWindow|'s {{Window/anonymous}}</p></li>
<li><p>|embedder|'s <a>iframe</a>'s <a
lt="attr-iframe-anonymous">anonymous</a></p></li>
</ul>
</li>
</ol>
</div>
<div class="monkey-patch">
To compute the <dfn export lt="navigation-anonymous">navigation's anonymous flag</dfn>,
given <a lt="concept-document-bc">browsing context</a> |browsing
context|, follows the same steps as in the <a
lt="initial-window-anonymous">initial window anonymous flag</a> algorithm.
</div>
Add several notes in the general section, gathering changes spread elsewhere in
the other algorithms.
<div class="monkey-patch">
Note: New [=Window=]'s {{Window/anonymous}} flag is computed either from the <a
lt="initial-window-anonymous">initial window anonymous flag</a> algorithm for
new <a lt="concept-document-bc">browsing context</a>, or from the <a
lt="navigation-anonymous">navigation's anonymous flag</a> algorithm, executed
when the navigation started, for navigations inside pre-existing <a
lt="concept-document-bc">browsing context</a>.
Note: Popup opened from <a>anonymous Window</a> are always with `noopener` set.
Note: Top-level <a>anonymous Window</a> do not exist.
</div>
### COEP embedder checks ### {#spec-coep-embedder-check}
The [=COEP=] embedding checks can be lifted.
Add a new parameters |anonymous| parameter to the <a>check a navigation
response's adherence to its embedder policy</a> and pass |navigationParams|'s <a
lt="navigation-params-anonymous">anonymous</a>.
<div class="monkey-patch">
<p>To <a>check a navigation response's adherence to its embedder policy</a>
given a <a lt="concept-response">response</a> |response|, a
<a>browsing context</a> |target|, an <a>embedder policy</a>
|responsePolicy|, <span class="customHighlight">and a boolean
|anonymous|</span>:</p>
<ol>
<li><p>If |target| is not a <a>child browsing context</a>, then
return true.</p></li>
<li><p>Let |parentPolicy| be |target|'s <a
lt="bc-container-document">container document</a>'s <a
lt="concept-document-policy-container">policy container</a>'s <a
lt="policy-container-embedder-policy">embedder policy</a>.</p></li>
<li><p>If |parentPolicy|'s <a
lt="embedder-policy-report-only-value">report-only value</a> is <a>compatible
with cross-origin isolation</a> and |responsePolicy|'s <a
lt="embedder-policy-value">value</a> is not, <span
class="customHighlight">and |anonymous| is false</span>, then
<a>queue a cross-origin embedder policy inheritance violation</a> with
|response|, "<code lt="">navigation</code>",
|parentPolicy|'s <a
lt="embedder-policy-report-only-reporting-endpoint">report only reporting
endpoint</a>, "<code lt="">reporting</code>", and |target|'s <a
lt="bc-container-document">container document</a>'s <a>relevant settings
object</a>.</p></li>
<li><p>If |parentPolicy|'s <a lt="embedder-policy-value">value</a>
is not <a>compatible with cross-origin isolation</a> or
|responsePolicy|'s <a lt="embedder-policy-value">value</a> is
<a>compatible with cross-origin isolation</a>, <span
class="customHighlight">or |anonymous| is true, </span>then return
true.</p></li>
<li><p><a>Queue a cross-origin embedder policy inheritance violation</a> with
|response|, "<code lt="">navigation</code>",
|parentPolicy|'s <a
lt="embedder-policy-reporting-endpoint">reporting endpoint</a>, "<code
lt="">enforce</code>", and |target|'s <a
lt="bc-container-document">container document</a>'s <a>relevant settings
object</a>.</p></li>
<li><p>Return false.</p></li>
</ol>
</div>
### Autofill ### {#spec-autofill}
In the "Anonymous iframe" section. Defining the how web browser should configure
their autofilling features.
<div class="monkey-patch">
<p><dfn export>Autofill and anonymous iframe</dfn>: User agents sometimes have features for helping users
fill forms in: for example prefilling the user's address, password, or payment informations. User
agents must disable those features when the data is both specific to the user and to the website.
</p>
</div>
### Environment's partition nonce ### {#spec-environment-partition-nonce}
In the "Anonymous iframe" section. Defining the [=page anonymous nonce=].
<div class="monkey-patch">
<p>Each top-level {{Window}} has an associated <dfn export>page anonymous nonce</dfn>. It
is an immutable nonce ("number used once").</p>
</div>
Add the <a for="environment">partition nonce</a> attribute to the
<a>environment</a> object.
<div class="monkey-patch">
<dl>
<dt>A <dfn export for="environment">partition nonce</dfn></dt>
<dd><p>An identifier or null. This is used to discriminate and isolate
environments further. Among others, it is non null for <a>anonymous
Window</a></p></dd>
</dl>
</div>
#### For Navigation #### {#spec-navigation-partition-nonce}
In the <a>process a navigate fetch</a>, add step:
<div class="monkey-patch">
13. If |anonymous| is true, let |partitionNonce| be
|browsingContext|'s <a>top-level browsing context</a>'s <a>page
anonymous nonce</a>, null otherwise.
</div>
|partitionNonce| is used later to create the [=Environment=]. Modify step
13.3.4:
<div class="monkey-patch">
13.3.4. Set <var ignore>request</var>'s <a
lt="concept-request-reserved-client">reserved client</a> to a new
<a>environment</a> whose <a lt="concept-environment-id">id</a> is a unique
opaque string, <a lt="concept-environment-target-browsing-context">target
browsing context</a> is |browsingContext|, <a
lt="concept-environment-creation-url">creation URL</a> is <var
ignore>currentURL</var>, <a>top-level creation URL</a> is
|topLevelCreationURL|, <a>top-level origin</a> is
|topLevelOrigin|, <span class="customHighlight">and <a
for="environment">partition nonce</a> is |partitionNonce|</div>.
</div>
#### For Window #### {#spec-window-partition-nonce}
In the <a>initialize the document object</a>, add step 6.9:
<div class="monkey-patch">
6.9. If |navigationParams|'s <a
lt="navigation-params-anonymous">anonymous</a> is true, let
|partitionNonce| be |browsingContext|'s <a>top-level browsing
context</a>'s <a>page anonymous nonce</a>, null otherwise.
</div>
Then, plumb it to create the [=Environment=] in step 6.10:
<div class="monkey-patch">
6.10 <a>Set up a window environment settings object</a> with |creationURL|,
<var ignore>realm execution context</var>, |navigationParams|'s <a
lt="navigation-params-reserved-environment">reserved environment</a>,
|topLevelCreationURL|, |topLevelOrigin|, <span class="customHighlight">and
|partitionNonce|.</span>
</div>
|partitionNonce| is passed to the <a>set up a window environment settings
object</a> this way:
<div class="monkey-patch">
To <a>set up a window environment settings object</a>, given a <a>URL</a>
|creationURL|, a <a>JavaScript execution context</a> <var ignore>execution
context</var>, null or an <a>environment</a> <var
ignore>reservedEnvironment</var>, a <a>URL</a> |topLevelCreationURL|, an
<a>origin</a> |topLevelOrigin|, and <span class="customHighlight">an identifier
|partitionNonce|</span> run these steps:</p>
</div>
It is used in step 6.
<div class="monkey-patch">
6. Set |settings object|'s <a lt="concept-environment-creation-url">creation
URL</a> to |creationURL|, |settings object|'s <a>top-level creation URL</a> to
|topLevelCreationURL|, |settings object|'s <a>top-level origin</a> to
|topLevelOrigin|, <span class="customHighlight">and |settings object|'s <a
for="environment">partition nonce</a> to |partitionNonce|.</span>
</div>
#### For Worker #### {#spec-worker-partition-nonce}
In the <a>script settings for workers</a> algorithm, add step 8:
<div class="monkey-patch">
8. Set |settings object|'s <a for="environment">partition nonce</a> to <var
ignore>outside settings</var>'s <a for="environment">partition nonce</a>.
</div>
#### For Worklet #### {#spec-worklet-partition-nonce}
In the <a>set up a worklet environment settings object</a> algorithm, modify
step 7:
<div class="monkey-patch">
7. Set <var ignore>settingsObject</var>'s <a lt="concept-environment-id">id</a> to a new
unique opaque string, <a lt="concept-environment-creation-url">creation URL</a> to
<var ignore>inheritedAPIBaseURL</var>, <a>top-level creation URL</a> to null, <a>top-level
origin</a> to <var ignore>outsideSettings</var>'s <a>top-level origin</a>,
<span class="customHighlight"><a for="environment">partition nonce</a> to
<var ignore>outsideSettings</var>'s <a for="environment">partition
nonce</a></span>, <a for="environment">target browsing context</a> to null,
and <a lt="concept-environment-active-service-worker">active service
worker</a> to null.
</div>
Integration with Fetch {#spec-fetch}
----------------------
Note: This corresponds to the following HTML specification change:
[whatwg/fetch/pull/1416](https://github.com/whatwg/fetch/pull/1416). <br/>
When merged this section will become obsolete.
### Plumb the partition-nonce ### {#spec-network-partition-key}
Add the `environment`'s `partition nonce` into the network partition key.
Proceed the following changes:
<div class="monkey-patch">
A <a>network partition key</a> is a tuple consisting of:
- A <a for=/>site</a>.
- null or an <a>implementation-defined</a> value.
- <span class="customHighlight">null or a nonce.</span>
</div>
<div class="monkey-patch">
<p>To <a lt="determine the network partition key">determine the network
partition key</dfn>, given an <a for=/>environment</a> |environment|,
run these steps:
<ol>
<li><p>Let |topLevelOrigin| be |environment|'s
<a for="environment">top-level origin</a>.
<li><p>If |topLevelOrigin| is null, then set |topLevelOrigin| to
|environment|'s <a for="environment">top-level creation URL</a>'s <a for=url>origin</a>.
<li><p>Assert: |topLevelOrigin| is an <a for=/>origin</a>.
<li><p>Let |topLevelSite| be the result of <a lt="obtain a site">obtaining a site</a>,
given |topLevelOrigin|.
<li><p>Let |secondKey| be null or an <a>implementation-defined</a> value.
<p class=XXX>The second key is intentionally a little vague as the finer points are still
evolving. See <a href=https://github.com/whatwg/fetch/issues/1035>issue #1035</a>.
<li><p class="customHighlight">Let |nonce| be
|environment|'s <a for="environment">partition nonce</a></p>
<li><p>Return (|topLevelSite|, |secondKey|, <var
class="customHighlight">nonce</var>).
</ol>
</div>
Integration with CHIPS {#spec-chips}
----------------------
This section defines a monkey-patch over: [[!CHIPS]], which is itself a
monkey-patch over [[!COOKIES]].
<div class="note">
Note / Summary: [Cookies Having Independent Partitioned
State](https://github.com/WICG/CHIPS) (CHIPS) introduce the cookie's partition
key. To implement anonymous iframe, when the [=environment=]'s
[=environment/partition nonce=] is defined:
1. Even in the absence of the "Partitioned" cookie attribute, the
"partition-key" is defined and contains: (top-level-site, partition-nonce).
2. The __Host- prefix is not required.
3. The [=environment=] only have access to cookies whose "partition-key" is
defined.
</div>
Modify the [[!CHIPS]] section:
<a href="https://github.com/WICG/CHIPS/blob/main/README.md#algorithm">https://github.com/WICG/CHIPS/blob/main/README.md#algorithm</a>
<div class="monkey-patch">