Sesssion en PHP. Bonnes pratiques.

mieux protéger une application internet

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com
La bienveillance de la session connaissent tous les programmeurs du PHP. Facile à implémenter dans la gestion des utilisateurs, mais très fragile aux attaques. Or le vol ne s'applique pas qu'aux voitures.

A travers cet article vous allez pouvoir connaître les dangers auxquels sont exposées les données de la session. Dans un deuxième temps vous pourrez voir quelques bonnes pratiques de l'utilisation des sessions en PHP, telles que:
1) The fingerprinting
2) Régénération de l'identifiant
3) L'ajout du sel
4) Le stockage de la session
5) Le cryptage
6) Httponly
7) Le temps de vie d'une session

Dangers de la session
L'une des attaques principales s'appelle session hijacking. Elle consiste à détourner l'identifiant de la session de l'utilisateur. L'attaquant qui possède un identifiant de la session peut facilement obtenir l'accès à la session entière de l'utilisateur. Cette attaque est possible lorsque l'application n'est pas protégée contre les attaques XSS (Cross Site Scripting). L'attaquant peut également écouter la transmission des données entre l'utilisateur et le serveur. L'identifiant est alors transmis sans cryptage (sauf que la connexion utilise SSL).

Une autre type d'attaque s'appelle session fixation. Il s'agit ici de forcer la victime à utiliser l'identifiant de la session créé par l'attaquant. Tout d'abord l'attaquant prépare un identifiant à envoyer. Après il se charge de le transmettre à la victime. La transmission peut aussi utiliser la vulnérabilité de l'application aux attaques XSS. Ou, tout simplement, la victime peut cliquer sur le lien passé par l'attaquant. Dès qu'elle se connecte en utilisant le faux identifiant, l'agresseur peut également être connecté à l'application.

Le troisième type de l'attaque, session injection, consiste à modifier les données qui sont dans la session. Cette vulnérabilité est due à l'enregistrement non autorisé des changements dans les fichiers de la session. Afin que l'attaque soit réalisable, elle doit remplir deux conditions. Tout d'abord, les variables de la session doivent être initiées ou éditées par les données issues de l'utilisateur. Deuxièmement, la validation de ces données doit être insuffisante.

Bonnes pratiques
1) The fingerprinting
Autrement dit, une empreinte de l'utilisateur, qui protège contre sesssion hijacking. Il s'agit ici de créer une variable de la session contenant des données uniques pour chaque internaute connecté à l'application. Elles devraient être cryptées pour rendre la défense moins vulnérable. Il peut s'agir d'une chaîne de caractères composée de l'IP de l'internaute et de son navigateur.

2) Régénération de l'identifiant
Une autre méthode de protection consiste à la régénération de l'identifiant de la session. Comme cela laisse supposer, c'est un moyen de protection contre session hijacking. PHP fournit une fonction qui est censée d'exécuter cette opération. Il s'agit de session_regenerate_id.

Normalement elle devrait être appelée à chaque fois où l'utilisateur change le niveau d'accès. Cela veut dire, par exemple, la régénération au moment de la connexion, de la déconnexion ou de l'accès à la partie administrative.

Les personnes plus soucieuses peuvent ajouter une rotation qui va se baser sur un test. Par exemple, le test peu vérifier si le chiffre aléatoire (disons entre 1 et 3000) est divisible par 2 ou pas. Si c'est le cas, l'application web régénère l'identifiant. Sinon, elle le laisse sans changements.

Il y a encore un autre moyen d'utiliser cette fonction en l'appelant à chaque rechargement de la page. Cependant, il faut inclure dans ce cas une éventuelle baisse de la performance de notre application web.

3) L'ajout du sel
Cette méthode n'est pas directement liée à la fragilité de la session. Néanmoins, il peut s'avérer que les données reprises par l'attaquant vont contenir les informations utilisées par l'utilisateur pour s'identifier dans l'application.

Si l'on est obligé de garder dans la session des données comme le mot de passe (crypté bien évidement), il vaut mieux qu'elles soient « salées ». Il s'agit d'attacher un mot connu uniquement par le développeur de l'application, au mot de passe ou autres données vulnérables.

4) Le stockage de la session
Parfois ce n'est pas notre application qui est dangereuse pour l'utilisateur mais la configuration du serveur. Surtout, quand on est obligé d'utiliser une offre mutualisé (plusieurs clients sur une seule machine).

Dans ce cas une des recommandations est de stocker les données de la session dans la base de données et non pas dans les fichiers sur le serveur. Cependant, cette solution est conseillée uniquement pour les applications web dont l'objectif principal n'est pas la performance (lesquelles donc ?). Or la lecture et l'écriture des données lors d'une activité important sur notre site, peuvent ralentir l'exécution d'autres opérations. Particulièrement quand on est sur le serveur mutualisé.

5) Le cryptage
Potentiellement, l'attaquant peut deviner l'identifiant de la session. Il peut consulter l'algorithme utilisé pour la création de l'identifiant dans les fichiers source du PHP.

Dans ce cas on peut écrire un générateur des identifiants. Sinon, on peut également configurer PHP afin qu'il crée l'identifiant de la manière un peu moins habituelle. On peut réussir cela grâce aux directives session.entropy_file et session.entropy_length. Que font-elles ?

La directive session.entropy_file signifie le nom du fichier externe qui sera utilisé pour la génération de l'identifiant de la session. Quant à session.entropy_length, il définit le nombre des bytes qui sont lus du fichiers spécifié dans session.entropy_file.

6) Httponly
C'est le paramètre qui indique au navigateur de ne pas permettre à aucun langage du côté client (comme JavaScript) d'accéder à l'objet document.cookie. Cette option a été ajoutée dans la version 5.2 du PHP dans la fonction setcookie.

Cependant, les utilisateurs de < PHP 5.2 ne doivent pas s'inquiéter. Comme l'indique Ilia Alshanetsky sur son blog (httpOnly cookie flag support in PHP 5.2), il est possible de l'envoyer dans header().

Malheureusement, ce n'est pas la solution miracle. Il faut toujours prendre en compte les navigateurs qui ne supportent pas httpOnly. Ensuite, il faut encore se protéger contre la lecture du cookie avec la méthode TRACE (Cross Site Tracing – XST). La solution consiste à créer une règle de rewriting:


RewriteEngine On
RewriteCond %{REQUEST_METHOD} ^TRACE
RewriteRule .* - [F]


7) SSL
Afin de ne pas permettre à l'attaquant d'écouter la transmission des données entre l'internaute et le serveur de notre application web, on peut utiliser les protocoles plus sécurisés que http.


Cependant, rien ne vous garantit que votre application web sera pleinement protégée. Comme vous avez pu observer dans l'article, le processus de sécurisation de l'application est complexe. Il suffit de rater un élément (voir rapport entre XSS et session hijacking) afin de gâcher tout l'effort de protection.

L'article écrit en rythme de:
Les Déesses ft Papa Tank - Danse Avec Moi
Bartosz KONIECZNY 14-12-2010 19:13 sécurité des applications web
Moi

Développeur d'applications Internet et journaliste passionné par l'adjectif français. Un aigle polonais orienté vers la progression, volant très haut et écoutant du zouk après les matches du foot français.

Vous appréciez mon travail ?

Pour contribuer au développement de ce site, ou pour remercier pour des articles rédigés, vous pouvez faire un don.

Un conseil PHP

Comment créer une signature pour OAuth

La création d'une signature (paramètre oauth_signature) pour la requête OAuth est réalisée avec l'algorithme HMAC-SHA1. Son implémentation chez PHP se présente ainsi :

hash_hmac('sha1', "Message to hashed", "Secret key", true)
Le résultat de cet algorithme doit ensuite être encodé avec Base64. Un exemple d'utilisation chez le protocle OAuth peut se présenter de la manière suivante :
public function getSignature($baseString, $signatureKey)
{
  return base64_encode(hash_hmac('sha1', $baseString, $signatureKey, true));   
}