Prévenir XSS dans ASP.NET

De nombreux problèmes de sécurité des sites Web proviennent d'une trop grande confiance en l'utilisateur. La plupart des utilisateurs de votre application Web ne feront que ce dont ils ont besoin. Un utilisateur curieux ou malveillant voudra souvent repousser les limites de l'accès. Sur ces bords, des failles de sécurité apparaissent souvent dans votre application. J'ai déjà écrit sur la prévention de deux types de vulnérabilités courants, l'injection SQL et la falsification de requêtes intersites, dans les applications ASP.NET auparavant. Cet article traite de la prévention du Cross Site Scripting, un troisième type de vulnérabilité courant sur les sites Web..

Bien qu'un cadre moderne rende beaucoup plus difficile ces attaques, je pense que nous devrions d'abord comprendre la manière dont une application est vulnérable à une attaque. Premièrement, regardons ce qu’est le Cross Site Scripting et comment il peut être exploité.

Qu'est ce que le Cross Site Scripting?

Le Cross Site Scripting (souvent abrégé en XSS) permet d’injecter des scripts malveillants dans un site Web par ailleurs fiable. Cette injection a lieu à l'insu de l'utilisateur. Le script injecté est exécuté comme s'il venait du site Web d'origine. Le script malveillant peut ainsi accéder à toutes les ressources du site Web hébergé auxquelles l'utilisateur aurait accès, telles que les cookies ou les jetons de session..

L'ouverture d'une attaque de script entre sites survient lorsqu'une application Web affiche les entrées d'utilisateurs ou de ressources externes sans les valider ou les coder correctement. Dans la plupart des attaques de script entre sites, l’attaquant tente d’injecter du code JavaScript dans la page Web d’un serveur de confiance. L’attaquant peut également tenter d’injecter du code HTML, Flash ou tout autre élément exécuté par le navigateur. Peu importe le script, le but reste que le navigateur exécute le code choisi par l'attaquant..

Une attaque XSS persistante

Il existe trois catégories d'attaques de script intersite, divisées par la méthode d'injection et la méthode de prévention de l'attaque. Dans le premier type d’attaque, le script est stocké de manière permanente sur le serveur cible et est donc appelé attaque de script intersite persistante. Cette attaque tente d'incorporer le script malveillant dans un élément tel qu'un message de forum stocké dans une base de données ou un champ apparemment anodin tel que la page d'accueil d'un utilisateur de la base de données. Le script persistant, chaque visiteur du site qui consulte l'article, le message ou un élément compromis devient victime potentielle de l'attaque..

Les pirates qui tentent ce type d’attaque ciblent généralement les champs de commentaires, les forums, les médias sociaux et d’autres domaines dans lesquels une entrée quelque peu arbitraire de l’utilisateur final est attendue et fait partie intégrante de l’application. L'attaquant peut inclure le script dans un message du forum dans une partie de la conversation par ailleurs valide. Chaque fois que quelqu'un voit la publication, le script sera exécuté.

Une attaque XSS réfléchie

Dans le deuxième type d’attaque de script intersite, appelé script intersite réfléchi, l’attaquant transmet le script injecté au site vulnérable afin qu’il soit immédiatement renvoyé à l’utilisateur. Méthodes courantes pour ce faire, les pages cibles où l'entrée utilisateur devient une partie de la sortie d'une page. Une page de recherche peut afficher les termes de recherche à l'intention de l'utilisateur et pourrait fournir un point de vente pour cette attaque. Le script injecté dans l'entrée d'un utilisateur ne doit jamais être stocké par l'application Web.

Attaques DOM

La troisième attaque de script entre sites se produit entièrement dans le navigateur. L'attaque fonctionne en manipulant le modèle interne de la page Web dans le navigateur connu sous le nom de DOM et sont appelées attaques à base de DOM. Celles-ci permettent à l'attaquant d'exécuter du code malveillant, mais le code renvoyé par le serveur est manipulé en JavaScript exécutable par la page Web..

En fin de compte, une attaque de script entre sites est une attaque de script entre sites, quelle que soit la manière dont elle est livrée. Comme le code injecté provient d'un serveur par ailleurs fiable, il peut souvent s'exécuter sous les autorisations du site. Il peut donc agir comme s'il s'agissait d'un code natif sur le site. 

Une attaque de script intersite réussie pourrait permettre l'accès aux cookies sur une page Web. Ces cookies peuvent contenir des informations sensibles, notamment des identificateurs de session, qui permettraient à l'attaquant de se faire passer pour l'utilisateur attaqué. L'attaque peut également modifier le contenu HTML d'une page pour afficher un faux formulaire de connexion et voler les informations de connexion de l'utilisateur. L'attaquant pourrait examiner et envoyer tout contenu de la page permettant de capturer des informations sensibles telles que les numéros de compte. Une attaque plus avancée pourrait en effet installer un enregistreur de frappe envoyant à un attaquant les informations entrées dans la page Web..

Protection contre les attaques de script intersite

Atténuer les scripts intersites nécessite de ne pas faire confiance aux entrées d'un utilisateur ou de toute autre source externe. L'application Web doit traiter ces données comme potentiellement dangereuses, peu importe la source. Examinons quelques méthodes spécifiques à ASP.NET pour empêcher ces attaques en utilisant des composants intégrés au framework et des bibliothèques disponibles gratuitement..

Valider toutes les entrées

L'application Web doit valider toute entrée dans l'application avant son utilisation. Tout comme avec d'autres attaques par injection telles que SQL Injection. L’application valide de préférence cette entrée par rapport à une liste blanche de valeurs acceptables. La validation supprime ou remplace les composants inattendus de l'entrée par une valeur codée. Une méthode de liste noire, qui ne supprime qu'une liste de caractères indésirables connus, peut être utilisée, mais est plus vulnérable aux nouvelles méthodes d'attaque..

Si nous savons qu'une valeur doit toujours être un entier, vous pouvez valider l'entrée à l'aide d'un code tel que:

int memberId; if (! int.TryParse (externalValue, out memberId)) return RedirectToAction ("InputError");  

Si le framework ne peut pas analyser ce qui a déjà été récupéré valeur externe sous forme d'entier, le code redirige vers une page qui afficherait une erreur. Sinon, nous savons que ID membres contient une valeur entière. Ce processus fonctionne également avec d'autres types de base. Certains types plus courants fournissent également des méthodes pour valider les informations. Le net Uri la classe contient une méthode IsWellFormedUriString qui peut valider une URL. Cela permettrait de valider que l'entrée de la page d'accueil d'un utilisateur contient une URL valide avant son affichage..

var userHomePage = userRecord ["homepage"]; if (! Uri.IsWellFormedUriString (newUrl, UriKind.Absolute)) Model.homepage = "none";  else Model.homepage = Html.Encode (userHomePage);  

D'autres types de données, plus complexes, nécessitent une validation plus complexe. La validation d'un champ de numéro de carte de crédit peut supprimer tous les caractères de la chaîne qui ne sont pas des chiffres. La validation de chaînes plus complexes peut nécessiter des expressions régulières. La validation d'une classe peut également nécessiter des vérifications plus complexes.

Validation de la demande ASP.NET

ASP.NET fournit une protection efficace contre les attaques réfléchies à l'aide de la validation de requête. Si ASP.NET détecte du balisage ou du code dans une requête, il lève une exception "valeur potentiellement dangereuse détectée" et arrête le traitement de la requête..

Bien que précieux, vous devez parfois autoriser ces valeurs dans une demande. Un exemple courant consiste à autoriser la saisie de texte enrichi dans un formulaire. Malheureusement, dans ce cas, la validation de la demande est trop souvent désactivée pour l’ensemble du site. Une meilleure solution désactive cette validation uniquement si nécessaire. Dans les versions antérieures d’ASP.NET, l’ajout de validateRequest = "false" au Page directive dans Webforms désactive la validation d'une page. Dans ASP.NET MVC, l’ajout de la [ValidateInput (false)] attribut à une action de contrôleur désactive la validation de cette action, tout en ajoutant la [AllowHtml] attribut désactive la validation d'un champ.

ASP.NET 4.0 a modifié la validation de la demande de plusieurs manières. Cette version et les versions ultérieures de l'infrastructure effectuent une validation au début de la requête HTTP. La validation s’applique également à toutes les demandes ASP.NET et pas seulement .aspx demandes de page. Cela inclut également les modules HTTP personnalisés. Les pages qui reposent sur le comportement d'origine peuvent revenir à l'ancienne méthode en définissant le paramètre requestValidationMode attribuer dans le web.config fichier à la version 2.0.

 

Encore mieux, ne désactivez cette option que pour les pages nécessaires, en utilisant la syntaxe web.configfichier:

     

ASP.NET 4.5 a ajouté la possibilité de différer la validation jusqu'à la demande des données. Réglage du requestValidationMode attribuer dans votre web.config fichier à la version 4,5 active ce nouveau comportement.

 

ASP.NET 4.5 a également ajouté le HttpRequest.Unvalidated propriété. L'utilisation de cette propriété permet d'accéder plus facilement à la valeur de formulaire non validée, le cas échéant. En combinant la validation différée et la Non validé propriété, vous pouvez accéder aux valeurs non validées en cas de besoin, mais protéger les autres entrées de formulaire.

Encodage HTML

Avant d'afficher des données externes sur une page Web, votre code HTML doit être codé afin qu'il ne soit pas traité par le navigateur. A titre d'exemple, prenons une page ASP.NET écrite afin qu'un message puisse être transmis pour l'affichage, tel qu'une mise à jour de statut. Une application peut utiliser cette page pour montrer à l'utilisateur que son compte a été créé sans erreur. L’URL de cette page devrait normalement ressembler à http: // appname / placeorder / Account + Created. La page résultante affiche le message à l'utilisateur avec un champ, tel que:

<%= Html.Label("Message", Model.message) %> 

… Et s'affiche comme:

Si nous changeons l'appel d'URL en http: / appname / placeorder /, nous avons maintenant quelque chose de différent.

Le script pourrait être n'importe quoi bien sûr et pas seulement la boîte d’alerte inoffensive qui apparaît ici. La validation de la demande intercepte les exemples ci-dessus et renvoie une exception avant affichage. S'il est désactivé, l'encodage de la sortie empêche l'attaque.

ASP.NET facilite le codage des données afin de prévenir les attaques. Les premières versions de MVC utilisant la syntaxe de Webform contenaient souvent un code tel que celui-ci qui ne codait pas HTML.

<%= status >

Vous deviez encoder manuellement la sortie afin que tout code HTML soit converti en un format d'affichage. Alors le < le caractère devient la chaîne <. le Html.Encode fonction fournit cette conversion. La forme de code plus sûre devient alors:

<%= Html.Encode(status) >

ASP.NET MVC a plus tard introduit une syntaxe permettant de le faire en une étape en remplaçant <= avec <: de sorte que le code peut être réduit à:

<%: status >

À l'aide du moteur d'affichage Razor, toutes les sorties sont codées en HTML, sauf si vous utilisez une méthode spécifique pour ne pas l'encoder. Dans Razor, le code équivalent à ce qui précède devient:

@statut

Razor gère automatiquement le codage HTML, quelle que soit la chaîne. statut contient. Dans le cas où vous devez rendre les données brutes, vous pouvez utiliser le HTML.Raw () méthode. Pour afficher le résultat sans encodage, on peut utiliser:

@ Html.Raw (statut)

Dans cet exemple, le code ci-dessus rendrait notre application vulnérable encore. Donc, il y a quelques cas où vous ne devriez pas encoder la sortie. Si vous désactivez cette fonctionnalité sur un champ, vous devez faire particulièrement attention à ce que les données soient désinfectées avant leur affichage. Heureusement, il existe une bibliothèque qui aide à cela, tout en protégeant votre application des scripts entre sites..

Bibliothèque AntiXSS

Si vous écrivez une application ASP.NET, vous devez utiliser la bibliothèque AntiXSS pour ASP.NET. "Sur le site Web du projet," AntiXSS fournit une multitude de fonctions de codage pour la saisie de l'utilisateur, notamment HTML, les attributs HTML, XML, CSS et JavaScript. "

La bibliothèque contient des méthodes axées sur la désinfection des données extérieures en fonction de l'utilisation prévue de ces données. Ces méthodes utilisent l'approche privilégiée basée sur la liste blanche. Cela signifie que les données codées, destinées à un attribut HTML, peuvent être filtrées pour ne contenir que des données valides pour un attribut HTML. Le traditionnel ASP.NET HtmlEncode les méthodes utilisent l'approche de liste noire qui ne code que certains caractères potentiellement dangereux.

Microsoft a commencé à inclure les routines principales de cette bibliothèque dans ASP.NET 4.5 dans une nouvelle System.Web.Security.AntiXss espace de noms. Vous pouvez également configurer le framework pour utiliser ces méthodes AntiXSS à la place des routines de codage intégrées. Vous faites cela en réglant la type d'encodeur attribut de httpRuntime dans le web.config fichier pour l'application:

 

Si votre application effectue un affichage significatif de données externes, l'utilisation d'AntiXSS contribuera grandement à protéger votre application contre les scripts intersites. Si vous utilisez ASP.NET 4.5, le fait de modifier votre application pour utiliser les nouvelles méthodes AntiXSS pour le codage par défaut fournit encore plus de protection pour votre application Web..

En résumé

Empêcher les scripts entre sites est plus difficile qu'il n'y parait initialement. OWASP répertorie plus de 80 vecteurs pouvant être ciblés à l'aide d'attaques de script intersite. Cette organisation répertorie également ces vulnérabilités au troisième rang de sa liste 2013 des dix principales vulnérabilités Web..

Si vous ne vous assurez pas que toutes les données extérieures introduites dans votre application sont correctement sauvegardées ou ne validez pas l'entrée avant de les placer sur une page de sortie, vous laissez votre application Web vulnérable au script intersite. En ASP.NET, cela peut être fait par:

  1. Valider toutes les entrées externes dans votre application avant de les afficher sur une page Web.
  2. Utilisez Request Validation partout où votre application n'a pas besoin de l'éteindre, telle qu'un formulaire permettant une entrée HTML riche. Si vous devez autoriser des informations non validées, laissez la validation partout ailleurs dans votre application..
  3. Encoder le code HTML avant d'afficher des données externes sur une page Web
  4. Utilisez les méthodes basées sur AntiXSS incluses dans ASP.NET 4.5 et utilisez la bibliothèque AntiXSS pour les anciennes versions d'ASP.NET.