GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||
GeezerVison is showing developer.mozilla.org — HTML Sanitizer API - Web APIs | MDN HTML Sanitizer API
|
| Element arrays | Attribute arrays | Valid? |
|---|---|---|
elements |
- | ✔️ |
elements |
attributes |
✔️ |
elements |
removeAttributes |
✔️ |
removeElements |
- | ✔️ |
removeElements |
attributes |
✔️ |
removeElements |
removeAttributes |
✔️ |
| - | attributes |
✔️ |
| - | removeAttributes |
✔️ |
elements + removeElements |
(anything) | ❌ |
| (anything) | attributes + removeAttributes |
❌ |
| - | - | ✔️ |
An allow configuration can optionally specify whether per-element attributes should be allowed and/or removed in its elements array.
The allowed configuration for these local attributes depends on whether or not global attributes or removedAttributes is defined.
The valid configuration section outlines the restrictions.
In general an "allow configuration" is safer for both the elements and attributes, because you list the elements and/or attributes that you want and know are safe, rather than all the items that are dangerous or might potentially be considered dangerous in future. If you specify an empty configuration object then an empty allow configuration is used.
With "allow configurations" you specify the elements and attributes you wish to allow (or replace with child elements) — all other elements/attributes in the input will be dropped. This makes it easy to understand what elements will be allowed in the DOM when the HTML is parsed. They are useful when you know exactly what HTML entities you want to be able to inject in a particular context.
Allow configurations are created by defining a Sanitizer that wraps a SanitizerConfig that includes the elements and/or attributes arrays (and not the removeElements or removeAttributes arrays).
For example, the following configuration is created by passing a SanitizerConfig that allows <p> and <div> elements, and cite and onclick attributes on any allowed element.
It will also replace <b> elements with their child nodes.
const sanitizer = new Sanitizer({
elements: ["p", "div"],
replaceWithChildrenElements: ["b"],
attributes: ["cite", "onclick"],
});
The same configuration can also be created using Sanitizer methods.
Note that in the following code the Sanitizer() constructor takes an empty object, which results in a Sanitizer where the underlying configuration includes both elements and attributes arrays — in other words, an "allow configuration".
// Create empty sanitizer
const sanitizer = new Sanitizer({});
// Use Sanitizer methods to update the properties.
sanitizer.allowElement("p");
sanitizer.allowElement("div");
sanitizer.replaceElementWithChildren("b");
sanitizer.allowAttribute("cite");
sanitizer.allowAttribute("onclick");
In "remove configurations" you specify the HTML elements and attributes that you want to remove: any other elements and attributes are permitted by the sanitizer (but may be blocked if you use a safe sanitizer method, or if the element is not allowed in the context).
Remove configurations are created using a SanitizerConfig that includes the removeElements and/or removeAttributes arrays (and not the elements or attributes arrays).
For example, the following Sanitizer configuration would remove the same elements that were allowed in the previous code:
const sanitizer = new Sanitizer({
removeElements: ["p", "div"],
removeAttributes: ["cite", "onclick"],
replaceWithChildrenElements: ["b"],
});
The configuration can also be created using Sanitizer methods.
To make this a "remove configuration" we have to declare the removeElements or removeAttributes array when constructing the object (if only one array is specified the other will be defined as part of normalization).
const sanitizer = new Sanitizer({
removeElements: [],
});
sanitizer.removeElement("p");
sanitizer.removeElement("div");
sanitizer.replaceElementWithChildren("b");
sanitizer.removeAttribute("cite");
sanitizer.removeAttribute("onclick");
Sanitizer configurationsSanitizer is recommended when you're using a configuration object that you might want to reuse or modify.
Whether the sanitizer has an allow or remove configuration depends on the SanitizerConfig passed when the object is created.
For example, if you pass a configuration object that has the elements or attributes array (or an empty object) the sanitizer will have an allow configuration.
In the examples above we created an allow configuration and then called allowElement(), allowAttribute(), and replaceElementWithChildren() to allow additional elements and attributes, and similarly we created a remove configuration and called removeElement() and removeAttribute() to specify additional elements to remove.
You can also call the allow methods on a remove configuration, and the remove methods on an allow configuration — but they behave differently.
When you call the allow methods on an allow sanitizer the specified elements and attributes are added to the underlying elements and attributes array.
However if you call those methods on a remove sanitizer there is no elements and attributes array; instead the specified element is removed from the corresponding removeElements or removeAttributes array, if present.
This works because allowing an element in an allow sanitizer is the same as "not removing" an element in a remove sanitizer.
You can call all the Sanitizer methods on either an allow or remove sanitizer, and the method will make whatever changes it is able that result in a valid configuration.
For example, if you add an element the method will either add it to elements or remove it from removeElements if present, depending on the type of sanitizer, and also remove the same element from the replaceWithChildrenElements array, if present.
Some operations that are possible for an allow configuration are not possible for a remove configuration.
For example, per-element attributes are defined in the elements array, which is not present in a remove sanitizer.
The methods return true or false to indicate whether or not they modified the underlying configuration.
So if you call allowElement() on an allow configuration and the specified element is not present, it will be added to the elements array and the method will return true.
But if the element is already present then the method would return false.
Note that if you call the same method to set a per-element attribute, this will return false if called on a remove sanitizer, because the change cannot be made.
The XSS-safe baseline configuration defines the items that must be removed from an input in order to make it XSS-safe:
<embed>, <frame>, <iframe>, <object>, <script>, and <use>.onafterprint, onbeforeinput, and so on.The configuration is automatically applied to Element.setHTML() and the other safe sanitization methods, and ensures that XSS-unsafe items are removed from the output even if they are allowed by a passed sanitizer.
You can also call removeUnsafe on a Sanitizer instance to apply this configuration and make it XSS-safe.
The default sanitizer configuration is more restrictive than the XSS-safe baseline.
It defines the sanitizer that is used if you call Element.setHTML() or the other safe sanitization methods without passing a sanitizer object.
It is also the configuration that is returned by the Sanitizer() constructor when no configuration is set.
The configuration removes the following sorts of items:
data-* attributes.Therefore it provides a sanitizer with a minimal attack surface, which is still suitable for the majority of sanitization use cases.
For a listing of the allowed elements and attributes, see Default sanitizer configuration.
The Trusted Types API provides mechanisms to ensure that inputs are passed through a user-specified transformation function before being passed to an API that might execute that input. This transformation function is most commonly used to sanitize the input but it doesn't have to: the purpose of the API is primarily to make it easy for developers to audit sanitization code, not to define how or if sanitization is done.
The safe HTML sanitization methods don't use trusted types. Because they always filter all XSS-unsafe entities before input HTML is injected, there is no need to sanitize the input string, or audit the methods.
However the unsafe HTML sanitization methods may inject untrusted HTML, depending on the sanitizer, and so will work with trusted types.
The methods can take either a string or a TrustedType as input.
If a sanitizer is also supplied, the transformation function will be run first, and then the sanitizer.
Note that the behavior of the transformation function in this case will depend on the website policy (which might be to reject all use of the unsafe methods).
Prior to the Sanitizer API, developers typically filtered input strings using third-party libraries such as DOMPurify, perhaps called from transformation functions in trusted types.
These should not be necessary when using the safe HTML sanitization methods as the API is integrated with the browser, and is more aware of the parsing context and what code is allowed to execute than external parser libraries can be.
They may be useful with the unsafe HTML methods and trusted types, depending on website trusted type policies.
SanitizerA reusable sanitizer configuration object that defines what elements and attributes should be allowed/removed when sanitizing untrusted strings of HTML. This is used in the methods that insert strings of HTML into the DOM or Document.
SanitizerConfigA dictionary that defines a sanitizer configuration.
This can be used in the same places as Sanitizer but is likely to be less efficient to use and reuse.
Element.setHTML()Parse a string of HTML into a subtree of nodes, dropping any elements that are invalid in the context of the element. Then drop any elements and attributes that are not allowed by the sanitizer configuration, and any that are considered XSS-unsafe (even if allowed by the configuration). The subtree is then inserted into the DOM as a subtree of the element.
ShadowRoot.setHTML()Parse a string of HTML into a subtree of nodes.
Then drop any elements and attributes that are not allowed by the sanitizer configuration, and any that are considered XSS-unsafe (even if allowed by the configuration).
The subtree is then inserted as a subtree of the ShadowRoot.
Document.parseHTML()Parse a string of HTML into a subtree of nodes.
Then drop any elements and attributes that are not allowed by the sanitizer configuration, and any that are considered XSS-unsafe (even if allowed by the configuration).
The subtree is then set as the root of the Document.
Element.setHTMLUnsafe()Parse a string of HTML into a subtree of nodes, dropping any elements that are invalid in the context of the element. Then drop any elements and attributes that are not allowed by the sanitizer: if no sanitizer is specified allow all elements. The subtree is then inserted into the DOM as a subtree of the element.
ShadowRoot.setHTMLUnsafe()Parse a string of HTML into a subtree of nodes.
Then drop any elements and attributes that are not allowed by the sanitizer: if no sanitizer is specified allow all elements.
The subtree is then inserted as a subtree of the ShadowRoot.
Document.parseHTMLUnsafe()Parse a string of HTML into a subtree of nodes.
Then drop any elements and attributes that are not allowed by the sanitizer: if no sanitizer is specified allow all elements.
The subtree is then set as the root of the Document.
The following examples show how to use the sanitizer API using the default sanitizer.
Element.setHTML() with the default sanitizerIn most cases calling Element.setHTML() without passing a sanitizer can be used as a drop-in replacement for Element.innerHTML.
The code below demonstrates how the method is used to sanitize the HTML input before it is injected into an element with id of target.
const untrustedString = "abc <script>alert(1)<" + "/script> def"; // Untrusted HTML (perhaps from user input)
const someTargetElement = document.getElementById("target");
// someElement.innerHTML = untrustedString;
someElement.setHTML(untrustedString);
console.log(target.innerHTML); // abc def
The element is not allowed by the default sanitizer, or by the <script>setHTML() method, so the alert() is removed.
Note that using Element.setHTMLUnsafe() with the default sanitizer will sanitize the same HTML entities.
The main difference is that if you use this method with Trusted Types it may still be audited:
someElement.setHTMLUnsafe(untrustedString);
This code shows how you might use Element.setHTMLUnsafe() with an allow sanitizer that allows only <p>, <b>, and <div> elements.
All other elements in the input string would be removed.
const sanitizer = new Sanitizer({ elements: ["p", "b", "div"] });
someElement.setHTMLUnsafe(untrustedString, { sanitizer });
Note that in this case you should normally use setHTML().
You should only use Element.setHTMLUnsafe() if you need to allow XSS-unsafe elements or attributes.
| Specification |
|---|
| HTML # sanitizer |