Skip to content

Commit 8b449a5

Browse files
hamishwilleewbamberggithub-actions[bot]
authored
SanitizerConfig - define valid config (#41945)
* SanitizerConfig - define valid config * Fix up valid list * Sanitizer() - fix up the param to point to valid configuration * Update Sanitizer methods - return bool * Extend examples as directed and tidy up valid config * Update files/en-us/web/api/html_sanitizer_api/using_the_html_sanitizer_api/index.md * Update index.md * Apply suggestions from code review - easy ones Co-authored-by: wbamberg <[email protected]> * Fix allow configuration issues in overview * Define santizer before explaining how to use it * clarify the fail case in description for allowElement * Update files/en-us/web/api/sanitizer/allowelement/index.md * Fix typo in config for dataAttributes * Update files/en-us/web/api/sanitizer/setdataattributes/index.md * Apply suggestions from code review Co-authored-by: wbamberg <[email protected]> * Apply suggestions from code review Co-authored-by: wbamberg <[email protected]> * Add section - Adding and removing from Sanitizer configurations * Sanitizer method notes about behaviour on allow/remove * Update files/en-us/web/api/sanitizer/setdataattributes/index.md * reviewdog fixes Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Apply suggestions from code review --------- Co-authored-by: wbamberg <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent bb435e7 commit 8b449a5

File tree

18 files changed

+389
-123
lines changed

18 files changed

+389
-123
lines changed

files/en-us/web/api/document/parsehtml_static/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ A {{domxref("Document")}}.
3838

3939
- `TypeError`
4040
- : This is thrown if `options.sanitizer` is passed a:
41-
- non-normalized {{domxref("SanitizerConfig")}} (one that includes both "allowed" and "removed" configuration settings).
41+
- {{domxref("SanitizerConfig")}} that isn't [valid](/en-US/docs/Web/API/SanitizerConfig#valid_configuration).
42+
For example, a configuration that includes both "allowed" and "removed" configuration settings.
4243
- string that does not have the value `"default"`.
4344
- value that is not a {{domxref("Sanitizer")}}, {{domxref("SanitizerConfig")}}, or string.
4445

files/en-us/web/api/document/parsehtmlunsafe_static/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,10 @@ A {{domxref("Document")}}.
5050
- : This is thrown if:
5151
- `html` is passed a string when [Trusted Types](/en-US/docs/Web/API/Trusted_Types_API) are [enforced by a CSP](/en-US/docs/Web/API/Trusted_Types_API#using_a_csp_to_enforce_trusted_types) and no default policy is defined.
5252
- `options.sanitizer` is passed a:
53-
- value that is not a {{domxref("Sanitizer")}}, {{domxref("SanitizerConfig")}}, or string.
54-
- non-normalized {{domxref("SanitizerConfig")}} (one that includes both "allowed" and "removed" configuration settings).
53+
- {{domxref("SanitizerConfig")}} that isn't [valid](/en-US/docs/Web/API/SanitizerConfig#valid_configuration).
54+
For example, a configuration that includes both "allowed" and "removed" configuration settings.
5555
- string that does not have the value `"default"`.
56+
- value that is not a {{domxref("Sanitizer")}}, {{domxref("SanitizerConfig")}}, or string.
5657

5758
## Description
5859

files/en-us/web/api/element/sethtml/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ None (`undefined`).
4545

4646
- `TypeError`
4747
- : This is thrown if `options.sanitizer` is passed a:
48-
- non-normalized {{domxref("SanitizerConfig")}} (one that includes both "allowed" and "removed" configuration settings).
48+
- {{domxref("SanitizerConfig")}} that isn't [valid](/en-US/docs/Web/API/SanitizerConfig#valid_configuration).
49+
For example, a configuration that includes both "allowed" and "removed" configuration settings.
4950
- string that does not have the value `"default"`.
5051
- value that is not a {{domxref("Sanitizer")}}, {{domxref("SanitizerConfig")}}, or string.
5152

files/en-us/web/api/element/sethtmlunsafe/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,10 @@ None (`undefined`).
5050
- : This is thrown if:
5151
- `input` is passed a string when [Trusted Types](/en-US/docs/Web/API/Trusted_Types_API) are [enforced by a CSP](/en-US/docs/Web/API/Trusted_Types_API#using_a_csp_to_enforce_trusted_types) and no default policy is defined.
5252
- `options.sanitizer` is passed a:
53-
- value that is not a {{domxref("Sanitizer")}}, {{domxref("SanitizerConfig")}}, or string.
54-
- non-normalized {{domxref("SanitizerConfig")}} (one that includes both "allowed" and "removed" configuration settings).
53+
- {{domxref("SanitizerConfig")}} that isn't [valid](/en-US/docs/Web/API/SanitizerConfig#valid_configuration).
54+
For example, a configuration that includes both "allowed" and "removed" configuration settings.
5555
- string that does not have the value `"default"`.
56+
- value that is not a {{domxref("Sanitizer")}}, {{domxref("SanitizerConfig")}}, or string.
5657

5758
## Description
5859

files/en-us/web/api/html_sanitizer_api/index.md

Lines changed: 112 additions & 26 deletions
Large diffs are not rendered by default.

files/en-us/web/api/html_sanitizer_api/using_the_html_sanitizer_api/index.md

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,31 @@ console.log(someElement.innerHTML); // abc def
2828

2929
The other XSS-safe methods, {{domxref('ShadowRoot.setHTML()')}} and {{domxref('Document/parseHTML_static','Document.parseHTML()')}}, are used in the same way.
3030

31-
### Safe methods further restrict allowed entities
31+
## Using a sanitizer configuration
3232

33-
You can specify the HTML entities that you want to allow or remove by passing a {{domxref('Sanitizer')}} in the second argument of all the sanitizer methods.
33+
All of the sanitization methods can be passed a {{domxref('Sanitizer')}} or {{domxref('SanitizerConfig')}}, which defines what elements, attributes and comments are either allowed, or should be removed, when inserting strings of HTML.
3434

35-
For example, if you know that only {{htmlelement("p")}} and {{htmlelement("a")}} elements are expected in the context of "someElement" below, you might create a sanitizer configuration that allows only those elements:
35+
The {{domxref('Sanitizer')}} is essentially a wrapper around a {{domxref('SanitizerConfig')}}, performing some optimizations and normalizations that make it easier and safer to use, share and modify,
36+
37+
### Using safe methods with a sanitizer
38+
39+
The XSS-safe methods always remove any unsafe HTML elements or attributes (as discussed in [Safe sanitization by default](#safe_sanitization_by_default) above).
40+
41+
You can pass a sanitizer as the second argument to the safe methods to allow the same or fewer entities than the default configuration.
42+
For example, if you know that only {{htmlelement("p")}} and {{htmlelement("a")}} elements are expected in the context of `someElement` below, you might create a sanitizer configuration that allows only those elements:
3643

3744
```js
3845
const sanitizerOne = new Sanitizer({ elements: ["p", "a"] });
3946
sanitizerOne.allowAttribute("href");
4047
someElement.setHTML(untrustedString, { sanitizer: sanitizerOne });
4148
```
4249

43-
Note though that the unsafe HTML entities are always removed when using the safe methods.
44-
When used with the safe methods, a permissive sanitizer configuration, will either allow the same or fewer entities than the default configuration.
50+
### Allowing unsafe sanitization
4551

46-
## Allowing unsafe sanitization
52+
Sometimes you might want to inject input that needs to contain potentially unsafe elements or attributes.
53+
In this case you could use one of the API XSS-unsafe methods: {{domxref('Element.setHTMLUnsafe()')}}, {{domxref('ShadowRoot.setHTMLUnsafe()')}}, and {{domxref('Document/parseHTMLUnsafe_static','Document.parseHTMLUnsafe()')}}.
4754

48-
Sometimes you might want to inject input needs to contain potentially unsafe elements or attributes.
49-
In this case you can use one of the API XSS-unsafe methods: {{domxref('Element.setHTMLUnsafe()')}}, {{domxref('ShadowRoot.setHTMLUnsafe()')}}, and {{domxref('Document/parseHTMLUnsafe_static','Document.parseHTMLUnsafe()')}}.
50-
51-
A common approach is to start from the default sanitizer, which only allows safe elements, and then allow just those unsafe entities that we expect in the input.
55+
To somewhat reduce the risk, you might first construct the default sanitizer, which only allows XSS-safe elements, and then allow just those unsafe entities that are expected in the input.
5256

5357
For example, in the following sanitizer all safe elements are allowed, and we further allow the unsafe `onclick` handler on `button` elements (only).
5458

@@ -64,7 +68,8 @@ someElement.setHTMLUnsafe(untrustedString, { sanitizer: sanitizerOne });
6468
With this code the `alert(1)` would be allowed, and there is a potential issue that the attribute might be used for malicious purposes.
6569
However we know that all other XSS unsafe HTML entities have been removed, so we only need to worry about this one case, and can put in other mitigations.
6670

67-
The unsafe methods will use any sanitizer configuration you supply (or none), so you need to be more careful than when using the safe methods.
71+
The unsafe methods will use any sanitizer configuration you supply (or none), so you need to be careful when using them.
72+
Minimally you should enforce [Trusted Types](/en-US/docs/Web/API/HTML_Sanitizer_API#sanitization_and_trusted_types) and pass {{domxref("TrustedHTML")}} instead of strings into the methods.
6873

6974
## Allow configurations
7075

@@ -111,7 +116,7 @@ const sanitizer = new Sanitizer({
111116
});
112117
```
113118

114-
You can add the elements to the `Sanitizer` using its API.
119+
You can also add the elements to a `Sanitizer` using {{domxref("Sanitizer.allowElement()")}}.
115120
Here we add the same elements to an empty sanitizer:
116121

117122
```js
@@ -152,7 +157,7 @@ const sanitizer = new Sanitizer({
152157
});
153158
```
154159

155-
You can also add each of the allowed attributes to the `Sanitizer` using its `allowAttribute()` method:
160+
You can also add each of the allowed attributes to a `Sanitizer` using the {{domxref("Sanitizer.allowAttribute()")}} method:
156161

157162
```js
158163
const sanitizer = new Sanitizer({});
@@ -192,7 +197,8 @@ const sanitizer = new Sanitizer({
192197
In both cases you can also specify each attribute as an object with `name` and `namespace` properties.
193198
You can also use set the attribute properties using the same element object passed to {{domxref("Sanitizer.allowElement()")}}.
194199

195-
Note however that you can't specify both element `attributes` and `removeAttributes` in one call. Attempting to do so will raise an exception.
200+
Note that it is impossible to define per-element attribute behavior on a Sanitizer with a remove configuration, as the (needed) `elements` array is not present.
201+
Other restrictions on per-element attributes are covered in [Valid configurations](/en-US/docs/Web/API/SanitizerConfig#valid_configuration)
196202

197203
### Replacing child elements
198204

@@ -296,9 +302,9 @@ sanitizer.removeAttribute("lang");
296302

297303
## Comments and data attributes
298304

299-
The {{domxref("SanitizerConfig")}} can also be used to specify whether comments and `data-` attributes will be filtered from injected content, using the [comments](/en-US/docs/Web/API/SanitizerConfig#comments) and [dataAttributes](/en-US/docs/Web/API/SanitizerConfig#dataattributes) boolean properties, respectively.
305+
The {{domxref("SanitizerConfig")}} can also be used to specify whether comments will be filtered from injected content, using the [`comments`](/en-US/docs/Web/API/SanitizerConfig#comments) property, and whether `data-` attributes are allowed without having to add them to the `attributes` array using the [`dataAttributes`](/en-US/docs/Web/API/SanitizerConfig#dataattributes) boolean property.
300306

301-
To allow both comments and data attributes you might use a configuration like this:
307+
To allow comments and all `data-*` attributes you might use a configuration like this:
302308

303309
```js
304310
const sanitizer = new Sanitizer({
@@ -307,7 +313,7 @@ const sanitizer = new Sanitizer({
307313
});
308314
```
309315

310-
You can similarly enable or disable the comments or data-attributes on an existing sanitizer using {{domxref("Sanitizer.setComments()")}} and {{domxref("Sanitizer.setDataAttributes()")}} methods:
316+
You can similarly set the comments or data-attributes properties on an existing sanitizer using {{domxref("Sanitizer.setComments()")}} and {{domxref("Sanitizer.setDataAttributes()")}}:
311317

312318
```js
313319
const sanitizer = new Sanitizer({});
@@ -319,15 +325,19 @@ sanitizer.setDataAttributes(true);
319325

320326
All the sanitization methods can be passed a sanitizer configuration that is either a {{domxref("Sanitizer")}} or {{domxref("SanitizerConfig")}} instance.
321327

328+
The {{domxref("SanitizerConfig")}} provides a compact method for specifying multiple elements or attributes that should be allowed or removed at the same time.
329+
Some care may be required when modifying this object to ensure that it remains a [valid configuration](/en-US/docs/Web/API/SanitizerConfig#valid_configuration).
330+
322331
The {{domxref("Sanitizer")}} object is a wrapper around {{domxref("SanitizerConfig")}} that provides additional useful functionality:
323332

324333
- The default constructor creates a configuration that allows all XSS-safe elements and attributes, and which is therefore a good starting point for creating either slightly more or slightly less restrictive sanitizers.
325-
- When you use the methods to allow or remove HTML entities, the entities are removed from the "opposite" lists.
326-
These normalizations make the configuration more efficient.
334+
- The `Sanitizer` methods ensure that the underlying `SanitizerConfig` remains a [valid configuration](/en-US/docs/Web/API/SanitizerConfig#valid_configuration).
335+
For example, if you call `allowElement()` to allow an element then the element would also be removed from the underlying `replaceWithChildrenElements` array (if present).
336+
The normalizations make the configuration more efficient.
327337
- The {{domxref("Sanitizer.removeUnsafe()")}} method can be used to remove all XSS-unsafe entities from an existing configuration.
328338
- You can export the configuration to see exactly what entities are allowed and dropped.
329339

330-
Note though, if you can use the safe sanitization methods, then you may not need to define a sanitizer configuration at all.
340+
Note that if you can use the safe sanitization methods, then you may not need to define a sanitizer configuration at all.
331341

332342
## Examples
333343

files/en-us/web/api/sanitizer/allowattribute/index.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ browser-compat: api.Sanitizer.allowAttribute
1010

1111
{{APIRef("HTML Sanitizer API")}}{{SeeCompatTable}}
1212

13-
The **`allowAttribute()`** method of the {{domxref("Sanitizer")}} interface sets an attribute to be allowed on all elements.
13+
The **`allowAttribute()`** method of the {{domxref("Sanitizer")}} interface sets an attribute to be allowed on all elements when the sanitizer is used.
1414

15-
The specified attribute is added to the list of [`attributes`](/en-US/docs/Web/API/SanitizerConfig#attributes_2) in this sanitizer's configuration.
16-
The attribute is removed from the [`removeAttributes`](/en-US/docs/Web/API/SanitizerConfig#removeattributes_2) list if present.
15+
The method can be used with either an [allow configuration](/en-US/docs/Web/API/HTML_Sanitizer_API#allow_configurations) or a [remove configuration](/en-US/docs/Web/API/HTML_Sanitizer_API#remove_configurations).
16+
If used with an allow configuration, the specified attribute is added to the `attributes` array.
17+
If used with a remove configuration, the attribute is removed from the `removeAttributes` array (if present).
1718

1819
Note that to allow/disallow attributes only on specific elements use {{domxref('Sanitizer.allowElement()')}}.
1920

@@ -34,7 +35,13 @@ allowAttribute(attribute)
3435

3536
### Return value
3637

37-
None (`undefined`).
38+
`true` if the operation changed the configuration to allow the attribute, and `false` if the configuration already allowed the attribute.
39+
40+
Note that `false` might be returned if the internal configuration:
41+
42+
- defines an [`attributes`](/en-US/docs/Web/API/SanitizerConfig#attributes) array and the attribute is already present (it does not need to be added again)
43+
- instead defines the [`removeAttributes`](/en-US/docs/Web/API/SanitizerConfig#removeattributes) array and the specified attribute is not present (and is hence already allowed)
44+
- [`dataAttributes`](/en-US/docs/Web/API/SanitizerConfig#dataattributes) is set `true`, but a `data-*` attribute is passed.
3845

3946
## Examples
4047

files/en-us/web/api/sanitizer/allowelement/index.md

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,8 @@ browser-compat: api.Sanitizer.allowElement
1111
{{APIRef("HTML Sanitizer API")}}{{SeeCompatTable}}
1212

1313
The **`allowElement()`** method of the {{domxref("Sanitizer")}} interface sets that the specified element is allowed in the output when the sanitizer is used.
14-
The element can be specified with lists of attributes that are allowed or disallowed on elements of that type.
1514

16-
The specified element is added to the [`elements`](/en-US/docs/Web/API/SanitizerConfig#elements) list in this sanitizer's configuration.
17-
If the element is already present in the list, then the existing entry is first removed and the new definition is appended to the end of the list.
18-
Note that if you need both per-element add-attribute and remove-attribute lists, they must be added in a single call to this method (since if done in two calls, the second call will replace the element definition added in the first call).
19-
20-
The specified element is removed from the sanitizer configuration [`removeElements`](/en-US/docs/Web/API/SanitizerConfig#removeelements) or [`replaceWithChildrenElements`](/en-US/docs/Web/API/SanitizerConfig#replacewithchildrenelements) lists if present.
15+
It can also be used to specify per-element attribute allow or remove arrays on `Sanitizer` instances with an [allow configuration](/en-US/docs/Web/API/HTML_Sanitizer_API#allow_configurations).
2116

2217
## Syntax
2318

@@ -54,7 +49,62 @@ allowElement(element)
5449

5550
### Return value
5651

57-
None (`undefined`).
52+
`true` if the operation changed the configuration to allow the element, and `false` if the configuration was not changed (usually because the element was already allowed, but potentially because the change could not be made).
53+
54+
Note that `false` might be returned if the internal configuration:
55+
56+
- defines the [`elements`](/en-US/docs/Web/API/SanitizerConfig#elements) array and the element is already present (it does not need to be added again).
57+
- defines the [`removeElements`](/en-US/docs/Web/API/SanitizerConfig#removeelements) array and the specified element is not present (and is hence already not filtered).
58+
- defines the [`removeElements`](/en-US/docs/Web/API/SanitizerConfig#removeelements) array and attempts to allow an element with per-element attributes.
59+
This operation is not supported because in a [valid configuration](/en-US/docs/Web/API/SanitizerConfig#valid_configuration) you can't have both `removeElements` and `elements` arrays, and per-element attributes are added in the `elements` array.
60+
The call won't change the configuration and will generate a console warning.
61+
62+
## Description
63+
64+
The `allowElement()` method sets that the specified element is allowed in the output when the sanitizer is used.
65+
66+
The method can be used with either an [allow configuration](/en-US/docs/Web/API/HTML_Sanitizer_API#allow_configurations) or a [remove configuration](/en-US/docs/Web/API/HTML_Sanitizer_API#remove_configurations).
67+
If used with an allow configuration, the specified element is added to the `elements` array.
68+
If used with a remove configuration, the element is removed from the `removeElements` array (if present).
69+
If present, it would also be removed from the [`replaceWithChildrenElements`](/en-US/docs/Web/API/SanitizerConfig#replacewithchildrenelements) array.
70+
71+
For example, the following code creates an allow `Sanitizer` that allows {{htmlelement("span")}} elements and then calls `allowElement()` to additionally allow {{htmlelement("b")}} elements.
72+
73+
```js
74+
const sanitizer = new Sanitizer({ elements: ["span"] });
75+
sanitizer.allowElement("b");
76+
```
77+
78+
When using a `Sanitizer` with an allow configuration you can also use the method to specify attributes to be allowed or disallowed on elements of that type.
79+
For example, the following code first creates an allow sanitizer configuration by specifying the `elements` array (creating a `Sanitizer` with an empty object or no configuration object would also result in an "allow configuration").
80+
It then calls `allowElement()` to allow `div` elements, to allow the `class` attribute on `<div>` elements, and to remove the `lang` attribute on `<div>` elements.
81+
82+
```js
83+
const sanitizer = new Sanitizer({ elements: ["span"] });
84+
sanitizer.allowElement({
85+
name: "div",
86+
attributes: ["class"],
87+
removeAttributes: ["lang"],
88+
});
89+
```
90+
91+
If you need both per-element add-attribute and remove-attribute arrays as shown above, they must be added in a single call to this method.
92+
If you were to do this in two calls the the second call would replace the element definition added in the first call.
93+
94+
When using a `Sanitizer` with a [remove configuration](/en-US/docs/Web/API/HTML_Sanitizer_API#remove_configurations), similar code to add per-element attribute allow or remove arrays will generate a console warning and return `false`.
95+
This is because internally the sanitizer doesn't have the `elements` array required to specify per-element attributes and won't change the configuration.
96+
97+
```js example-bad
98+
// Define Sanitizer with a remove configuration
99+
// by specifying removeElements in the configuration
100+
const sanitizer = new Sanitizer({ removeElements: [] });
101+
// Returns false and raises a console warning
102+
sanitizer.allowElement({
103+
name: "div",
104+
attributes: ["class"],
105+
removeAttributes: ["lang"],
106+
});
107+
```
58108

59109
## Examples
60110

0 commit comments

Comments
 (0)