Skip to content

Commit 5b4a8fd

Browse files
authored
Update explainer.md
1 parent abc4a3a commit 5b4a8fd

File tree

1 file changed

+50
-89
lines changed

1 file changed

+50
-89
lines changed

explainer.md

Lines changed: 50 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -32,30 +32,37 @@ to start small until we know how existing templating systems and sanitizers will
3232
primitives we introduce into their existing systems. The following approach seems compelling as a
3333
first step:
3434

35-
1. Introduce a number of types that correspond to the XSS sinks we wish to protect. For example,
35+
1. Introduce a number of types that correspond to the sinks we wish to protect. For example,
36+
to cover DOM XSS vulnerabilities
3637
we could define a `TrustedHTML` object that marks it as suitable for using via `innerHTML`
3738
(instead of a string). Or a `TrustedScriptURL` object that's suitable to be assigned to a
3839
`ScriptElement.src` attribute.
3940

4041
These types should be pretty minimal in nature, making them polyfillable in browsers that don't
4142
support them natively.
4243

43-
2. Enumerate all the XSS sinks we wish to protect, and overload each of them with a variant that
44-
accepts the matching type. For example, `Element.innerHTML`'s setter could accept `(DOMString or TrustedHTML)`,
44+
2. Enumerate all the sinks we wish to protect, and overload each of them with a variant that
45+
accepts the matching type. For example, `Element.innerHTML`'s setter could accept `TrustedHTML`,
4546
and we could overload `document.write(DOMString)` with `document.write(TrustedHTML)`.
4647

4748
As above, this mechanism should be polyfillable; the polyfilled types define stringifiers which
4849
would enable them to be automatically cast into strings when called on existing setters.
4950

5051
3. Introduce a mechanism for disabling the raw string version of each of the sinks identified
51-
above. For example, `Content-Security-Policy: trusted-types`
52-
header could cause the `innerHTML` setter to throw a `TypeError` if a raw string was passed in.
52+
above. For example, to signify that the application opts into DOM XSS sink protection
53+
`Content-Security-Policy: require-trusted-types-for 'script'`
54+
header could be used: This causes the `innerHTML` setter to throw a `TypeError` if a raw string was passed in.
5355

5456
This is possible to polyfill for many setters and
55-
methods, apart from the ones that aren't marked as [`[Unforgeable]`](https://heycam.github.io/webidl/#Unforgeable).
57+
methods, apart from the ones that are marked as [`[Unforgeable]`](https://heycam.github.io/webidl/#Unforgeable).
58+
59+
This approach could later be extended to cover other types of risky and easy to misuse APIs (e.g. to cover
60+
CSS-based data exfiltration attacks).
5661

5762
### Trusted Types
5863

64+
We identified three types that match the different contexts relevant for DOM XSS:
65+
5966
* **TrustedHTML**: This type would be used to represent a trusted snippet that could be passed
6067
into an HTML context.
6168

@@ -65,15 +72,6 @@ first step:
6572
}
6673
```
6774
68-
* **TrustedURL**: This type would be used to represent a trusted URL that could be used to load
69-
non-scripting resources or navigate a frame.
70-
71-
```webidl
72-
interface TrustedURL {
73-
stringifier;
74-
}
75-
```
76-
7775
* **TrustedScriptURL**: This type would be used to represent a URL that could be used to load
7876
resources that may result in script execution in the current document.
7977
@@ -135,7 +133,6 @@ As valid trusted type objects must originate from a policy, those policies alone
135133
```webidl
136134
interface TrustedTypePolicyFactory {
137135
TrustedTypePolicy createPolicy(DOMString policyName, TrustedTypeInnerPolicy policy);
138-
Array<DOMString> getPolicyNames();
139136
}
140137
```
141138
We propose to provide a `TrustedTypePolicyFactory` implementation under `window.trustedTypes`. The most important function available in a `TrustedTypePolicyFactory` is `createPolicy`.
@@ -145,21 +142,18 @@ The policy rules for creating individual types are configured via the properties
145142
```webidl
146143
interface TrustedTypeInnerPolicy {
147144
string createHTML(string);
148-
string createURL(string);
149145
string createScriptURL(string);
150146
string createScript(string);
151147
}
152148
```
153-
154149
Policy (with a unique name) can be created like this:
155150

156151
```javascript
157-
const myPolicy = trustedTypes.createPolicy('https://example.com#mypolicy', {
152+
const myPolicy = trustedTypes.createPolicy('mypolicy', {
158153
createHTML: (s) => { return customSanitize(s) },
159-
createURL: (s) => { /* parse and validate the url. throw if non-conformant */ },
154+
createScriptURL: (s) => { /* parse and validate the url. throw if non-conformant */ },
160155
})
161156
```
162-
163157
The policy object is returned, and can be used as a capability to create typed objects i.e. code parts without a reference to the policy object cannot use it.
164158

165159
The policy object can be used directly to create typed values that conform to its rules:
@@ -175,22 +169,49 @@ the polyfill code.
175169

176170
#### Limiting policies
177171

178-
We propose to allow for whitelisting policy names in a CSP, e.g. in a following fashion:
172+
Applications may want to further limit how policies are created; We propose to allow for
173+
allow-listing policy names in a CSP, e.g. in a following fashion:
179174
```http
180175
Content-Security-Policy: trusted-types foo bar
181176
```
182177

183178
That will assure that no additional policies are created at runtime. Creating a policy with a name
184179
that was already created, or was not specified in the CSP throws, so introduction of non-reviewed
185-
policies breaks the application functionally.
180+
policies breaks the application functionally. There's also an espace hatch - `'allow-duplicate'`
181+
CSP keyword that allows the applications to create a given policy multiple times (that's useful
182+
if a dependency is used twice in an application).
186183

187184
#### Default policy
188185

189-
There is an experimental support for a default policy that allows applications
190-
to use strings with the injection sinks. These strings would be passed to a single
191-
user-defined policy that sanitizes the value or rejects it. The intention is to
192-
allow for a gradual migration of the code from strings towards Trusted Types.
193-
Please check the [specification draft](https://w3c.github.io/trusted-types/dist/spec/#default-policy-hdr) for details.
186+
One of the policies the application may create is special, in that it allows to use strings with the injection sinks.
187+
These strings would be passed to a single user-defined policy that sanitizes the value or rejects it.
188+
The intention is to allow for a gradual migration of the code from strings towards Trusted Types.
189+
Please check the [specification draft](https://w3c.github.io/webappsec-trusted-types/dist/spec/#default-policy-hdr) for details.
190+
191+
192+
#### javascript: URLs
193+
194+
Using `javascript:` URLs as a payload for DOM XSS exploitation is quite common. At the same time,
195+
there are many sinks in the platform that accept URLs, and it would be prohibitive for the authors to have to r
196+
rewrite all of their `HTMLAnchorElement.href` assignments only because a `javascript:` URL could be used.
197+
198+
Instead of that we propose a simple workaround - with Trusted Types enforcement (`require-trusted-types-for 'script'`)
199+
navigation to `javascript:` URLs will be guarded via a default policy mechanism. Commonly, they will simply stop working.
200+
To reenable them, the application needs to create a default policy that allows it to control the code before it
201+
executes like so:
202+
203+
```javascript
204+
trustedTypes.createPolicy('default', {
205+
createScript: payload => {
206+
if (payload === 'void(0)') { // javascript:void(0) navigation or, e.g. eval('void(0)')
207+
return 'void(0)';
208+
} // returning undefined rejects a value and stops navigation.
209+
}
210+
});
211+
```
212+
213+
This mechanism compliments CSP's `'unsafe-inline'`, allowing the authors to enable strong security
214+
controls in their application even if it occasionally uses `javascript:` URLs for legitimate purposes.
194215

195216
### DOM Sinks
196217

@@ -229,63 +250,7 @@ Please check the [specification draft](https://w3c.github.io/trusted-types/dist/
229250
DOMString srcdoc;
230251
};
231252
```
232-
233-
* **URL Contexts**: Given something like `typedef (USVString or TrustedURL) URLString`, we'd poke
234-
at a number of methods and attribute setters to accept the new type:
235-
236-
```webidl
237-
partial interface Location {
238-
stringifier attribute URLString href;
239-
void assign(URLString url);
240-
void replace(URLString url);
241-
242-
// (These aren't `URLString`, but they should be something)
243-
DOMString pathname;
244-
DOMString search;
245-
};
246-
```
247-
248-
```webidl
249-
// A few element types go here. `HTMLBaseElement`, `HTMLLinkElement`
250-
// `HTMLHyperlinkElementUtils` from a quick skim through HTML.
251-
partial interface HTMLXXXElement : HTMLElement {
252-
attribute URLString href;
253-
};
254-
```
255-
256-
```webidl
257-
// A few element types go here. `HTMLSourceElement`, `HTMLImageElement`,
258-
// `HTMLIFrameElement`, `HTMLTrackElement`, `HTMLMediaElement`,
259-
// `HTMLInputElement`, `HTMLFrameElement`
260-
// from a quick skim through HTML.
261-
//
262-
// The same applies to their SVG variants.
263-
partial interface HTMLXXXElement : HTMLElement {
264-
attribute URLString src;
265-
attribute URLString srcset; // Only `HTMLSourceElement` and `HTMLImageElement`
266-
};
267-
```
268-
269-
```webidl
270-
partial interface HTMLObjectElement : HTMLElement {
271-
attribute URLString data;
272-
attribute URLString codebase;
273-
};
274-
```
275-
276-
```webidl
277-
partial interface Document {
278-
attribute URLString location;
279-
};
280-
```
281-
282-
```webidl
283-
partial interface Window {
284-
attribute URLString location;
285-
void open(URLString location);
286-
};
287-
```
288-
253+
289254
* **Script URL Context**: Given something like `typedef (USVString or TrustedScriptURL) ScriptURLString`,
290255
we'd poke at a number of methods and attribute setters to accept the new type:
291256
@@ -323,7 +288,3 @@ Please check the [specification draft](https://w3c.github.io/trusted-types/dist/
323288
attribute DOMString textContent;
324289
};
325290
```
326-
327-
## Open Questions
328-
329-
Some details have still not been sketched out - see [issues](https://github.com/w3c/webappsec-trusted-types/issues).

0 commit comments

Comments
 (0)