Découvrez les sessions
Pourquoi implémenter une session ?
Pour autant, il est intéressant de savoir où votre utilisateur est allé dans votre site ou d’où il vient, ou bien encore ce qu’il a ajouté à son panier afin de pouvoir utiliser ses informations plus tard.
Malheureusement, le protocole HTTP ne possède pas de mécanisme natif de maintien de l’état mais il peut le simuler en utilisant des sessions.
Qu’est-ce qu’une session ?
ll s’agit d’un espace mémoire alloué pour chaque utilisateur, permettant de sauvegarder des informations tout au long de sa visite. Elle permet au client OU au serveur de mémoriser des informations relatives à l’utilisateur. Ce contenu est conservé jusqu’à ce que l’utilisateur ferme son navigateur ou reste inactif trop longtemps, ou lorsqu’il se déconnecte du site.
Implémentez une session
L’implémentation peut être faite de 3 manières :
Côté client par l’URL, en utilisant la Storage API HTML5 ou par cookies ;
Côté serveur en mémoire applicative ou en mémoire distribuée ;
En base de données.
Quelle que soit la manière de la stocker, l’application qui gère la session crée souvent un identifiant de session unique et peu prédictible (par exemple 121DFD2149687TRE
). Cet identifiant permet de retracer l’activité d’un utilisateur sur les pages d’un site, par exemple.
La faiblesse des sessions
Vous l’aurez compris, la gestion de session est nécessaire pour suivre l’état de la connexion d’un utilisateur dans une application web. La problématique est de concevoir un système de gestion de session sécurisée qui doit empêcher les fuites de données vers des utilisateurs malveillants, exposant les applications à des attaques classiques.
Exemple d'attaque, le vol de session par fixation
Imaginons la situation suivante :
Dans une application de type réseau social, le transfert des identifiants de session se fait dans l’URL avec la méthode GET. Par exemple :
http://www.applicationpeusecurisee/?sessionid=46546SDFFQ
Un utilisateur malveillant remarque ce fonctionnement et envoie donc un message sur le réseau à un autre utilisateur en écrivant :
Hello X ^^, connecte-toi, il faut que je te parle. Voici le lien :
http://www.reseausocialpeusecurise/?sessionid=123456
Notre utilisateur victime va cliquer sur le lien avec cet identifiant de session figé. L’attaquant n’aura plus qu’à se diriger vers le lien et bénéficiera des droits de la victime.
Cette attaque de vol de session est appelé attaque par fixation de session.
Prenez garde aux frameworks
Bien évidemment, la plupart des frameworks implémentent leur propre système de gestion de sessions. En tant que développeur, vous ne devriez pas avoir une confiance aveugle dans ces outils. Même si ces frameworks sont écrits pour convenir à la majorité des cas d’utilisation possibles, ils peuvent contenir des bugs, être partiellement complets ou bien ne pas être à jour. Il est donc important que les concepteurs s’interrogent sur :
La capacité de leurs outils à implémenter les bonnes pratiques développées ci-dessous ;
La cohérence entre les exigences de sécurité et l’implémentation du framework utilisé.
Les sessions sont un élément important dans le monde du Web, car elles permettent d’enrichir le comportement sans état et déconnecté du protocole HTTP. Les développeurs ont donc du mal à s’en passer. Néanmoins, l’exemple précédent met en évidence le besoin de sécurisation du système de session.
Mais comment fait-on concrètement ?
Mettez en place les bonnes pratiques
Générez un identifiant de session avec la cryptographie
Une manière répandue de stocker les données de session est de les persister sur le serveur (cas de l'implémentation côté serveur) puis de générer un identifiant de session que l’on stocke dans un cookie.
Pour savoir si vous êtes vulnérable à la prédiction des identifiants de session, vous pouvez essayer d’en forger une grande quantité (1 000 par exemple) en peu de temps et de les porter sur un graphique pour voir s'ils sont facilement prévisibles. Dans ce cas, je vous conseille d’utiliser une bibliothèque reconnue comme solide, et de lier l’obtention de l’id de session à l’adresse IP du client par exemple.
En PHP, forgez la session au plus tôt
Pourquoi procéder ainsi ?
Si PHP utilise les cookies pour repérer quel est l'identifiant de session utilisé par votre utilisateur, il va écrire cet identifiant de session dans un cookie. Or, le fonctionnement du protocole HTTP prévoit que les en-têtes (qui permettent de dire à votre navigateur « Crée un cookie ayant tel nom et telle valeur ») sont envoyés avant le premier caractère HTML transmis.
Donc, dès que vous envoyez un caractère HTML, les en-têtes seront envoyés et vous ne pourrez plus les modifier. Il ne sera donc plus possible d’écrire le cookie de session.
Stockez les données de vos sessions au bon endroit
Vous vous en souvenez, dans l’introduction au mécanisme de session, il existe 3 possibilités pour stocker les informations de session. Une bonne pratique consiste à stocker dans le cookie uniquement l’identifiant de session puis les informations de session, soit côté serveur, ou bien dans la base de données.
Vérifiez les informations que vous stockez et qui peut les voir
Vous l’aurez compris, intégrer un mécanisme de sessions comporte une certaine charge supplémentaire dans l’application. Une bonne pratique est de ne garder que le strict minimum dans la session. Les champs cachés de l’HTML sont une mauvaise pratique, car ils sont visibles de tous. Dans ce cas, s’il s’agit d’une données secrètes, il est plus sécurisé de les placer en session ou dans une base de données.
Utilisez des cookies « HTTP Only »
Pour éviter que les cookies de sessions ne soient pas accessibles en Javascript, les frameworks utilisés ou le développeur d’application doit mettre par défaut la propriété HTTPOnly
des cookies à true
. Cette méthode permet de préciser au navigateur que le cookie ne peut pas être utilisé par Javascript pour lire la session d’un autre utilisateur qui naviguerait sur un site contenant un logiciel malveillant.
Utilisez des cookies « SSL Only »
Il est aussi recommandé, quand cela est possible, de mettre la propriété Secure
à true
pour obliger l’accès à ce dernier seulement via HTTPS. Cela permet d’éviter les attaques du type homme du milieu.
Fixez une fin de validation de session
Dans la mesure du possible, il est aussi nécessaire de contraindre la durée de vie d’une session à une durée maximale. En général, la valeur de 15 minutes est conseillée. La plupart des frameworks possèdent cette fonctionnalité. Par exemple, en .NET, c’est le but de la fonction Session.timeout
.
On recommande aussi de prévoir la destruction de session à la fermeture de la page ou à la déconnexion.
Utilisez les jetons CSRF
Imaginons la situation suivante :
Je suis administrateur sur un blog. Je peux donc ajouter, modifier voire supprimer des articles. Un autre utilisateur n’a évidemment pas ces droits d’administration. Mais cet autre utilisateur peut récupérer l’adresse URL qui permet de faire ces opérations, et m’envoyer un message privé avec une image dont l’adresse pointe vers la page de suppression d’articles.
Si j’essaie d’afficher l’image, le navigateur se rend sur la page web de suppression et l’exécute. Ça marche puisque j’étais connecté comme administrateur et que j’ai affiché cette page pour laquelle j’avais les droits.
Qu’est-ce qu’un jeton ?
Il s’agit d’un nombre ou d’une chaîne de caractères aléatoires qui sera testée avant toute modification d’une donnée. Elle est souvent calculée grâce à une fonction de hachage (MD5 par exemple). En PHP, par exemple, on peut la créer de cette façon :
<?php md5(bin2hex(openssl_random_pseudo_bytes(6))); ?>
qui utilise une fonction qui génère une chaîne pseudo aléatoire ensuite convertie en hexadécimal.
Cette méthode est souvent doublée d’une demande de confirmation de suppression, afin de renforcer l’effet sécurisant.
En résumé
Dans ce chapitre, nous avons vu ensemble l’importance de la gestion des sessions dans une application web et quelles sont les bonnes pratiques à mettre en oeuvre pour les sécuriser.
Dans la prochaine partie, je vous invite à approfondir un deuxième axe qui mérite toute votre attention : celui des données.