Je crée un site Web qui permet aux gens de télécharger du contenu HTML.
Actuellement, ce sont les balises qui sont interdites:
<script></script>
<iframe>
<object>
<embed>
<style></style>
All on= attributes, i'm not gonna list them all there are like 70 of them
Je ne veux pas que l'utilisateur utilise du JavaScript ou ne place aucun code qui affectera d'autres balises sur la page, donc pas de balises de style non plus.
Existe-t-il d'autres balises dont je dois tenir compte lorsque je permets aux utilisateurs de générer du code HTML sans impact sur la page?
Vous essayez de filtrer les entrées des utilisateurs en mettant sur liste noire les choses que vous ne voulez pas autoriser. Malheureusement, surtout compte tenu de la très grande liste d'options pour HTML5, il est assez facile de manquer quelque chose. Manquer quelque chose entraînera une vulnérabilité XSS potentiellement dangereuse, ce que vous ne voulez vraiment pas. Pour choisir des exemples aléatoires du haut de ma tête:
on
que vous avez bannis, avez-vous vérifié et obtenu l'attribut d'événement onbounce
de la balise Marquee obsolète (mais toujours disponible)?Il peut y avoir tellement de pièges que la sécurisation des entrées avec une liste noire est presque impossible. De plus, vous abordez le problème sous un mauvais angle. En matière de sécurité, l'approche que vous souhaitez commencer est le Principe du moindre privilège . Plutôt que de demander "que dois-je empêcher mes utilisateurs de faire", il est beaucoup plus sûr de demander "que dois-je leur permettre de faire?". Par conséquent, vous avez besoin d'un processus en deux étapes:
1. Analyseur robuste. Vous avez besoin d'un analyseur très robuste. C'est étonnamment difficile car les navigateurs sont très indulgents quand il s'agit d'analyser du HTML. Si un attaquant vous donne un mauvais HTML et que votre analyseur cesse d'essayer et dit: "Il n'y a pas de HTML ici - vous êtes en sécurité!", Mais le navigateur prend la même entrée, essaie de deviner ce que le HTML était censé être, et se termine avec quelque chose de malveillant, vous avez une vulnérabilité XSS. C'est encore plus difficile que cela puisse paraître parce que différents navigateurs peuvent appliquer différentes "corrections" lors du traitement de la saisie HTML, ce qui rend encore plus difficile la tâche déjà difficile d'analyser le HTML de manière fiable.
À titre d'exemple de navigateurs jouant rapidement et librement avec HTML, vous pouvez enregistrer ce HTML dans un fichier et le charger dans votre navigateur:
<table><img src="1" <table onerror="alert(1)"
<p>hi</p></table>
Si vous le chargez avec Chrome et inspectez l'élément sur la page, vous verrez que le navigateur l'a rendu (cela dépend probablement de votre version)):
<img src="1" <table="" onerror="alert(1)" <p="">hi<p></p><table></table>
C'est une balise d'image avec une charge utile XSS active (qui est légèrement obscurcie par le fait qu'une balise table
et la p
se sont transformées en attributs sans signification), une chaîne littérale hi
, une balise p
vide et une balise table
vide. Le résultat final est assez différent de l'entrée. Je n'ai pas essayé de cacher la charge utile, mais votre analyseur l'aurait-il compris de la même manière? Peut-être que votre analyseur aurait tenté d'ignorer la balise img
à l'intérieur de la balise table
car tout ce qui ne se trouve pas dans une balise td
serait techniquement illégal. Peut-être que votre analyseur aurait été confus par le <table
à l'intérieur de la balise img
et ignoré la onerror
car une balise de table n'a pas techniquement d'événements. En fin de compte, rien de tout cela n'a empêché le navigateur d'exécuter ma charge utile javascript. Votre analyseur l'aurait-il saisi?
2. Liste blanche des balises et des attributs autorisés Une fois que vous avez analysé le code HTML de l'utilisateur, vous ne voulez pas comparer avec une liste noire et supprimer les balises/attributs non autorisés. Au lieu de cela, vous souhaitez comparer à une liste blanche et supprimer tout ce que vous n'avez pas spécifiquement vérifié et approuvé comme sûr. Cela renforce votre sécurité et, soyons honnêtes, voulez-vous vraiment que vos utilisateurs utilisent la balise Marquee
de toute façon?
Mais surtout, la construction d'un analyseur HTML robuste est étonnamment difficile. Si vous essayez de le faire vous-même, vous passerez beaucoup de temps et vous vous tromperez probablement beaucoup. Dans des circonstances normales, vous feriez bien mieux de simplement trouver une bibliothèque tierce bien prise en charge à utiliser.
Une tactique différente que je recommanderais normalement serait de ne pas laisser l'utilisateur utiliser HTML du tout. Au lieu de cela, autorisez un langage plus limité (comme le markdown utilisé pour écrire des questions et des réponses dans le débordement de pile). La spécification de langue plus limitée rend l'écriture d'un analyseur beaucoup plus facile et moins sujette aux erreurs, et le processus de conversion du démarque en HTML facilite la garantie de la "sécurité" (remarque: plus facile, non garanti - le démarque vers les convertisseurs HTML souffre toujours de XSS occasionnel vulnérabilités). Il y a un léger inconvénient à limiter le type d'options de formatage dont disposent les utilisateurs (bien que je ne considère pas vraiment cela comme un inconvénient dans la plupart des cas), mais vous avez également un avantage appréciable que les analyseurs de démarques et les convertisseurs HTML sont disponibles dans un large éventail variété de langues. Une option plus limitée comme celle-ci est généralement un bon compromis entre convivialité et sécurité. Vous pouvez même ajouter un éditeur WYSIWYG qui crée le démarque pour les utilisateurs.
Actuellement, ce sont les balises qui sont interdites:
En plus de ce qui a déjà été publié, assurez-vous que l'interdiction signifie "ne pas laisser l'utilisateur sauvegarder les données" , not = "supprimer les éléments interdits et enregistrer le reste" .
Un exemple:
Input:
Hi there, here is my <script>alert('scary script')</script>, will I be shown?
Filtered:
Hi there, here is my alert('scary script'), will I be shown?
Semble bon en supprimant simplement les balises interdites? Après tout, nous avons arrêté la balise de script de faire quelque chose de stupide. Mais que se passe-t-il si j'entre à la place?
Input:
Hi there, here is my <scr<script>ipt>alert('scary script')</scr<script>ipt>, will I be shown?
Filtered:
Hi there, here is my <script>alert('scary script')</script>, will I be shown?
Oups! Suppression du <script>
les balises ont fait de ma chaîne une attaque valide.
J'ai utilisé cette astuce pour créer une page de profil plus cool sur un réseau social oublié depuis longtemps qui vous a permis d'ajouter du HTML personnalisé. Le filtrage HTML est difficile, essayez de trouver un autre moyen de réaliser ce que vous recherchez.
Laissant de côté toutes les façons dont je pourrais encore glisser XSS au-delà de cette liste noire (que d'autres réponses ont largement couvert), autoriser le HTML arbitraire est toujours très dangereux. Par exemple, si l'utilisateur a le contrôle sur style=
attribut (vous avez dit que vous avez bloqué les balises de style, mais rien à propos des attributs en ligne), ou même qu'il a juste accès aux attributs de positionnement hérités (si vous laissez les utilisateurs fournir le code HTML, le navigateur devra autoriser une entrée quelque peu invalide) , l'attaquant peut essentiellement dessiner sur toute la page avec du contenu malveillant, tel qu'un formulaire de connexion de phishing, un (faux) avertissement de sécurité/message d'extorsion de ransomware, des images ou des vidéos horribles, etc. Les utilisateurs malveillants peuvent également trouver du HTML qui a un impact négatif sur un navigateur moteur de rendu (comme consommer une tonne de RAM et/ou prendre une éternité pour restituer et utiliser tout leur CPU; toutes les attaques ne visent pas à prendre le contrôle d'un système) et spam que HTML partout où ils pouvez.
La seule bonne option est d'utiliser un langage de mise en page sûr qui est traduit en HTML par une bibliothèque bien testée (les différentes formes de démarques ou bbcode sont prévues pour cela). Si vous devez autoriser le HTML, faites-le en ajoutant des balises spécifiques à la liste blanche, et au sein de ces balises, ajoutez des attributs spécifiques à la liste blanche (et si nécessaire uniquement en autorisant des valeurs spécifiques de ces attributs), et en jetant tout ce qui ne correspond pas. Ensuite, un nouveau test après chaque changement effectué par votre filtre pour vous assurer que le changement du filtre n'a pas introduit une entrée malveillante.
Il existe des risques majeurs avec le contenu généré par l'utilisateur qui doit être interprété/analysé et affiché publiquement. Les attaques XSS et similaires peuvent se produire lorsque les utilisateurs sont capables de se faufiler dans vos fonctions de nettoyage, et il existe de nombreuses variantes qu'un navigateur interprétera pour lesquelles vous devez concevoir.
Recommandation? N'autorisez pas les balises du tout. Si vous devez le faire, il existe des bibliothèques (côté serveur) qui tentent cela et sont susceptibles d'avoir beaucoup de travail pour éviter les contournements de désinfection qui peuvent exister.
En termes de votre question:
Existe-t-il d'autres balises dont je dois être attentif lorsque je permets aux utilisateurs de générer du HTML sans effet sur la page?
La meilleure approche consiste à supposer que toutes les balises sont préoccupantes, et plus encore, décidez des balises spécifiques que vous souhaitez (comme l'a suggéré l'utilisateur Ghedipunk). En effet, les balises peuvent être exploitées de manière unique et parfois imprévue. Cela peut aller de bizarreries d'implémentation de navigateur spécifiques à des utilisations moins courantes des balises. Il est beaucoup plus facile de supprimer toutes les entrées qui suivent le modèle d'une balise HTML, à l'exception de balises spécifiques, que d'essayer d'empêcher des balises spécifiques.
Il existe différentes manières d'y parvenir, des méthodes les plus naïves aux méthodes les plus avancées (traitement DOM réel). Si vous essayez de faire une approche de liste noire, vous chasserez constamment les variations de différentes attaques de contournement ainsi que les utilisations inattendues de diverses balises que vous pensiez sûres ou que vous avez oublié d'inclure.
Je suis convaincu qu'il existe déjà une bibliothèque qui a de telles opérations effectuées de manière plus avancée et sécurisée. Ma recommandation serait de les rechercher pour n'importe quelle plate-forme pour laquelle vous développez.
Si cela ne pose pas de problème pour la mise en page, une bonne option serait de placer le code généré par l'utilisateur dans un <iframe>
et le servir à partir d'un sous-domaine ou domaine distinct.
<iframe>
est conçu pour isoler le contenu à l'intérieur du cadre de la page à l'extérieur. En servant le contenu du cadre d'un domaine séparé, vous pouvez également l'isoler de tous les cookies que le site principal utilise. Les cookies du domaine principal (example.com) sont également visibles dans les sous-domaines (foo.example.com), mais si le site principal est dans un sous-domaine différent (www.example.com) ou un domaine complètement différent (example2.com), les sites aurait différents cookies.
L'inconvénient est qu'il est difficile de faire fusionner le contenu du cadre avec la page environnante, et cela peut provoquer par exemple barre de défilement séparée pour que le cadre apparaisse.
Cela pourrait conduire à un vecteur d'attaque appelé Cross Site Scripting (XSS) plus à ce sujet ici . Vous ne devez pas compter/faire confiance sur la mise sur liste noire de la liste des balises car il existe de nombreuses façons de la contourner dans un langage HTML en constante évolution.
La règle générale est d'utiliser l'environnement du bac à sable, d'assainir l'entrée et de coder la sortie. Il existe différentes solutions et frameworks aux deux extrémités (côté client et côté serveur) qui peuvent effectuer de telles tâches pour vous comme DOMPurify .