Le script intersites basé sur le DOM (DOM XSS) se produit lorsque des données provenant d'une
source contrôlée par l'utilisateur (comme un nom d'utilisateur ou une URL de redirection extraite du fragment d'URL
) atteignent un récepteur, qui est une fonction telle que eval() ou un setter de propriété
tel que .innerHTML qui peut exécuter du code JavaScript arbitraire.
Le DOM XSS est l'une des failles de sécurité Web les plus courantes, et il est fréquent que les équipes de développement l'introduisent accidentellement dans leurs applications. Les Trusted Types vous fournissent les outils nécessaires pour écrire, examiner la sécurité et protéger les applications contre les failles DOM XSS en sécurisant par défaut les fonctions d'API Web dangereuses. Les Trusted Types sont disponibles en tant que polyfill pour les navigateurs qui ne les prennent pas encore en charge.
Arrière-plan
Depuis de nombreuses années, le DOM XSS est l'une des failles de sécurité Web les plus répandues et les plus dangereuses.
Il existe deux types de scripts intersites. Certaines failles XSS sont causées par du code côté serveur qui crée de manière non sécurisée le code HTML formant le site Web. D'autres ont une cause racine sur le client, où le code JavaScript appelle des fonctions dangereuses avec du contenu contrôlé par l'utilisateur.
Pour éviter le XSS côté serveur, ne générez pas de code HTML en concaténant des chaînes. Utilisez plutôt des bibliothèques de modèles d'échappement automatique contextuel sécurisées, ainsi qu'une Content Security Policy basée sur un nonce pour atténuer davantage les bugs.
Les navigateurs peuvent désormais également aider à prévenir le XSS basé sur le DOM côté client à l'aide des Trusted Types.
Présentation de l'API
Les Trusted Types fonctionnent en verrouillant les fonctions de récepteur risquées suivantes. Vous en reconnaîtrez peut-être certaines, car les fournisseurs de navigateurs et les frameworks Web vous empêchent déjà d'utiliser ces fonctionnalités pour des raisons de sécurité.
- Manipulation de scripts:
<script src>et définition du contenu textuel des<script>éléments. - Génération de code HTML à partir d'une chaîne:
- Exécution de contenu de plug-in:
- Compilation de code JavaScript au moment de l'exécution:
evalsetTimeoutsetIntervalnew Function()
Les Trusted Types vous obligent à traiter les données avant de les transmettre à ces fonctions de récepteur. L'utilisation d'une chaîne uniquement échoue, car le navigateur ne sait pas si les données sont fiables :
anElement.innerHTML = location.href;
Pour indiquer que les données ont été traitées de manière sécurisée, créez un objet spécial : un Trusted Type.
anElement.innerHTML = aTrustedHTML;
TrustedHTML
pour les récepteurs qui attendent des extraits HTML. Il existe également des objets
TrustedScript et TrustedScriptURL pour d'autres
récepteurs sensibles.
Les Trusted Types réduisent considérablement la surface d'attaque DOM XSS de votre application. Ils simplifient les examens de sécurité et vous permettent d'appliquer les vérifications de sécurité basées sur le type effectuées lors de la compilation, de la linting ou du regroupement de votre code au moment de l'exécution, dans le navigateur.
Utiliser les Trusted Types
Préparer les rapports de non-respect de la Content Security Policy
Vous pouvez déployer un collecteur de rapports, tel que le processeur Open Source reporting-api-processor ou go-csp-collector, ou utiliser l'un des équivalents commerciaux. Vous pouvez également ajouter une journalisation personnalisée et déboguer les violations dans le navigateur à l'aide d'un ReportingObserver :
const observer = new ReportingObserver((reports, observer) => {
for (const report of reports) {
if (report.type !== 'csp-violation' ||
report.body.effectiveDirective !== 'require-trusted-types-for') {
continue;
}
const violation = report.body;
console.log('Trusted Types Violation:', violation);
// ... (rest of your logging and reporting logic)
}
}, { buffered: true });
observer.observe();
ou en ajoutant un écouteur d'événements :
document.addEventListener('securitypolicyviolation',
console.error.bind(console));
Ajouter un en-tête CSP en mode rapport uniquement
Ajoutez l'en-tête de réponse HTTP suivant aux documents que vous souhaitez migrer vers les Trusted Types :
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Toutes les violations sont désormais signalées à //my-csp-endpoint.example, mais le site Web continue de fonctionner. La section suivante explique le fonctionnement de //my-csp-endpoint.example.
Identifier les violations des Trusted Types
Désormais, chaque fois que les Trusted Types détectent une violation, le navigateur envoie un rapport à un report-uri configuré. Par exemple, lorsque votre application transmet une chaîne à innerHTML, le navigateur envoie le rapport suivant :
{
"csp-report": {
"document-uri": "https://my.url.example",
"violated-directive": "require-trusted-types-for",
"disposition": "report",
"blocked-uri": "trusted-types-sink",
"line-number": 39,
"column-number": 12,
"source-file": "https://my.url.example/script.js",
"status-code": 0,
"script-sample": "Element innerHTML <img src=x"
}
}
Cela indique que dans https://my.url.example/script.js à la ligne 39, innerHTML a été
appelé avec la chaîne commençant par <img src=x. Ces informations devraient vous aider à identifier les parties du code susceptibles d'introduire un DOM XSS et qui doivent être modifiées.
Résoudre les violations
Vous disposez de plusieurs options pour corriger une violation de Trusted Type. Vous pouvez supprimer le code qui pose problème, utiliser une bibliothèque, créer une règle Trusted Type ou, en dernier recours, créer une règle par défaut.
Réécrire le code qui pose problème
Il est possible que le code non conforme ne soit plus nécessaire ou qu'il puisse être réécrit sans les fonctions qui provoquent les violations :
el.textContent = ''; const img = document.createElement('img'); img.src = 'xyz.jpg'; el.appendChild(img);
el.innerHTML = '<img src=xyz.jpg>';
Utiliser une bibliothèque
Certaines bibliothèques génèrent déjà des Trusted Types que vous pouvez transmettre aux fonctions de récepteur. Par exemple, vous pouvez utiliser DOMPurify pour assainir un extrait HTML en supprimant les charges utiles XSS.
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});
DOMPurify prend en charge les Trusted Types
et renvoie du code HTML assaini encapsulé dans un objet TrustedHTML, de sorte que le navigateur
ne génère pas de violation.
Créer une règle Trusted Type
Parfois, vous ne pouvez pas supprimer le code qui provoque la violation, et aucune bibliothèque n'est disponible pour assainir la valeur et créer un Trusted Type pour vous. Dans ce cas, vous pouvez créer vous-même un objet Trusted Type.
Commencez par créer une règle. Les règles sont des usines pour les Trusted Types qui appliquent certaines règles de sécurité à leur entrée :
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
createHTML: string => string.replace(/\</g, '<')
});
}
Ce code crée une règle appelée myEscapePolicy qui peut produire des objets TrustedHTML à l'aide de sa fonction createHTML(). Les règles définies échappent les caractères < en HTML pour empêcher la création de nouveaux éléments HTML.
Utilisez la règle comme suit :
const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped; // '<img src=x onerror=alert(1)>'
Utiliser une règle par défaut
Parfois, vous ne pouvez pas modifier le code qui pose problème, par exemple si vous chargez une bibliothèque tierce à partir d'un CDN. Dans ce cas, utilisez une règle par défaut :
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
trustedTypes.createPolicy('default', {
createHTML: (string, sink) => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true})
});
}
La règle nommée default est utilisée chaque fois qu'une chaîne est utilisée dans un récepteur qui n'accepte que les Trusted Types.
Passer à l'application de la Content Security Policy
Lorsque votre application ne génère plus de violations, vous pouvez commencer à appliquer les Trusted Types :
Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Désormais, quelle que soit la complexité de votre application Web, la seule chose qui peut introduire une faille DOM XSS est le code de l'une de vos règles. Vous pouvez renforcer la sécurité en limitant la création de règles.