Passer au contenu principal

Dans cette série d’article nous allons parler de bonnes pratiques visant à sécuriser les applications web. En effet, pour la plupart d’entre elles, la seule « sécurité » consiste à demander un login/mot de passe puis à prier pour que l’utilisateur n’aille pas trafiquer les URLs pour débusquer les failles.
Note : cette série d’article n’a absolument pas vocation à être exhaustive, mais plutôt de vous donner quelques concepts de base. Pour ceux qui veulent approfondir, vous pouvez notamment lire cet ouvrage.

Dans ce premier article de la série nous allons parler de la manière de sécuriser une application au niveau du code.

Le mécanisme d’authentification

Le mécanisme d’authentification d’un utilisateur se déroule toujours en deux temps :

  1. Tout d’abord l’utilisateur rentre des informations permettant de l’authentifier. L’application va vérifier auprès d’un dictionnaire LDAP, ou de tout autre mécanisme permettant de vérifier ces informations.
  2. Une fois cette opération effectuée avec succès, l’application va déterminer quels droits ont été affectés à l’utilisateur. A noter qu’à chaque fois que celui-ci effectue une action côté serveur, il est nécessaire de s’assurer, toujours côté serveur, que l’utilisateur qui l’effectue a bien le droit de la réaliser. Si ce n’est pas le cas, il faut renvoyer un code d’erreur 403. En effet, si aucun contrôle n’est effectué côté serveur, un utilisateur connecté pourrait tout à fait invoquer des actions sans que le serveur ne le voit, et attaquer l’application comme cela. De manière générale, pour toute action du client, le serveur doit appliquer la règle never trust your input, ça évite bien des ennuis.

Dans la suite nous explorerons plus en détail les différents mécanismes d’autorisation.

Les rôles

Les rôles servent à déterminer quel utilisateur a le droit d’invoquer telle ou telle action. Par exemple, on pourra imaginer que les administrateur d’une application ont le droit de lister, ajouter, modifier ou enlever des utilisateurs. Dès lors, chacune des actions ici citées devra vérifier que l’utilisateur qui l’invoque a bien le rôle administrateur.

Il s’agit là d’un mécanisme simple à implémenter avec les frameworks existants, néanmoins il n’est pas toujours suffisants. Ci-dessous quelques frameworks permettant la sécurisation par rôle :

  • Spring Security
  • Les EJB dans la specification JEE

A noter que pour gérer les rôles, un annuaire de type LDAP est parfaitement indiqué, étant donné qu’on peut y affecter des utilisateurs à des groupes, lesquels représentent les rôles de notre application.

Les listes de contrôles d’accès (ACL)

Les listes de contrôles d’accès (ACLs) permettent de spécifier, pour une action donnée, à quels éléments on a le droit d’accéder.

Imaginons le cas d’une application de stockage de fichiers de type DropBox. Quand l’utilisateur va sur l’application web ou télécharge des fichiers, le serveur doit, avant d’autoriser le transfert, s’assurer que le fichier est bien accessible pour l’utilisateur qui le demande.

Typiquement, un système d’ACLs contiendra un certain nombre de droits dont les plus courants sont :

  • Lire l’élément
  • Modifier l’élément
  • Supprimer l’élément

Une implémentation efficace d’un tel mécanisme passe par un système de proxys : quand la couche web invoquer un service métier, le proxy va vérifier, avant, pendant ou après l’invocation du service, que l’utilisateur a bien le droit d’effectuer l’action demandée. Typiquement, le proxy en question appellera un service dont le rôle est d’effectuer le contrôle. A noter que c’est une mauvaise idée de vérifier la sécurité au sein même des services, car dans certains cas vous pouvez avoir besoin d’appeler l’un d’entre eux sans qu’un contrôle ne soit effectué.

Pour ceux qui savent lire du PHP, Symfony 2 fournit un très bon exemple d’implémentation d’un tel service, la documentation étant ici.

Autres failles de sécurité les plus courantes (et leur remède)

Dans cette partie nous couvrons quelques unes des failles de sécurité les plus courantes, ainsi que le moyen de les éviter. Attention, cette liste ne prétend pas être exhaustive.

Les injections SQL

Les injections SQL consistent à injecter un bout de requête SQL dans un champ afin de détourner celui-ci de son rôle premier. Le client peut ainsi faire apparaître des informations auxquelles il n’aurait pas accès normalement, ou faire des modifications non autorisées en base.

Ce type de faille est très simple à éviter :

  • Tout d’abord l’application ne doit en aucun cas permettre l’incorporation de morceaux de SQL du client dans ses requêtes, par exemple pour des champs de recherche complexe. Ca va peut-être vous amuser, mais j’ai déjà vu ça !!!
  • Ensuite, il convient d’utiliser systématiquement des PreparedStatement et non des Statement tout simples pour toutes les requêtes paramétrées : parce que dans certains cas les performances peuvent être améliorées mais surtout parce qu’elles sont plus sécurisées. Exemple de requête sans preparedstatement et avec, pour rechercher un élément dans la table ‘foo’ par son nom :
    • Sans PreparedStatement : 'SELECT * FROM foo WHERE name = "' + inputUser + '"'
    • Avec PreparedStatement : 'SELECT * FROM foo WHERE name = ?'. Ici, le ‘?’ sera substitué en invoquant la méthode ps.setString() de l’interface PreparedStatement.

    Maintenant supposons qu’un utilisateur malveillant entre comme valeur " OR 1=1 OR name=". Oui c’est tiré par les cheveux mais c’est comme ça que fonctionnent les injections. Sans PreparedStatement, notre requête sera interprétée par le SGBD comme SELECT * FROM foo WHERE name = "" OR 1=1 OR name="" et remontera l’intégralité du contenu de la table. Dans le deuxième cas, notre requête sera interprétée comme SELECT * FROM foo WHERE name = "\" OR 1=1 OR name=\"" et ne retournera cette fois-ci que l’enregistrement dont le champ name vaut ce que l’utilisateur a entré.

Les attaques de type XSS/Cross scripting

<

p>Les attaques de type XSS/Cross scripting consistent à insérer du code HTML dans une page web en détournant l’application de son rôle initial.

<

p>

Par exemple, on peut envisager un utilisateur qui rentre dans un formulaire de données et enregistre la valeur suivante :

<iframe src="http://www.google.com" width="500" height="650"></iframe>

Si aucun contrôle n’est effectué, l’utilisateur qui affichera les données du formulaire verra un joli lien vers la page d’accueil de Google. Cet exemple n’est pas bien méchant, à part qu’on peut s’en servir pour défigurer un site, mais à la place de celui-ci on pourrait invoquer un script Javascript qui est chargé de voler le cookie du navigateur, et voler ainsi la session de l’utilisateur !

Il est aussi assez simple d’éviter ce problème, en Java avec la librairie Apache commons-lang, classe StringEscapeUtils.

Autres failles

Parmi les failles les plus courantes on trouve :

  • Le Cross-site request forgery qui vise à faire déclencher par un utilisateur une action indésirable. Rejoint par certains points le XSS.
  • Pour certaines technos, la non-validation d’URLs, notamment en PHP.

Pour une liste plus complète, voir ce lien.

Protéger sa base de données

Malgré toutes les protections mises en place, dans certains cas des pirates peuvent réussir à s’introduire sur votre système d’informations pour y récupérer des données. On pourra citer notamment les attaques dont ont récemment été victimes Adobe, Steam ou encore Sony via son Playstation Network.

Si un tel cas survient, il s’agit de limiter la casse en ralentissant l’exploitation par les pirates des données sensibles, permettant ainsi à vos utilisateurs de modifier ces dernières afin de prévenir toute exploitation.

Pour ce faire, il est important d’appliquer un salt : il s’agit d’un hachage aléatoire qui est généré au moment où l’utilisateur crée la donnée sensible comme un mot de passe. Ce dernier doit être unique, et

surtout pas réutilisé pour différents enregistrements d’une même table

. En effet, une attaque commune est là rainbow table, qui permet à des pirates de retrouver en très peu de temps un maximum d’informations. Le salt, bien appliqué permet de s’en protéger, mais si le même salt est appliqué partout il suffit aux pirates de régénérer la rainbow table avec le bon salt pour parvenir à leurs fins.

Julien
Moi c’est Julien, ingénieur en informatique avec quelques années d’expérience. Je suis tombé dans la marmite étant petit, mon père avait acheté un Apple – avant même ma naissance (oui ça date !). Et maintenant je me passionne essentiellement pour tout ce qui est du monde Java et du système, les OS open source en particulier.

Au quotidien, je suis devops, bref je fais du dév, je discute avec les opérationnels, et je fais du conseil auprès des clients.

Son Twitter Son LinkedIn

Laisser un commentaire