4.7.1 Tester le système de management des sessions (OTG-SESS-001)

Sommaire
Pour éviter que l'utilisateur ait à se ré-authentifier sur chaque page d'un site web ou d'un service, les applications web implémentent des mécanismes pour stocker et valider les crédentiels, et ce, pour un temps donné. Ces mécanismes sont connus sous le nom de management ou gestion de sessions. Bien qu'ils soient important pour améliorer l'expérience utilisateur, ils peuvent être exploités par un testeur d'intrusion pour accéder à un compte utilisateur, sans avoir besoin de donner les crédentiels nécessaires.

Dans ce test, le testeur va vérifier que les cookies et autres jetons de session sont créés de manière sûre et aléatoire. Un attaquant qui est capable de prédire et de fabriquer un cookie faible peut aisément détourner les sessions des utilisateurs légitimes.

Les cookies, décrits en détail dans la RFC 2965, sont le plus souvent utilisés pour implémenter la gestion de sessions. En bref, lorsqu'un utilisateur accède à une application qui a besoin de gérer des sessions et l'identité des utilisateurs, le serveur génère un (ou plusieurs) cookie et l'envoit au client. Le client renverra ce (ou ces) cookie au serveur à chaque connexion jusqu'à ce que le cookie atteigne sa durée de vie ou soit détruit. Les données stockées dans le cookie indiqueront beacuou d'informations au serveur : qui est l'utilisateur, quelles actions a-t-il faites jusqu'ici, quelles sont ses préférences, etc. Ainsi un protocole comme HTTP n'est plus sans état.

Un panier de courses en ligne est un parfait exemple de cela. Tout au long de la session d'un utilisateur, l'application garde la trace de son identité, de son profil, des produits qu'il a mis dans son panier, des quantités, des prix, des remises, etc. Les cookies sont un moyen efficace d'échanger des informations entre client et serveur (d'autres méthodes existent : paramètres d'URL ou champs cachés).

Du fait de l'importance des données qu'ils contiennent, les cookies sont vitaux pour la sécurité générale d'une application. En falsifiant des cookies, on peut détourner les sessions d'utilisateurs légitimes, escalader en privilège dans une session existante, et de manière générale influencer le comportement de l'application de manière frauduleuse.

Dans ce cadre, le testeur va vérifier si les cookies envoyés aux clients peuvent résister à une large gamme d'attaques destinées à interférer avec les sessions des utilisateurs légitimes et avec l'application elle-même. Le principal but est de générer un cookie qui sera considéré comme valide par l'application et qui octroira des accès non autorisés (détournement de session, escalade de privilèges, ...).

Généralement les principales étapes du schéma d'attaque sont les suivantes :
 * collecte de cookies : collecte d'un échantillon de cookies suffisamment important ;
 * rétro-ingénierie de cookies : analyse de l'algorythme de génération des cookies ;
 * manipulation de cookies : construction d'un cookie valide pour mener l'attaque à bien. Ce dernier point peut demander un grand nombre d'essais, selon la façon dont sont générés les cookies (cookie brute-force attack).

Un autre mode d'attaque est possible : le débordement de cookie. C'est une attaque de nature différente, puisqu'ici on ne cherche pas à générer un cookie valide. Au lieu de cela, le but est de déborder une zone mémoire, et ainsi de déclencher un comportement non-prévu de l'application. Ainsi, il peut être possible d'injecter (et d'exécuter à distance) du code malicieux.

Exemples et tests en black box
Chaque interaction entre client et serveur doit être testée selon au moins un des critères suivants :
 * Est-ce que tous les cookies ont l'option Secure ?
 * Est-ce que le cookie peut être transporté en clair (non chiffré) ?
 * Est-ce que l'on peut forcer le transport non chiffré du cookie ?
 * Si oui, comment l'application assure-t-elle la sécurité ?
 * Est-ce que les cookies sont persistents ?
 * Quelle est la durée de persistence des cookies ? Est-elle raisonnable ?
 * Est-ce que les cookies prévus pour être transient sont définis comme tel ?
 * Quels paramètres Cache-Control sont utilisés pour protéger les cookies en HTTP/1.1 ?
 * Quels paramètres Cache-Control sont utilisés pour protéger les cookies en HTTP/1.0 ?

Collecte de cookies
La première étape pour manipuler un cookie est de comprendre comment l'application le génère et le gère. Pour cela, les testeurs doivent essayer de répondre aux questions suivantes :

Naviguez sur l'application. Notez quand les cookies sont créés. Faites une liste des cookies reçus, incluant la page qui les génère (directive set-cookie), le domaine pour lequel ils sont valides, et leurs caractéristiques. En navigant sur l'application, trouvez quels cookies restent constants, et lesquels sont modifiés. Quel événement modifie un cookie ? Trouvez quelles parties de l'application nécessite un cookie. Accédez à une page, et essayez encore sans le cookie, ou avec une version modifiée de celui-ci. Essayez de cartographier quels cookies sont utilisés où.
 * Combien de cookies sont utilisés par l'application ?
 * Quelle partie de l'application génère et/ou modifie le cookie ?
 * Quelles parties de l'application nécessite ce cookie pour être accessible et fonctionner ?

Une feuille de calcul listant la correspondance de chaque cookie avec les parties de l'application les utilisant, et les informations concernées peut être un résultat de grande valeur, lors de cette étape.

Analyse de session
Du point de vue de la sécurité, les jetons de session (cookie, SessionID, champs cachés) eux-mêmes doivent être examinés pour s'assurer de leur qualité. Ils doivent être testés selon des critères comme l'entropie, l'unicité, la résistance à l'analyse statistique et cryptographique, et les fuites d'informations.

La première étape est d'examiner la structure et le contenu d'un identifiant de session fourni par l'application. Une erreur classique est d'inclure des données spécifiques dans le jeton, au lieu de produire une valeur générique et de référencer les données significatives côté serveur.
 * Structure des jetons & fuite d'information

Si l'identifiant de session est en clair, la structure et les données pertinentes sont immédiatement accessibles : 192.168.100.1:owaspuser:password:15:58

Si une partie ou le jeton entier apparaît comme encodé ou hashé, il faut le comparer avec des techniques évidentes d'obfuscation. Par exemple la chaîne "192.168.100.1:owaspuser:password:15:58" convertie en Hexa, Base64, et MD5 : Hex	3139322E3136382E3130302E313A6F77617370757365723A70617373776F72643A31353A3538 Base64	MTkyLjE2OC4xMDAuMTpvd2FzcHVzZXI6cGFzc3dvcmQ6MTU6NTg= MD5	01c2fc4f0a817afd8366689bd29dd40a

Après avoir identifié le type d'obfuscation, il peut être possible de décoder la donnée originale, bien que dans la plupart des cas ce soit peut probable. Par contre il peut être utile de déterminer l'encodage à partir du format du message. En outre, si le format et la méthode d'obfuscation peuvent être déterminés, une attaque automatisée en brute force peut être mise au point.

Des jetons hybrides peuvent contenir différentes informations, comme l'adresse IP, l'identifiant utilisateur, ainsi qu'une portion codée : owaspuser:192.168.100.1: a7656fafe94dae72b1e1487670148412

Après analyse d'un premier jeton de session, un échantillon représentatif doit être examiné. Une simple analyse des jetons doit révéler immédiatement tout schema évident. Par exemple un jeton de 32 bits peut contenir 16 bits de données statiques et 16 bits de données variables. Cela peut indiquer que les 16 premiers bits représentent un attribut fixe lié à l'utilisateur, par exemple son identifiant ou son adresse IP. Si le second groupe de 16 bits est incrémenté d'une manière régulière, cela peut indiquer que c'est une séquence ou une valeur liée au moment de la génération du jeton.

Si des éléments statiques ont été identifiés dans le jeton, d'autres échantillons doivent être collectés, en faisant varier une valeur à chaque fois. Par exemple, des essais de connexion avec un compte différent, ou depuis une adresse IP différente, peuvent indiquer une variance dans des parties du jeton auparavant statiques.

Les questions suivantes devraient être adressées lors du test de structure d'identifiant de session unique ou multiple :
 * Quelles parties de l'identifiant de session sont statiques ?
 * Quelles information confidentielles sont stockées en clair dans l'identifiant de session ? Ex: identifiant utilisateur/UID, adresse IP.
 * Quelles informations confidentielles sont facilement décodables ?
 * Quelles informations peuvent être déduites de la structure de l'identifiant de session ?
 * Quelle portions de l'identifiant de session sont statiques dans les mêmes conditions de connexion ?
 * Quels schemas évidents sont présents dans l'identifiant de session, ou dans des parties de ce dernier ?

prévisibilité et entropie de l'identifiant de session
Une analyse de la partie variable (si elle existe) de l'identifiant de session est nécessaire pour démontrer l'existence de valeurs reconnaissables et prévisible. Ces analyses peuvent être faites manuellement avec des outils spécifiques, ou statistiques/cryptanalitiques, pour déduire tout motif présent dans l'identifiant de session. Ces vérification manuelles doivent comprendre des comparaisons d'identifiant de session générés dans les mêmes conditions de connexion (même identifiant, mot de passe, adresse IP, ...).

Le temps est aussi un facteur qui doit être contrôlé. Il faut faire un grand nombre de connexions dans la même fenêtre temporelle et garder cette variable constante. Même une répartition sur 50ms ou moins peut s'avérer trop large, et empêcher l'échantillonage de montrer des composants basés sur le temps.

Les éléments variables doivent être analysés sur la durée pour déterminer s'ils sont de nature incrémentale. S'ils sont incrémentaux, les motifs liés au temps absolu ou relatif doivent être examinés. Beaucoup de systèmes utilisent le temps pour l'initialisation de générateurs pseudo-aléatoires. Quand les motifs semblent aléatoires, des hash à sens unique ou d'autres variations d'environnement doivent être considérés comme possible. Généralement, le résultat d'un hash cryptographique est un nombre décimal ou hexadécimal qui devrait être identifiable.

Lors de l'analyse d'identifiant de session, les séquences, motifs ou cycles, éléments statiques et dépendances client doivent tous être vu comme influençant la structure et le fonctionnement de l'application.
 * Est-ce que les identifiants de session sont formellement aléatoires par nature ? Est-ce que les valeurs générées peuvent être reproduites ?
 * Est-ce que les mêmes conditions d'entrée produisent le même identifiant sur un test ultérieur ?
 * Peut-on prouver que les identifiants de session sont résistants à l'analyse statistique et cryptographique ?
 * Quels éléments des identifiants de session sont liés au temps ?
 * Quelles parties de l'identifiant de session sont prévisibles ?
 * Est-ce que le prochain identifiant de session peut être déduit à partir de la connaissance complète de l'algorithme de génération et des identifiants précédants ?

Rétro-ingénierie de cookie
Maintenant que le testeur a fait l'inventaire des cookies et a une bonne idée générale de leur utilisation, il est temps d'investiguer plus en détail les cookies qui semblent intéressants. Quels sont les cookies qui vont intéresser le testeur ? Pour fournir une méthode sécurisée de gestion de session, un cookie doit avoir certaines caractéristiques, chacune d'elles étant destinée à protéger le cookie d'une classe d'attaques différente.

Ces caractéristiques sont résumées ci-dessous :
 * 1) Imprévisibilité : un cookie doit contenir une certaine quantité de données difficilement prévisibles. Plus il est difficile de construire un cookie valide, plus il sera difficile de s'introduire dans la session d'un utilisateur légitime. Si des attaquants peuvent deviner le cookie utilisé dans une session active d'un utilisateur légitime, ils pourront usurper complètement l'utilisateur (détournement de session). Il est possible d'utiliser des valeurs aléatoires et/ou de la cryptographie pour rendre le cookie complètement imprévisible.
 * 2) Résistance à la contrefaçon : un cookie doit résister aux tentatives de modification malicieuse. Si le testeur reçoit un cookie tel que "IsAdmin=No", il est trivial de le modifier pour obtenir des droits d'administration, sauf si l'application ajoute une seconde vérification (par exemple, ajouter au cookie un hash de la valeur du cookie).
 * 3) Péremption : un cookie critique ne doit être valide que pour une période de temps appropriée et doit être ensuite supprimé du disque et de la mémoire, afin d'éviter le risque de rejeu. Cela ne s'applique pas aux cookie qui contiennent des données non critiques qui doivent être conservées d'une session à l'autre (ex: options de visualisation).
 * 4) Option "Secure" : un cookie dont la valeur est critique pour l'application doit avoir cette option activée, afin de n'autoriser sa transmission que via un canal chiffré pour dissuader l'espionnage.

Ici, l'approche est de collecter suffisamment d'exemples de cookies et de chercher les motifs récurrents dans leurs valeurs. Le sens exact de "suffisamment" peut varier de quelques uns, si la méthode de génération des cookies est facile à casser, à plusieurs milliers, si le testeur a besoin de procéder à une analyse mathématique (ex: khi-deux, attracteurs, voir plus loin pour plus d'information).

Une attention particulière doit être portée sur les processus de l'application, puisque l'état d'une session peut avoir un impact sur les cookies collectés. Un cookie collecté avant authentification peut être très différent d'un cookie obtenu après.

Il faut également prendre en compte un autre aspect : le temps. Enregistrez toujours le moment exact où un cookie a été obtenu, quand il est possible que le temps joue un rôle dans la valeur du cookie (le serveur pourrait utiliser l'horodatage du cookie pour une partie de sa valeur). L'heure enregistrée peut être l'heure locale, ou celle du serveur indiquée dans la réponse HTTP (ou les deux).

Lors de l'analyse des données collectée, le testeur devrait essayer de détecter toutes les variables qui peuvent influencer la valeur du cookie, et essayer de les modifier une par une. Envoyer au serveur des versions modifiées du même cookie peut s'avérer très utile pour comprendre comment l'application lit et utilise le cookie.

Exemples de vérification à faire lors de cette étape :
 * Quel jeu de caractères est utilisé dans le cookie ? Le cookie a-t-il une valeur numérique ? Alphanumérique ? Hexadécimale ? Que se passe-t-il si l'on injecte dans un cookie des caractères n'appartenant pas au jeu de caractères attendu ?
 * Est-ce que le cookie est composé de différentes parties contenant différentes informations ? Comment ces parties sont-elles séparées ? Avec quel séparateur ? Certaines parties pourraient avoir une plus grande variance, d'autres être constantes, d'autres encore avoir un nombre limité de valeurs possibles. Décomposer le cookie en ses composants de base est l'étape première et fondamentale.

Un exemple de cookie à structure évidente :

ID=5a0acfc7ffeb919:CR=1:TM=1120514521:LM=1120514521:S=j3am5KzC4v01ba3q

Cet exemple contient 5 champs, contenant différents types de données :

ID – hexadécimal CR – entier court TM and LM – large integer. (Curieusement, ils contiennent la même valeur. Il peut être intéressant de voir ce qui se passe si l'on modifie l'une d'elle) S – alphanumerique

Même si aucun séparateur n'est présent, avoir suffisamment d'exemples peut aider. Par exemple, regardons la série suivante :

0123456789abcdef

Attaque en force brute
Les attaques en force brute sont innévitablement liées aux question de prévisibilité et d'entropie. La variance dans un identifiant de session doit être considérée en même temps que la durée de vie de la session et le temps d'inactivité maximal. Si la variance à l'intérieur de l'identifiant de session est relativement basse, et que la durée de vie de la session est longue, les chances de succès d'une attaque en force brute sont beaucoup plus grandes.

Un identifiant de session long (ou plutôt comportant une variance élevée) et une durée de validité plus courte pourrait augmenter la difficulté d'une attaque en force brute.
 * Combien de temps prendrait une attaque en force brute sur toutes les valeurs possibles d'un identifiant de session ?
 * Est-ce que le nombre de valeurs possibles de l'identifiant de session est suffisamment grand pour empêcher une attaque en force brute ? Par exemple, est-ce que la longueur de la clef est suffisante, comparée à la durée de validité de la session ?
 * Est-ce que les délais imposés entre les tentatives de connexion avec différent identifiants de session permettent de limiter les risques d'une attaque en force brute ?

Exemple et test en boite grise
Si le testeur a connaissance de l'implémentation du système de management de session, il peut vérifier : L'identifiant de session envoyé au client ne devrait pas être facilement prévisible (n'utilisez pas d'algorithmes linéaires basés sur des variables prévisibles comme l'adresse IP du client). Utilisez de préférence des algorithmes cryptographiques avec des clefs de 256 bits (comme AES). Un identifiant de session doit contenir au moins 50 caractères. Les jetons de session devraient avoir une limite de temps d'inactivité défini (cela dépend de la criticité des données manipulées par l'application).
 * Jeton de session aléatoire
 * Taille des jetons
 * Limite du temps d'inactivité
 * Configuration des cookies:
 * non-persistent: seulement en RAM
 * secure (limité à HTTPS): Set Cookie: cookie=data; path=/; domain=.aaa.it; secure
 * HTTPOnly (non lisible par un script): Set Cookie: cookie=data; path=/; domain=.aaa.it; HTTPOnly

Pour plus d'information : Testing for cookies attributes

Outils

 * OWASP Zed Attack Proxy Project (ZAP) - https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project - inclut un mécanisme d'analyse de jetons de session
 * Burp Sequencer - http://www.portswigger.net/suite/sequencer.html
 * Foundstone CookieDigger - http://www.mcafee.com/us/downloads/free-tools/cookiedigger.aspx
 * YEHG's JHijack - https://www.owasp.org/index.php/JHijack

Description des vulnérabilités de management de session
Cf. les articles de l'OWASP : Session Management Vulnerabilities.

Description des contre-mesures en management de session
Cf. les articles de l'OWASP : Session Management Countermeasures.

Comment éviter les vulnérabilités de management de session
Voir : OWASP Development Guide article on how to Avoid Session Management Vulnerabilities.

Revue de code pour le management de session
Voir : OWASP Code Review Guide article on how to Review Code for Session Management Vulnerabilities.