Skip to content

Commit 3fbaa9e

Browse files
mikewestdomenic
andauthored
Define the [CrossOriginIsolated] extended attribute
Web IDL currently defines a [SecureContext] extended attribute that governs whether or not a given construct is exposed within a given context. This patch defines a similar [CrossOriginIsolated] attribute to govern exposure based on cross-origin isolation. This supports the broader Securer Contexts proposal (https://github.com/mikewest/securer-contexts), which aims to guide spec authors to combat threats we've started paying more attention to over the last few years. Closes #875. Co-authored-by: Domenic Denicola <[email protected]>
1 parent 5021df4 commit 3fbaa9e

File tree

1 file changed

+161
-72
lines changed

1 file changed

+161
-72
lines changed

index.bs

Lines changed: 161 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -994,15 +994,17 @@ The relevant language binding determines how interfaces correspond to constructs
994994
in the language.
995995

996996
The following extended attributes are applicable to interfaces:
997+
[{{CrossOriginIsolated}}],
997998
[{{Exposed}}],
998999
[{{Global}}],
999-
[{{LegacyWindowAlias}}],
10001000
[{{LegacyFactoryFunction}}],
10011001
[{{LegacyNoInterfaceObject}}],
1002-
[{{LegacyOverrideBuiltIns}}], and
1002+
[{{LegacyOverrideBuiltIns}}],
1003+
[{{LegacyWindowAlias}}], and
10031004
[{{SecureContext}}].
10041005

10051006
The following extended attributes are applicable to [=partial interfaces=]:
1007+
[{{CrossOriginIsolated}}],
10061008
[{{Exposed}}],
10071009
[{{LegacyOverrideBuiltIns}}], and
10081010
[{{SecureContext}}].
@@ -1245,7 +1247,7 @@ in the <a href="#es-namespaces">ECMAScript binding</a>.
12451247
Note that unlike [=interfaces=] or [=dictionaries=], [=interface mixins=] do not create types.
12461248

12471249
Of the extended attributes defined in this specification,
1248-
only the [{{Exposed}}] and [{{SecureContext}}] extended attributes
1250+
only the [{{CrossOriginIsolated}}], [{{Exposed}}], and [{{SecureContext}}] extended attributes
12491251
are applicable to [=interface mixins=].
12501252

12511253
An <dfn>includes statement</dfn> is a definition
@@ -1770,7 +1772,8 @@ on which they appear. It is language binding specific whether
17701772
</div>
17711773

17721774
The following extended attributes are applicable to constants:
1773-
[{{Exposed}}],
1775+
[{{CrossOriginIsolated}}],
1776+
[{{Exposed}}], and
17741777
[{{SecureContext}}].
17751778

17761779
<pre class="grammar" id="prod-Const">
@@ -1951,8 +1954,9 @@ interface will be stringified to the value of the attribute. See
19511954

19521955
The following [=extended attributes=]
19531956
are applicable to regular and static attributes:
1957+
[{{CrossOriginIsolated}}],
19541958
[{{Exposed}}],
1955-
[{{SameObject}}],
1959+
[{{SameObject}}], and
19561960
[{{SecureContext}}].
19571961

19581962
The following [=extended attributes=]
@@ -2403,11 +2407,12 @@ type=] that has a [=dictionary type=] in its [=flattened member types=].
24032407
</div>
24042408

24052409
The following extended attributes are applicable to operations:
2410+
[{{CrossOriginIsolated}}],
24062411
[{{Default}}],
24072412
[{{Exposed}}],
2408-
[{{NewObject}}],
2409-
[{{SecureContext}}],
2410-
[{{LegacyUnforgeable}}].
2413+
[{{LegacyUnforgeable}}],
2414+
[{{NewObject}}], and
2415+
[{{SecureContext}}].
24112416

24122417
The <dfn>method steps</dfn> of an operation |operation| should be introduced using text of the form
24132418
“The <code>|operation|(<var ignore>arg1</var>, <var ignore>arg2</var>, ...)</code> method
@@ -4266,7 +4271,8 @@ must not have a
42664271
[=asynchronously iterable declaration=].
42674272

42684273
The following extended attributes are applicable to [=iterable declarations=]:
4269-
[{{Exposed}}],
4274+
[{{CrossOriginIsolated}}],
4275+
[{{Exposed}}], and
42704276
[{{SecureContext}}].
42714277

42724278
<pre class="grammar" id="prod-Iterable">
@@ -4456,7 +4462,8 @@ An [=interface=] with an [=asynchronously iterable declaration=] and its [=inher
44564462
must not have a [=maplike declaration=], [=setlike declaration=], or [=iterable declaration=].
44574463

44584464
The following extended attributes are applicable to [=asynchronously iterable declarations=]:
4459-
[{{Exposed}}],
4465+
[{{CrossOriginIsolated}}],
4466+
[{{Exposed}}], and
44604467
[{{SecureContext}}].
44614468

44624469
Issue: these [=extended attributes=] are not currently taken into account.
@@ -4707,7 +4714,7 @@ The order that members appear in has significance for property enumeration in th
47074714

47084715
Note that unlike interfaces or dictionaries, namespaces do not create types.
47094716

4710-
Of the extended attributes defined in this specification, only the [{{Exposed}}] and [{{SecureContext}}] extended attributes are applicable to namespaces.
4717+
Of the extended attributes defined in this specification, only the [{{CrossOriginIsolated}}], [{{Exposed}}], and [{{SecureContext}}] extended attributes are applicable to namespaces.
47114718

47124719
[=Namespaces=] must be annotated with the [{{Exposed}}] [=extended attribute=].
47134720

@@ -9094,6 +9101,91 @@ for the specific requirements that the use of
90949101
</div>
90959102

90969103

9104+
<h4 id="CrossOriginIsolated" extended-attribute lt="CrossOriginIsolated">[CrossOriginIsolated]</h4>
9105+
9106+
If the [{{CrossOriginIsolated}}] [=extended attribute=] appears on an
9107+
[=interface=],
9108+
[=partial interface=],
9109+
[=interface mixin=],
9110+
[=partial interface mixin=],
9111+
[=callback interface=],
9112+
[=namespace=],
9113+
[=partial namespace=],
9114+
[=interface member=],
9115+
[=interface mixin member=], or
9116+
[=namespace member=],
9117+
it indicates that the construct is [=exposed=] only within an environment whose
9118+
[=environment settings object/cross-origin isolated capability=] is true. The
9119+
[{{CrossOriginIsolated}}] extended attribute must not be used on any other construct.
9120+
9121+
The [{{CrossOriginIsolated}}] extended attribute must [=takes no arguments|take no arguments=].
9122+
9123+
If [{{CrossOriginIsolated}}] appears on an [=overloaded=] [=operation=],
9124+
then it must appear on all overloads.
9125+
9126+
The [{{CrossOriginIsolated}}] [=extended attribute=] must not be specified both on
9127+
9128+
* an [=interface member=] and its [=interface=] or [=partial interface=];
9129+
* an [=interface mixin member=] and its [=interface mixin=] or [=partial interface mixin=];
9130+
* a [=namespace member=] and its [=namespace=] or [=partial namespace=].
9131+
9132+
Note: This is because adding the [{{CrossOriginIsolated}}] [=extended attribute=] on a [=member=]
9133+
when its containing definition is also annotated with the [{{CrossOriginIsolated}}]
9134+
[=extended attribute=] does not further restrict the exposure of the [=member=].
9135+
9136+
An [=interface=] without the [{{CrossOriginIsolated}}] [=extended attribute=]
9137+
must not [=interface/inherit=] from another interface
9138+
that does specify [{{CrossOriginIsolated}}].
9139+
9140+
<div class="example">
9141+
9142+
The following [=IDL fragment=] defines an interface with one [=operation=] that is executable
9143+
from all contexts, and two which are executable only from cross-origin isolated contexts.
9144+
9145+
<pre highlight="webidl">
9146+
[Exposed=Window]
9147+
interface ExampleFeature {
9148+
// This call will succeed in all contexts.
9149+
Promise &lt;Result&gt; calculateNotSoSecretResult();
9150+
9151+
// This operation will not be exposed to a non-isolated context. In such a context,
9152+
// there will be no "calculateSecretResult" property on ExampleFeature.prototype.
9153+
[CrossOriginIsolated] Promise&lt;Result&gt; calculateSecretResult();
9154+
9155+
// The same applies here: the attribute will not be exposed to a non-isolated context,
9156+
// and in such a context there will be no "secretBoolean" property on
9157+
// ExampleFeature.prototype.
9158+
[CrossOriginIsolated] readonly attribute boolean secretBoolean;
9159+
};
9160+
9161+
// HighResolutionTimer will not be exposed in a non-isolated context, nor will its members.
9162+
// In such a context, there will be no "HighResolutionTimer" property on Window.
9163+
[Exposed=Window, CrossOriginIsolated]
9164+
interface HighResolutionTimer {
9165+
DOMHighResTimeStamp getHighResolutionTime();
9166+
};
9167+
9168+
// The interface mixin members defined below will never be exposed in a non-isolated
9169+
// context, regardless of whether the interface that includes them is. That is, in
9170+
// non-isolated context, there will be no "snap" property on ExampleFeature.prototype.
9171+
[CrossOriginIsolated]
9172+
interface mixin Snapshotable {
9173+
Promise&lt;boolean&gt; snap();
9174+
};
9175+
ExampleFeature includes Snapshotable;
9176+
9177+
// On the other hand, the following interface mixin members will be exposed to a
9178+
// non-isolated context when included by a host interface that doesn't have the
9179+
// [CrossOriginIsolated] extended attribute. That is, in a non-isolated context, there will
9180+
// be a "log" property on ExampleFeature.prototype.
9181+
interface mixin Loggable {
9182+
Promise&lt;boolean&gt; log();
9183+
};
9184+
ExampleFeature includes Loggable;
9185+
</pre>
9186+
</div>
9187+
9188+
90979189
<h4 id="Default" extended-attribute lt="Default">[Default]</h4>
90989190

90999191
If the [{{Default}}] [=extended attribute=] appears on a [=regular operation=], then it indicates
@@ -9336,20 +9428,53 @@ Otherwise, it is the [=host interface=]'s [=exposure set=].
93369428

93379429
1. If |realm|.\[[GlobalObject]] does not implement an [=interface=]
93389430
that is in |construct|'s [=exposure set=], then return false.
9339-
1. If |construct| is [=available in both secure and non-secure contexts=],
9340-
then return true.
9341-
1. If the [=relevant settings object=] of |realm|.\[[GlobalObject]] is a [=secure context=],
9431+
1. If |realm|'s [=Realm/settings object=] is not a [=secure context=], and |construct| is
9432+
[=conditionally exposed=] on [{{SecureContext}}], then return false.
9433+
1. If |realm|'s [=Realm/settings object=]'s
9434+
[=environment settings object/cross-origin isolated capability=] is false, and |construct|
9435+
is [=conditionally exposed=] on [{{CrossOriginIsolated}}], then return false.
9436+
1. Return true.
9437+
</div>
9438+
9439+
<div algorithm>
9440+
An [=interface=], [=callback interface=], [=namespace=], or [=member=] |construct| is
9441+
<dfn id="dfn-conditionally-exposed" export>conditionally exposed</dfn> on a given
9442+
[=extended attribute=] |exposure condition| if the following steps return true:
9443+
9444+
1. Assert: |construct| is an [=interface=], [=callback interface=], [=namespace=],
9445+
[=interface member=], [=interface mixin member=], or [=namespace member=].
9446+
1. Let |H| be |construct|'s [=host interface=] if |construct| is an [=interface mixin member=],
9447+
or null otherwise.
9448+
1. If |construct| is an [=interface member=], [=interface mixin member=], or
9449+
[=namespace member=], then:
9450+
1. If the |exposure condition| [=extended attribute=] is specified on |construct|,
9451+
then return true.
9452+
1. Otherwise, set |construct| to be the
9453+
[=interface=], [=partial interface=],
9454+
[=interface mixin=], [=partial interface mixin=],
9455+
[=namespace=], or [=partial namespace=]
9456+
|construct| is declared on.
9457+
1. If |construct| is a [=partial interface=], [=partial interface mixin=], or
9458+
[=partial namespace=], then:
9459+
1. If the |exposure condition| [=extended attribute=] is specified on |construct|,
9460+
then return true.
9461+
1. Otherwise, set |construct| to be the original [=interface=], [=interface mixin=], or
9462+
[=namespace=] definition of |construct|.
9463+
1. If |construct| is an [=interface mixin=], then:
9464+
1. If the |exposure condition| [=extended attribute=] is specified on |construct|,
9465+
then return true.
9466+
1. Otherwise, set |construct| to |H|.
9467+
1. Assert: |construct| is an [=interface=], [=callback interface=] or [=namespace=].
9468+
1. If the |exposure condition| [=extended attribute=] is specified on |construct|,
93429469
then return true.
93439470
1. Otherwise, return false.
93449471
</div>
93459472

93469473
Note: Since it is not possible for the [=relevant settings object=]
93479474
for an ECMAScript global object to change whether it is a
9348-
[=secure context=] or not over time, an implementation's
9349-
decision to create properties for an interface or interface member
9350-
can be made once, at the time the
9351-
[=initial objects=]
9352-
are created.
9475+
[=secure context=] or [=environment settings object/cross-origin isolated capability=] over time, an
9476+
implementation's decision to create properties for an interface or interface member can be made
9477+
once, at the time the [=initial objects=] are created.
93539478

93549479
See
93559480
[[#es-interfaces]],
@@ -9888,45 +10013,6 @@ on any other construct.
988810013

988910014
The [{{SecureContext}}] extended attribute must [=takes no arguments|take no arguments=].
989010015

9891-
A construct is <dfn export>available in both secure and non-secure contexts</dfn> if it is not
9892-
[=available only in secure contexts=] (i.e., if no [{{SecureContext}}] extended attribute applies
9893-
to it).
9894-
9895-
<div algorithm>
9896-
9897-
To check if a construct |C| is
9898-
<dfn id="dfn-available-only-in-secure-contexts" export>available only in secure contexts</dfn>,
9899-
run the following steps:
9900-
9901-
1. Assert: |C| is an [=interface=], [=callback interface=], [=namespace=],
9902-
[=interface member=], [=interface mixin member=], or [=namespace member=].
9903-
1. Let |H| be |C|'s [=host interface=] if |C| is an [=interface mixin member=], or null otherwise.
9904-
1. If |C| is an [=interface member=], [=interface mixin member=], or [=namespace member=], then:
9905-
1. If the [{{SecureContext}}] [=extended attribute=] is specified on |C|,
9906-
then return true.
9907-
1. Otherwise, set |C| to be the
9908-
[=interface=], [=partial interface=],
9909-
[=interface mixin=], [=partial interface mixin=],
9910-
[=namespace=], or [=partial namespace=]
9911-
|C| is declared on.
9912-
1. If |C| is a [=partial interface=], [=partial interface mixin=], or [=partial namespace=], then:
9913-
1. If the [{{SecureContext}}] [=extended attribute=] is specified on |C|,
9914-
then return true.
9915-
1. Otherwise, set |C| to be the original [=interface=], [=interface mixin=], or [=namespace=]
9916-
definition of |C|.
9917-
1. If |C| is an [=interface mixin=], then:
9918-
1. If the [{{SecureContext}}] [=extended attribute=] is specified on |C|,
9919-
then return true.
9920-
1. Otherwise, set |C| to |H|.
9921-
1. Assert: |C| is an [=interface=], [=callback interface=] or [=namespace=].
9922-
1. If the [{{SecureContext}}] [=extended attribute=] is specified on |C|,
9923-
then return true.
9924-
1. Otherwise, return false.
9925-
</div>
9926-
9927-
Note: Whether a construct is [=available only in secure contexts=]
9928-
influences whether it is [=exposed=] in a given [=Realm=].
9929-
993010016
If [{{SecureContext}}] appears on an [=overloaded=] [=operation=],
993110017
then it must appear on all overloads.
993210018

@@ -9944,6 +10030,11 @@ An [=interface=] without the [{{SecureContext}}] [=extended attribute=]
994410030
must not [=interface/inherit=] from another interface
994510031
that does specify [{{SecureContext}}].
994610032

10033+
[{{SecureContext}}] must not be specified on a construct is that is [=conditionally exposed=] on
10034+
[{{CrossOriginIsolated}}]. (Doing so would be redundant, since every environment which is
10035+
[=environment settings object/cross-origin isolated capability|cross-origin isolated=] is also a
10036+
[=secure context=].)
10037+
994710038
<div class="example">
994810039

994910040
The following [=IDL fragment=] defines an interface
@@ -9952,46 +10043,44 @@ that does specify [{{SecureContext}}].
995210043

995310044
<pre highlight="webidl">
995410045
[Exposed=Window]
9955-
interface PowerfulFeature {
10046+
interface ExampleFeature {
995610047
// This call will succeed in all contexts.
995710048
Promise &lt;Result&gt; calculateNotSoSecretResult();
995810049

995910050
// This operation will not be exposed to a non-secure context. In such a context,
9960-
// there will be no "calculateSecretResult" property on PowerfulFeature.prototype.
10051+
// there will be no "calculateSecretResult" property on ExampleFeature.prototype.
996110052
[SecureContext] Promise&lt;Result&gt; calculateSecretResult();
996210053

996310054
// The same applies here: the attribute will not be exposed to a non-secure context,
996410055
// and in a non-secure context there will be no "secretBoolean" property on
9965-
// PowerfulFeature.prototype.
10056+
// ExampleFeature.prototype.
996610057
[SecureContext] readonly attribute boolean secretBoolean;
996710058
};
996810059

996910060
// HeartbeatSensor will not be exposed in a non-secure context, nor will its members.
997010061
// In such a context, there will be no "HeartbeatSensor" property on Window.
9971-
[SecureContext]
10062+
[Exposed=Window, SecureContext]
997210063
interface HeartbeatSensor {
997310064
Promise&lt;float&gt; getHeartbeatsPerMinute();
997410065
};
997510066

997610067
// The interface mixin members defined below will never be exposed in a non-secure context,
9977-
// regardless of whether the interface that includes them is.
9978-
// In a non-secure context, there will be no "snap" property on
9979-
// PowerfulFeature.prototype.
10068+
// regardless of whether the interface that includes them is. That is, in a non-secure
10069+
// context, there will be no "snap" property on ExampleFeature.prototype.
998010070
[SecureContext]
998110071
interface mixin Snapshotable {
998210072
Promise&lt;boolean&gt; snap();
998310073
};
9984-
PowerfulFeature includes Snapshotable;
10074+
ExampleFeature includes Snapshotable;
998510075

9986-
// On the other hand, the following interface mixin members will be exposed
9987-
// to a non-secure context when included by a host interface
9988-
// that doesn't have the [SecureContext] extended attribute.
9989-
// In a non-secure context, there will be a "log" property on
9990-
// PowerfulFeatures.prototype.
10076+
// On the other hand, the following interface mixin members will be exposed to a non-secure
10077+
// context when included by a host interface that doesn't have the [SecureContext] extended
10078+
// attribute. That is, in a non-secure context, there will be a "log" property on
10079+
// ExampleFeature.prototype.
999110080
interface mixin Loggable {
999210081
Promise&lt;boolean&gt; log();
999310082
};
9994-
PowerfulFeatures includes Loggable;
10083+
ExampleFeature includes Loggable;
999510084
</pre>
999610085
</div>
999710086

0 commit comments

Comments
 (0)