Maison >interface Web >js tutoriel >Votre texte enrichi pourrait être une vulnérabilité de script intersite
Reconnaître et atténuer les vulnérabilités SXSS avant qu'elles ne soient exploitées
Par Luke Harrison
Cet article a été initialement publié sur IBM Developer.
De nombreuses applications actuelles doivent afficher du texte enrichi en HTML sur leurs sites Web. Afin de générer ce texte formaté à partir de la saisie de l'utilisateur, les développeurs utilisent un composant d'éditeur de texte enrichi. Le problème ? Cette fonctionnalité peut indirectement ouvrir votre application et vos données à une vulnérabilité connue sous le nom de scripts intersites stockés (SXSS).
Dans cet article, vous découvrirez ce qu'est une vulnérabilité SXSS et passerez en revue quelques « odeurs de code » que vous pouvez utiliser pour vérifier si vos applications sont affectées. Vous verrez également un exemple d'application vulnérable et découvrirez une stratégie de correction pour cette vulnérabilité.
Les scripts intersites stockés sont un type de vulnérabilité que les attaquants peuvent exploiter pour injecter du code malveillant dans une base de données. Ce code s'exécute ensuite sur le navigateur de la victime après avoir été récupéré et restitué par un framework frontal.
Cette vulnérabilité est extrêmement dangereuse car elle peut permettre aux attaquants de voler des cookies, de déclencher des redirections ou d'exécuter un assortiment de scripts dangereux dans le navigateur de la victime. La propagation de l'exploit nécessite très peu de travail de la part de l'attaquant : la victime n'a pas besoin de cliquer sur un lien malveillant ou de se laisser prendre à un stratagème de phishing, elle utilise simplement un site de confiance affecté par SXSS. Consultez les liens en bas de la page pour plus de détails sur les vulnérabilités de script intersite.
Une odeur de code est simplement une caractéristique du code qui indique un problème plus profond. Les navigateurs n'exécutent normalement pas automatiquement les scripts injectés, mais si un développeur utilise des API de navigateur ou des propriétés d'éléments potentiellement dangereuses, cela peut conduire à une situation dans laquelle les scripts do s'exécutent.
Jetez un œil à l'extrait de code suivant :
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
Dans cet exemple, nous stockons du HTML dans une variable, récupérons un élément du DOM et définissons la propriété innerHTML de cet élément sur le contenu stocké dans la variable. La propriété innerHTML peut être utilisée pour restituer du HTML à partir d'une chaîne à l'intérieur d'un autre élément HTML.
Ce qui est dangereux avec cette propriété, c'est qu'elle restituera tout code HTML ou JavaScript que vous lui transmettrez. Cela signifie que si quelqu'un était en mesure de contrôler les données transmises à la propriété, il pourrait techniquement exécuter n'importe quel JavaScript dans le navigateur d'un utilisateur.
Un autre moyen populaire mais dangereux de restituer du HTML dynamique dans un navigateur consiste à utiliser la propriété du composant React DangerlySetInnerHTML. Cette propriété se comporte exactement de la même manière que la propriété innerHTML dans Vanilla JavaScript et HTML.
L'exemple suivant apparaît dans la documentation React :
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
Si vous utilisez actuellement l'une de ces propriétés dans une application Web frontale, il y a de fortes chances que vous ayez un certain type de vulnérabilité de script intersite. Nous verrons comment ces propriétés peuvent être exploitées et quelques mesures que vous pouvez prendre pour résoudre ces problèmes plus loin dans cet article.
Un autre signe indiquant que votre application pourrait être vulnérable à SXSS est simplement le fait que vous utilisez ou non un éditeur de texte enrichi, tel que TinyMCE ou CKEditor.
La plupart des éditeurs de texte enrichi fonctionnent en convertissant le texte formaté généré par un utilisateur en HTML. Comme mesure de sécurité supplémentaire, bon nombre de ces éditeurs utilisent une forme de nettoyage pour supprimer le JavaScript potentiellement malveillant de leurs entrées. Cependant, si vous n'appliquez pas ces mêmes techniques de nettoyage sur les services qui reçoivent et stockent le contenu en texte enrichi, vous rendez probablement vos applications vulnérables à SXSS.
Même si vous ne restituez pas le contenu sur vos propres sites, il y a de fortes chances que ces données soient consommées par des applications qui effectuent le rendu. Pour concevoir des applications sécurisées, il est extrêmement important de prendre en compte les consommateurs actuels et futurs de vos données. Si vos données sont affectées par SXSS, toutes les applications qui consomment vos données le sont également.
Jetons un coup d'œil à un petit exemple d'application Web présentant une vulnérabilité SXSS, puis tentons de l'exploiter.
Pour exécuter cette application, clonez d'abord ce dépôt d'application de démonstration et suivez les instructions « Exécuter l'application » dans le fichier readme.md.
Après avoir exécuté l'application et accédé à http://localhost:3000/unsanitized.html, vous devriez voir une page qui ressemble à ceci :
Cette application prend simplement du texte enrichi d'un utilisateur, le stocke sur un serveur Web, puis le restitue dans la section intitulée Sortie.
Avant d'exploiter la vulnérabilité SXSS, prenez un moment pour jeter un œil à l'application. Reportez-vous aux odeurs de code mentionnées ci-dessus et parcourez le code pour voir si vous pouvez repérer les sections problématiques. Essayez d'ouvrir l'onglet Réseau dans votre navigateur et voyez les requêtes qu'il envoie lorsque vous saisissez et soumettez du texte enrichi.
Dans le fichier unsanitzed.html, vous verrez la fonction suivante, nommée renderPostByID :
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
Regardez attentivement cette fonction. Vous remarquerez que nous utilisons la propriété innerHTML mentionnée ci-dessus pour restituer du texte enrichi que nous avons récupéré de l'API sous forme HTML.
Maintenant que nous voyons la partie vulnérable du code, exploitons-la. Nous allons contourner l'entrée de l'éditeur de texte enrichi et accéder au point de terminaison de l'API qui enregistre les publications directement sur le serveur Web. Pour ce faire, vous pouvez utiliser la commande cURL suivante :
function createMarkup() { return {__html: 'First · Second'}; } function MyComponent() { return <div dangerouslySetInnerHTML={createMarkup()} />; }
Remarquez la charge utile de données que nous envoyons dans la demande. Il s'agit d'un code HTML malveillant qui inclut une balise d'image avec une propriété onerror définie sur du JavaScript qui affiche une boîte de dialogue d'alerte. Les attaquants utiliseront des astuces comme celle-ci pour éviter les méthodes de nettoyage mal mises en œuvre visant à supprimer le JavaScript des éléments HTML avant qu'ils ne soient stockés dans une base de données.
Après avoir exécuté le script ci-dessus, vous devriez recevoir un identifiant de publication comme le suivant :
const renderPostByID = async (id) => { // setting url seach params let newURL = window.location.protocol + "//" + window.location.host + window.location.pathname + `?post=${id}`; window.history.pushState({ path: newURL }, "", newURL); // getting rich text by post id let response = await fetch(`/unsanitized/${id}`, { method: "GET" }); let responseJSON = await response.json(); console.log(responseJSON); // rendering rich text output.innerHTML = responseJSON.richText; };
Collez cet ID de publication dans le paramètre de requête d'URL de publication et appuyez sur Entrée.
Lorsque vous faites cela, vous devriez voir une boîte de dialogue d'alerte sur votre écran confirmant que le site est effectivement vulnérable à SXSS.
Maintenant que nous avons vu comment exploiter une vulnérabilité SXSS, voyons comment nous pouvons corriger une vulnérabilité. Pour ce faire, vous devrez nettoyer le texte enrichi HTML à trois endroits différents :
Il peut être clair pourquoi vous souhaitez nettoyer le contenu avant de le stocker dans la base de données et lors de son rendu côté client, mais pourquoi le nettoyer lors de sa récupération ? Eh bien, imaginons que quelqu'un obtienne les privilèges nécessaires pour insérer du contenu directement dans votre base de données. Ils pouvaient désormais insérer directement du code HTML malveillant, contournant complètement le désinfectant initial. Si un consommateur de l’une de vos API n’implémente pas également cette désinfection côté client, il pourrait être victime de l’exploit de script intersite.
Gardez toutefois à l'esprit que l'ajout d'une désinfection aux trois emplacements pourrait entraîner une dégradation des performances. Vous devrez donc décider vous-même si vous avez besoin de ce niveau de sécurité. À tout le moins, vous devez nettoyer toutes les données côté client avant de restituer du contenu HTML dynamique.
Voyons comment nous implémentons la désinfection dans la version sécurisée de notre application vulnérable. Étant donné que cette application est principalement écrite en JavaScript, nous utilisons la bibliothèque dompurify pour le côté client et la bibliothèque isomorphic-dompurify pour la désinfection côté serveur. Dans le programme app.js qui fait office de serveur web, vous trouverez un point de terminaison express /sanitized avec une implémentation GET et POST :
const someHTML = “<h1>Hello world</h1>“ const output = document.getElementById("rich-text-output"); output.innerHTML = someHTML
Dans l'implémentation POST, nous récupérons d'abord le texte riche du corps de la requête, puis appelons la méthode sanitize de la bibliothèque isomorphic-dompurify avant de le stocker dans notre objet de données. De même, dans l'implémentation GET, nous appelons la même méthode sur le texte enrichi après l'avoir récupéré de notre objet de données et avant de l'envoyer à notre consommateur.
Côté client, nous utilisons à nouveau cette même méthode avant de définir la propriété innerHTML de notre div de sortie dans sanitized.html.
function createMarkup() { return {__html: 'First · Second'}; } function MyComponent() { return <div dangerouslySetInnerHTML={createMarkup()} />; }
Maintenant que vous avez vu comment nous nettoyons correctement le HTML pour empêcher les scripts intersites, revenez à l'exploit d'origine de cette application et exécutez-la à nouveau, cette fois en utilisant le point de terminaison nettoyé. Vous ne devriez plus voir la boîte de dialogue d'alerte, car nous utilisons désormais les techniques appropriées pour empêcher la vulnérabilité SXSS.
Pour un guide SXSS complet, comprenant les meilleures pratiques et d'autres techniques de prévention du XSS, jetez un œil à l'aide-mémoire OWASP Cross-Site Scripting.
Dans cet article, nous avons examiné comment vous pouvez améliorer la sécurité de vos applications en empêchant les scripts intersites stockés, un type courant de vulnérabilité des applications Web. Vous devriez maintenant être en mesure de reconnaître si vos propres applications sont vulnérables, quelles fonctionnalités vous devez examiner et comment les atténuer avant que des acteurs malveillants puissent exploiter ces vulnérabilités.
La sécurité est primordiale pour les développeurs d'entreprise. Utilisez les ressources suivantes pour continuer à vous sensibiliser aux vulnérabilités possibles et aux moyens par lesquels vous pouvez améliorer votre posture de sécurité.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!