Vertrouwde typen is een beveiligingsfunctie die DOM-gebaseerde cross-site scripting (DOM XSS) helpt voorkomen door te vereisen dat gegevens die worden doorgegeven aan 'gevaarlijke' browser-API's (ook wel sinks genoemd), eerst worden geconverteerd naar een specifiek type, zoals TrustedHTML.
Standaard accepteren veel DOM API's (zoals innerHTML of document.write) onbewerkte tekenreeksen. Als een tekenreeks een schadelijk script van een niet-vertrouwde bron bevat, kan dit worden uitgevoerd. Trusted Types verandert dit gedrag: zodra deze sinks zijn aangezet via CSP, accepteren ze alleen TrustedHTML-objecten die zijn gemaakt door geautoriseerd beleid.
Belangrijke implementatiegegevens
Volg deze 4 hoofdstappen om Trusted Types te gebruiken:
- Definieer een beveiligingsbeleid dat aangeeft hoe tekenreeksen moeten worden opgeschoond of getransformeerd.
- Gebruik dat beleid om Trusted Type-objecten te maken op basis van onbewerkte tekenreeksen.
- Gebruik de Trusted Type-objecten als je naar DOM-sinks schrijft.
- Dwing vertrouwde typen af met een Content Security Policy (CSP).
1. Een beleidsregel maken
Een beleid is een reeks regels om content op te schonen. Je maakt het met trustedTypes.createPolicy(), meestal door te delegeren naar een opschoningsbibliotheek zoals DOMPurify of de HTML-escapingregels van je app:
import DOMPurify from 'dompurify';
const myPolicy = trustedTypes.createPolicy('sanitize-html', {
createHTML: (input) =>
// Return a sanitized string; createPolicy() wraps it in a TrustedHTML object.
// Example using DOMPurify:
DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: false }),
});
// Example using HTML escaping (for environments without third-party sanitizers):
const escapePolicy = trustedTypes.createPolicy('escape-html', {
createHTML: (input) =>
String(input)
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
.replaceAll("'", '''),
});
2. Het beleid gebruiken
In plaats van een tekenreeks rechtstreeks door te geven aan een sink, roep je de aanmaakmethode van het beleid aan.
const untrustedInput = '<p>Hello, <strong>world</strong>!</p><img src="x" onerror="alert(1)">';
// In an enforced environment, this would throw a TypeError:
// element.innerHTML = untrustedInput;
// This returns a TrustedHTML object with unsafe elements and attributes removed:
const cleanHTML = myPolicy.createHTML(untrustedInput);
// Result: "<p>Hello, <strong>world</strong>!</p><img src=\"x\">"
3. Sinks overzetten om Trusted Types te gebruiken
Update elke instantie waarin je naar een sink schrijft om deze eerst te converteren naar een Trusted Type-object. Als je wilt vinden waar de code moet worden geüpdatet, kun je een tijdelijk default-beleid definiëren dat registreert wanneer een sink wordt geschreven met een tekenreeks in plaats van een TrustedType.
trustedTypes.createPolicy("default", {
createHTML(value) {
console.warn("String passed instead of Trusted Type.");
return DOMPurify.sanitize(value, { RETURN_TRUSTED_TYPE: false });
},
});
Veelvoorkomende sinks die Trusted Types ondersteunen, zijn onder andere:
- HTML:
element.innerHTML,element.outerHTML,document.write(),element.setHTMLUnsafe(),Document.parseHTMLUnsafe() - Script:
<script>tekstcontent,eval() - ScriptURL:
<script src>,Worker(),SharedWorker()
// Assign the TrustedHTML object.
element.innerHTML = cleanHTML;
Voor de 'veilige' HTML-opschoningsmethoden (element.setHTML() en Document.parseHTML(), behandeld in Niet-vertrouwde HTML opschonen) is geen Trusted Types-beleid vereist, omdat ze potentiële XSS-aanvallen altijd native opschonen.
4. Vertrouwde typen afdwingen met CSP
Vertrouwde typen moeten incrementeel worden uitgerold om te voorkomen dat je app niet meer werkt. Volledige handhaving biedt de sterkste bescherming, maar brengt het risico met zich mee dat de site niet meer werkt als niet elke sink-schrijfactie is gemigreerd.
Vereisten
- Samenwerking met frameworks: Als het framework van je app (of een bibliotheek van derden die naar DOM-sinks schrijft) geen
TrustedHTML- ofTrustedScript-waarden produceert, kun je Trusted Types niet afdwingen zonder die code te breken. Controleer de frameworkondersteuning voordat je de uitrol start. - Refactoring van sinks: Zorg dat je gevaarlijke sinks hebt geïdentificeerd en gerefactord om je Trusted Types-beleid te gebruiken.
Uitrolstrategie
Alleen rapportage: Rol eerst uit met de header
Content-Security-Policy-Report-Only. Zo worden schendingen geregistreerd op je rapportage-eindpunt zonder dat de schrijfbewerkingen daadwerkelijk worden geblokkeerd.Content-Security-Policy-Report-Only: require-trusted-types-for 'script';Handhaving: Nadat je je beleid hebt geïntegreerd en het aantal schendingsmeldingen tot nul is gedaald, ga je over tot volledige handhaving.
Content-Security-Policy: require-trusted-types-for 'script';
Je kunt ook beperken welke beleidsregels mogen worden gemaakt (vermeld je beleidsnamen, zoals sanitize-html of escape-html, neem dompurify op als je beleid delegeert naar DOMPurify.sanitize(), waardoor intern een dompurify-beleid wordt gemaakt, en neem default op als je een standaardbeleid registreert tijdens de migratie):
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;
Met dit CSP veroorzaken schrijfbewerkingen naar een sink die geen vertrouwde typen gebruiken een fout. Als je een Trusted Type-beleid probeert te maken met een naam die niet in trusted-types staat, wordt er een foutmelding weergegeven.
Je kunt dit CSP ook instellen als een <meta>-tag in de <head> van je document, hoewel dit mogelijk minder beveiligd is.
<!-- First child of `<head>`, as earlier tags will not enforce this CSP. -->
<meta
http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;"
/>
Reservestrategieën
Voor browsers die Trusted Types nog niet ondersteunen, kun je een minimale 'tinyfill' gebruiken om te zorgen dat je code niet wordt verbroken terwijl je nog steeds opschoning biedt.
if (!window.trustedTypes) {
window.trustedTypes = {
createPolicy: (name, rules) => rules,
};
}
Zo kun je je code vandaag nog schrijven met het patroon voor vertrouwde typen. Ondersteunende browsers dwingen de typen af, terwijl oudere browsers je opschoningslogica nog steeds uitvoeren via het mock-beleid.
Als een browser geen vertrouwde typen ondersteunt, worden de TrustedHTML-objecten behandeld als tekenreeksen (als de tinyfill wordt gebruikt) of wordt de handhavingscontrole niet uitgevoerd op sinkniveau.