Sécurisation des applications web : les vulnérabilités majeures et leurs parades

Date : 15 Avril 2005

L'année 2004 et ce début d'année 2005 ont été marqués par de nombreuses failles impactant les navigateurs web (Internet Explorer, Mozilla, Netscape, etc...). Pour les serveurs web, les organisations sont également habituées à les mettre à jour ainsi que les serveurs d’applications pour corriger les failles qui sont régulièrement découvertes.

Par contre, dans le cas d’applications web, garantir un niveau de sécurité nécessite de prendre en considération toute les nouvelles menaces, qui s’ajoutent aux menaces déjà existantes. Il reste encore des menaces et potentiellement des failles de sécurité bien que tous les composants logiciels concernés sont à jour en terme de sécurité : les applications web, et les développements qu’elles impliquent, peuvent se montrer vulnérables à de nombreuses problématiques de sécurité, propres aux applications web. Les failles de sécurité applicatives résultent de la mise en œuvre de méthodes de programmation non sûres, et du non respect de règles de programmation visant à limiter les risques suite à l'apparition de nouvelles failles.

Cet article a pour objectifs :

  • de sensibiliser le lecteur à la sécurité des applications web,
  • de présenter succinctement les principales problématiques de sécurité applicatives et les vulnérabilités majeures pouvant affecter les applications web (illustrées d'exemples),
  • de fournir des pistes pour couvrir ces problématiques.

Nota : Au delà de cet article, pour une prise en compte rigoureuse des risques de sécurité dans les applications web, il conviendrait de prendre en compte la sécurité applicative dans le cycle de vie des projets :

  • fourniture aux projets de documents applicables qui détaillent les exigences pour les développements d’applications web sécurisées,  
  • définition de la sensibilité,
  • définition et validation des exigences applicables,
  • recette sécurité,
  • etc...


A/ Les problématiques

1/ La perte de confidentialité des données

  • Divulgation d’informations via les messages d'erreur

Principe : Lors de leur fonctionnement, les applications web sont amenées à générer des messages d'erreur, lorsque l’utilisateur fournit une requête non valide. Ces messages doivent être compréhensibles pour l'utilisateur, mais préserver les informations sensibles. La mauvaise gestion des messages d'erreur au niveau d'un site web peut entraîner plusieurs types de problème de sécurité. On peut citer :

  • Divulgation du nom et de la version précise du service web et du serveur d’application.
  • Fourniture d’informations sur l’existence de comptes applicatifs : pour un formulaire d’authentification applicative, lorsque l’authentification échoue, il faudrait retourner un seul message d’erreur, générique. En effet, à l’inverse, des messages d’erreur trop détaillés (exemple : "le mot de passe est incorrect) permettent de déterminer l’existence de comptes valides, afin dans un second temps de tenter de compromettre les mots de passe.  
  • Divulgation du chemin d’accès absolu de ressources sur le serveur (dans le cas où l’URL demandée n’existe pas).
  • etc...

Nota : Un serveur web peut également donner des informations trop précises sur les versions des produits et systèmes utilisés. Il s’agira alors d’appliquer les derniers correctifs sur le service, ou bien de modifier sa configuration de façon à minimiser les informations envoyées au client.

Solution : Mettre en place, au niveau du site, une politique de sécurité permettant de gérer tous les types possibles d'erreur, avec les informations associées. Ces dernières doivent permettre d'aider l'utilisateur sans lui révéler d'informations sensibles. Certaines erreurs doivent par ailleurs être journalisées, à des fins d'analyse en cas de tentatives d'attaques. 

  • Divulgation d’informations sensibles dans le code client (JavaScript)

Il convient de veiller à ce que les traitements JavaScript, réalisés sur le navigateur client, ne comportent pas d’informations sensibles.

Par exemple, la vérification de validité d’un identifiant, parmi tous les identifiants disponibles, ne devrait pas être réalisée côté client, car cela suppose de transmettre au client la liste de tous les identifiants valides. Cette vérification devrait alors être réalisée uniquement côté serveur, afin d’éviter cette fuite d’informations. 

  • Problème de stockage de l'information

Principe : Certaines applications web doivent conserver des données sensibles (mots de passe, numéros de cartes de crédit, informations concernant les utilisateurs, etc...). Si la sensibilité de ces données l’exige, elles devront être protégées grâce à des mécanismes de chiffrement (notamment dans le cas où l’application s’interface avec une base de données, ou bien avec une application tierce).

Les problèmes de sécurité liés au stockage de ces informations peuvent avoir plusieurs causes : échec de chiffrement des données confidentielles, stockage non sûr de clés, certificats ou mots de passe, conservation en mémoire de secrets, mauvais choix d'algorithme, etc...

Nota : Des fichiers temporaires ou de configuration laissés dans l’espace de diffusion web peuvent entraîner la divulgation d’informations concernant le fonctionnement de l’application.

Solution : Si une solution de chiffrement s'impose, privilégier une solution reconnue comme robuste et proposant un chiffrement fort. S'assurer que les informations sensibles sont stockées de manière sécurisée.

2/ Le problème d'authentification

Principe : Lorsqu’une application doit gérer des espaces privatifs pour les utilisateurs, des mécanismes d'authentification et de gestion de session sont mis en place au niveau de l’application web, afin de gérer les sessions des différents utilisateurs, et de maintenir un cloisonnement de ces sessions. Ces mécanismes doivent apporter des garanties de confidentialité et d’intégrité des données privatives.

Les problématiques de sécurité qui doivent être gérées par l’application sont alors principalement les suivantes :

  • Chiffrement des flux - risques de vol de session par absence de chiffrement des flux HTTP : cette problématique relève non pas des développements applicatifs, mais de l’infrastructure technique mise en œuvre : tous les mécanismes de sécurité mis en œuvre dans l’application sont valides, du moment que le protocole HTTPS est utilisé, afin de garantir la confidentialité des échanges, et afin d’empêcher le vol d’informations par capture passive sur le réseau.
  • Phase d’authentification - risques de contournement de l’authentification : lors des traitements qui vérifient que l'identifiant et le mot de passe sont valides, l’application doit prendre en compte les problèmes posés par les caractères "à risques", qui pourraient perturber cette vérification. En particulier, une injection SQL réalisée lors de la phase d’authentification pourrait permettre à un attaquant de provoquer une authentification réussie, à tous les coups (cf. "injection SQL).
  • Phase d’authentification - divulgation d’informations sensibles : les messages d’erreur, en cas d’échec d’authentification, ne doivent pas permettre à un attaquant d’identifier l’existence de comptes valides (cf. "messages d’erreur).
  • Phase d’authentification - faiblesse des mots de passe : le niveau de robustesse minimal imposé par l’application aux mots de passe des utilisateurs devrait être en accord avec le niveau de sensibilité de l’application.
  • Gestion de session - risque de vol de session via un problème de gestion de "cookie" : le "cookie" de session doit être une valeur aléatoire, imprédictible. Si ce n’était pas le cas, alors il serait possible pour un attaquant de deviner la valeur des "cookies" d’autres utilisateurs, et par là même de voler la session courante de ces utilisateurs. Nota : Les "middleware" modernes, comme les environnements Java "servlet" ou .NET, fournissent toutes les primitives nécessaires à la gestion de "cookie" de session et de persistance de session. La sécurité de ces mécanismes est donc "garantie, du moment que le "middleware" est à jour en terme de correctifs de sécurité.
  • Gestion de session - risque d’accès à des données ou fonctions non autorisées via des données transmises via le client : Pour gérer la persistance d'une session, seul le mécanisme de "cookie" devrait être utilisé : le "cookie", positionné par le serveur puis transmis par le client à chaque requête, permet d’identifier l’utilisateur. Et côté serveur, les données propres à cet utilisateur sont stockées dans une table des sessions actives, indexée par la valeur du "cookie". Si on s’éloigne de ce principe de fonctionnement, alors on s’expose à des risques. Par exemple, l’identifiant interne de l’utilisateur, ou bien son nom, ne devraient pas se retrouver véhiculés via des requêtes HTTP, car ces informations sont connues de l’application, dès lors que l’utilisateur s’est authentifié. Si une fonctionnalité de l’application récupère ces données non pas côté serveur, mais côté client, alors il y a risque d’usurpation d’identité.
    • Par exemple :

        POST /myAppliServlet/ HTTP/1.1
        […]
        Cookie: JSESSIONID=QSKDFDFKLDSFL3CNVCOTP450ACNDREKXWN34SDOGDJKLZ40
        Content-Type: application/x-www-form-urlencoded
        Content-Length: 107

        FONCTION=afficheComptes&ident=Dupont

      Sur cet exemple, le paramètre "ident" est à risques : il représente l’identité de l’utilisateur courant, alors que cette identité est déjà connue de l’application.

      L’utilisateur "Dupont", s’il est mal intentionné, pourra alors fournir une autre identité, afin de se faire passer pour un autre utilisateur : 

        FONCTION=afficheComptes&ident=Durand

      Ici, si l’application n’effectue aucune vérification particulière, alors elle va utiliser l’identité "Durand" pour réaliser l’opération demandée (affichage des comptes).

      Sur cet exemple, il faudrait donc :

      • soit, supprimer l’utilisation du paramètre à risques "ident", et récupérer cette information côté serveur (au lieu de côté client),
      • soit, ajouter un test sur le paramètre "ident" : la valeur de "ident" doit être égale au nom de l’utilisateur, connu côté serveur.

3/ Le problème de contrôle d'accès

Principe : Les mécanismes de contrôle d'accès ont lieu après l'authentification de l'utilisateur et permettent de déterminer si un utilisateur donné est autorisé à accéder à certaines ressources. Un problème de contrôle d'accès va permettre à un attaquant authentifié d'accéder en lecture à des données non autorisées, mais peut également lui permettre de modifier ou détruire ces données, de réaliser des opérations nuisibles au niveau de l'application, voire de prendre le contrôle de cette dernière.

Solution :

  • Mettre en place, au niveau du site, une politique de sécurité permettant de gérer les contrôles d'accès de manière efficace. Concrètement, au début de chaque fonctionnalité élémentaire de nature privative, il convient de vérifier que :

    •  l’utilisateur demandeur est un utilisateur authentifié.
    • le profil de l’utilisateur demandeur lui autorise l’accès à cette fonctionnalité.
    • les paramètres de la requête sont dans le périmètre de l’utilisateur demandeur (exemple : le numéro du compte à débiter doit appartenir à l’utilisateur demandeur).
  • Par ailleurs, lorsque cela est possible, les paramètres doivent être gérés en relatif, par rapport aux données de session utilisateur gérées côté serveur, plutôt que dans l’absolu parmi toutes les données gérées par l’application. Par exemple, le compte à débiter devrait être représenté par un indice parmi la liste des comptes de l’utilisateur, plutôt que par le numéro de compte. Si l’application travaille avec des valeurs absolues, alors elle devra effectuer des vérification supplémentaires (exemple : le numéro du compte à débiter doit appartenir à l’utilisateur demandeur).

Sans risques

A risques

GET /myAppliServlet? FONCTION=virement&compteDebit=2

GET /myAppliServlet? FONCTION=virement&compteDebit=00010310264

4/ L'injection sémantique

Ces failles concernent les cas où les données envoyées par un pirate au système dans un contexte particulier contiennent une sémantique supplémentaire qui sera interprétée lors du traitement de ces données, mais dans un état non prévu à cet effet. Les données envoyées par l’utilisateur auront alors un sens pour une autre couche du système qui les interprétera.

Trois déclinaisons courantes de ce type de failles sont :

    •  les vulnérabilités de type "Cross Site Scripting" (les données envoyées par l’utilisateur contiennent du code HTML et des scripts),
    •  les vulnérabilités de type "SQL Injection" (les données envoyées contiennent des requêtes SQL),
    •  les vulnérabilités de type "Injection de code" (visant le système d’exploitation sur lequel tourne l’application).
  • Vulnérabilité de type "Cross-Site Scripting" (CCS)
  • Principe : De façon générique, le "Cross-Site Scripting" (voir l'article du bulletin de sécurité mensuel d'août 2001 du Cert-IST) correspond à l'action d'insérer des tags HTML ou scripts malicieux dans une page dynamique de l’application. L'exemple typique de "Cross-Site Scripting " est celui d'un attaquant qui envoie des scripts offensifs sur le poste d'un utilisateur victime, en utilisant la complicité involontaire d'un site web vulnérable. L'intérêt immédiat de cette attaque par rebond est que, contrairement au cas d'une attaque directe (cas où l'internaute victime visiterait un site pirate offensif), le site visité par la victime est à priori anodin, et l'utilisateur n'a donc pas de raison particulière d'être méfiant. De plus certains navigateurs web comme "Internet Explorer" permettent d'allouer des niveaux de confiances aux sites web. Ainsi, si un site web de confiance est vulnérable à un problème de type "CSS", il pourra être utilisé par un site malveillant pour exécuter sur le poste de la victime des scripts dans un contexte de confiance. Par ailleurs, ce type de vulnérabilité permet à l’attaquant de récupérer des données personnelles de la victime, dans le périmètre du site web vulnérable (par exemple, récupération du "cookie" de session, afin de voler cette session).

    Solution : L'effort de protection doit consister à pratiquer une programmation défensive : validation et filtrage systématique de toutes les données reçues de l'extérieur, même les plus anodines, le risque étant présent avec les données entrantes qui seront par la suite utilisées pour construire une page web résultante. Les données les plus à risques étant les caractères/mots <, >, ', ", "script", etc… 

  • Vulnérabilité de type "Injection SQL"
  • Principe : Les attaques de type "injection SQL" (voir l'article du bulletin de sécurité mensuel de février 2002 du Cert-IST) consistent à exécuter du code malveillant (requêtes SQL, ...) dans un serveur de base de données SQL, par le biais d'une application web faisant appel à cette base de données. Ces attaques reposent sur un mauvais contrôle des données envoyées par l'utilisateur ; ces données, si elles contiennent du code SQL, vont être transmises telles qu’elles au SGBD, ce qui va modifier la requête SQL, et donc provoquer un détournement de l’exécution de cette requête.

    Exemple :

    SELECT fieldlist
      FROM table
    WHERE field = '$EMAIL';

    Si un paramètre EMAIL est transmis tel quel au SGBD, alors ce paramètre pourra être utilisé par l’attaquant pour transmettre de la sémantique SQL

    SELECT fieldlist
      FROM table
    WHERE field = 'anything' OR 'x'='x';

    Solution : Il faut effectuer systématiquement (dans les programmes) un contrôle des données fournies par l'utilisateur (ou plus généralement reçues de l'extérieur), et interdire les caractères à risques, comme ' ou ; etc…

    Par ailleurs, suivant l’environnement "middleware" utilisé, des bonnes pratiques existent pour limiter ces risques. Par exemple, en environnement Java "servlet", il convient de programmer les appels vers les bases de données via des méthodes de la classe "PrepareStatement". 

  • Vulnérabilité de type "Injection de code"

    Principe : Les attaques "par injection" consistent pour un utilisateur à détourner le fonctionnement normal de l’application, en injectant des données ayant une sémantique particulière vis-à-vis de la plate-forme.

    Exemple : Modification d’une commande, invoquée via script, et dont la construction utilise des données provenant de l’utilisateur.

    Solution : Eviter l’appel de programmes externes à partir de scripts au niveau du serveur, surtout si les données saisies par l’utilisateur sont intégrées en tant que paramètres de ces commandes. Si l’utilisation de commandes externes est inévitable, contrôler les paramètres fournis par l’utilisateur. Concevoir l'application de façon à ce que les composants activés par l'utilisateur disposent du moins de privilèges possible. 

5/ Le débordement de pile

Principe : Lorsqu'un programme est lancé, un numéro de processus est alloué par le système et une zone mémoire est attachée à ce dernier. Il s'agit de la "pile". Lors de son exécution, le programme appelle un nombre important de fonctions pour son traitement. Effectuer un "débordement de pile" consiste à écraser l'adresse de retour d'une fonction appelée par le programme, en saturant la pile judicieusement, jusqu'à pouvoir atteindre ladite adresse de retour et la modifier par un pointeur de son choix. Ainsi, le programme reprend son exécution à l'adresse modifiée, qui peut contenir du code malicieux, et le cours du programme est détourné (voir l'article du bulletin de sécurité mensuel de mai 1999 du Cert-IST).

Nota : Cette problématique de débordement de pile a tendance à disparaître, avec l’avènement des serveurs d’application modernes, "de haut niveau". Par exemple, dans un environnement Java servlet, la problématique de débordement de pile n’est pas à prendre directement en compte dans les développements.

Solution : Effectuer systématiquement un contrôle sur la longueur des chaînes reçues par l'application web.

6/ La mauvaise validation des données reçues (vulnérabilité de type "format string")

Principe : Les applications web reçoivent des données en provenance des requêtes HTTP. Un attaquant peut donc se servir de ces requêtes (URL, en-têtes, "cookies", formulaires, champs masqués, etc...) afin de contourner les mécanismes de protection. Ce problème de validation des données conduisent à des vulnérabilités dans la gestion des chaînes de caractères ("format string"- voir l'article du bulletin de sécurité mensuel d'octobre 2000 du Cert-IST).

Nota : Cette problématique de "format string" a tendance à disparaître, avec l’avènement des serveurs d’application modernes, "de haut niveau". Par exemple, dans un environnement Java "servlet", la problématique de "format string" n’impacte pas l’environnement Java. 

7/ Le déni de service sur une application web

Principe : La majorité des applications web traitent en temps normal un grand nombre d'utilisateurs simultanés. Un unique attaquant pourrait pourtant générer assez de trafic pour provoquer l'arrêt d'une application, empêchant dès lors les autres utilisateurs de se connecter. Il pourrait également être possible à un attaquant d'empêcher l'accès aux ressources à un seul utilisateur, en faisant par exemple verrouiller son compte.

Cette problématique, dans une application web, résulte en général d’une mauvaise gestion des cas d’erreur, ou bien du fait que certains traitements soient trop gourmands en ressources et ne supportent pas la montée en charge.

Solution : Les moyens à mettre en œuvre pour lutter contre les dénis de service au niveau applicatif se rapprochent de la qualité, dans le sens où il ne s'agit pas seulement d'un problème de sécurité, mais surtout d'un problème de conception/développement pour lequel des recommandations de qualité de service doivent être appliquées.

8/ La mauvaise configuration d'une application web

Principe : La mauvaise configuration d'une application ou d'un serveur web peut entraîner un grand nombre de failles de sécurité. Parmi ces problèmes, on retrouve les vulnérabilités de sécurité non corrigées, les failles de types "traversée de répertoire", l'utilisation de pages par défaut ou de fichiers d'exemple, la mauvaise gestion des permissions, l'ouverture de services non utiles (administration distante par exemple), les comptes par défaut (avec les mots de passe par défaut), les messages d'erreur trop verbeux, une mauvaise configuration du chiffrement SSL, l'utilisation de certificats auto-signés, l'utilisation de certificats par défaut, etc...

Nota : On s’éloigne ici des problématique de sécurité liés à l’application ; il s’agit de mesures portant sur la configuration des services. 

9/ Le défaut d'auditabilité

Principe : Une application est sujette à un défaut d’auditabilité lorsqu’il est impossible d’obtenir des informations sur l’utilisation qui en est faite. Il ne sera alors pas possible de détecter les utilisations ou tentatives d’utilisation frauduleuse de l’application ou d’investiguer sur un problème de sécurité constaté sur l’application.

Solution : Mettre en oeuvre des mécanismes de journalisation au niveau de l’application : au delà de la journalisation du serveur web et serveur d'application, l’application doit journaliser les événements applicatifs nécessaires : identification réussie, échouée, déconnexions, mises à jour de données sensibles, ....

 

B/ Recommandations et outils disponibles

Outre les recommandations effectuées dans cet article, il est essentiel de maintenir les systèmes à jour en terme de correctifs de sécurité (applications, mais également système d'exploitation, réseau, garde-barrière, anti-virus).

Il existe également des documents de type "check-list" donnant des recommandations sur les méthodes de programmation sécurisée des applications web. En voici une liste non exhaustive :

Documents généraux :

Documents concernant les différents serveurs d’applications web :

Une liste Bugtraq dédiée à la sécurité permet de surveiller les dernières vulnérabilités et de s'informer sur la sécurisation web (http://www.securityfocus.com/archive/107).

Des outils sont également disponibles afin d'aider les développeurs à sécuriser leurs applications et serveurs web :

 

C/ Pour plus d'information

Précedent Précedent Suivant Suivant Imprimer Imprimer