• 4 heures
  • Facile

Les variable de session

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Comme toutes les variables super-globales, les variables de session sont également un danger potentiel. Une session mal protégée peut être volée ou empoisonnée (respectivement "sessions hijacking" et "session poisoning"). Développons un peu tout ça.

Le vol de session

Explication

Avant toute chose il faut savoir que lorsque vous vous connectez sur un site, une session unique est créée. Un ID unique est alors attribué à cette session : le PHPSESSID . C'est cet ID qui va permettre au serveur de vous reconnaitre. Et cela pose certains problèmes de sécurité.

Figurez-vous un cas où l'ordinateur d'un utilisateur a été infecté par un hacker. Ce dernier peut assister en direct à tout ce qui se passe dans l'ordinateur de sa victime. L'utilisateur, qui ne se doute de rien, se connecte à vote site. Pendant qu'il navigue, le hacker en profite pour se renseigner sur les données de navigation. Il récupère le PHPSESSID, se rend sur votre site, et remplace son propre PHPSESSID par celui de la victime. Le serveur, qui ne sait pas faire la différence entre les deux, reconnait le hacker comme l'utilisateur et le connecte. Un petit schéma pour éclairer tout ça :

Bien que ce type d'attaque ne fonctionne pas dans 100% des cas, il serait quand même plus professionnel de sécuriser tout ça.

Comment s'en protéger

Bon vous l'aurez compris, il faut trouver un moyen d'identifier précisément l'utilisateur. On aurait alors tendance à vouloir utiliser son adresse IP. Mais malheureusement aujourd'hui l'adresse IP n'est plus une valeur sure. Eh oui, une IP ça se vole, ça se masque, ça se change. De plus certains organismes ont une forte tendance à modifier leurs IP (Les entreprises, les banques, les écoles...). Bref dans notre cas, l'IP ne nous apportera rien de bon.

Dans ce cas, utilisons toutes les variables d'environnement ! On vérifie  le User-Agent comme ça on connait le navigateur, le système d'exploitation, le pays et c'est bon. Le hacker ne pourra quand même pas tout imiter ?

Rappelle-toi le fondement même de la sécurité informatique : Tu ne feras jamais confiance aux données renvoyées par l'utilisateur ! Si le hacker a accès au PHPSESSID, il pourra récupérer sans problème le contenu du User-Agent. Donc même si cela complique l'attaque, cela ne la rend absolument pas impossible.

Bah si on ne peut se baser sur aucune des données de l'utilisateur, il est impossible de l’identifier...

En fait vous avez raison, il est tout simplement impossible d'être sûr à 100% de qui est réellement connecté. Il va donc falloir rendre la tâche le plus complexe possible. Il existe beaucoup de techniques pour lutter contre ce genre de faille, je vais vous présenter celle que mon maitre à moi m'a enseigné ;)

Il va en fait falloir créer un système de communication entre le client et le serveur. On va en fait mettre en place un système de "tickets". Le serveur génère un ticket qu'il garde en mémoire. Il le stock ensuite dans les cookies de l'utilisateur. A chaque fois que l'utilisateur demande une nouvelle page, le serveur vérifie qu'ils ont bien le même ticket avant d'en générer un nouveau pour la page suivante. Exemple :

  1. L'utilisateur se connecte : début de la session

  2. Il se rend sur la page "index.php".

  3. Le serveur génère un ticket qui a pour valeur "ticket001"

  4. Il l'enregistre simultanément dans une variable de session et dans les cookies de l'utilisateur

  5. L'utilisateur change de page

  6. Le serveur vérifie qu'ils ont tous les deux le même ticket

  7. Il génère un nouveau ticket qui a pour valeur "ticket002" (par exemple)

On réalise dans ce cas que si le hacker vole la session, il se retrouvera avec un ticket aléatoire et donc forcément différent de celui de l'utilisateur. Lorsqu'il essaye de se rendre sur une page, le serveur réalise que les tickets sont différents et la session est détruite. Un petit code pour éclairer tout cela :

<?php

session_start();

$cookie_name = "ticket";
// On génère quelque chose d'aléatoire
$ticket = session_id().microtime().rand(0,9999999999);
// on hash pour avoir quelque chose de propre qui aura toujours la même forme
$ticket = hash('sha512', $ticket);

// On enregistre des deux cotés
setcookie($cookie_name, $ticket, time() + (60 * 20)); // Expire au bout de 20 min
$_SESSION['ticket'] = $ticket;

?>

Puis pour le vérifications :

<?php

# Pensez à ajouter des isset() dans le if() !
# Je les ai volontairement retirés par soucis de lisibilité du code
	
session_start();

if ($_COOKIE['ticket'] == $_SESSION['ticket'])
{
	// C'est reparti pour un tour
	$ticket = session_id().microtime().rand(0,9999999999);
	$ticket = hash('sha512', $ticket);
	$_COOKIE['ticket'] = $ticket;
	$_SESSION['ticket'] = $ticket;
}
else
{
	// On détruit la session
	$_SESSION = array();
	session_destroy();
	header('location:index.php');
}

?>

Pensez également à vérifier que le navigateur de l'utilisateur accepte les cookies, sans quoi le script ne pourra pas fonctionner correctement. Mais pas de panique, ça se fait très facilement ! Un simple isset() et le tour est joué ;)

<?php

setcookie($name, $value, $time);

if(!isset($_COOKIE[$name])) {
    // Le navigateur ne semble pas accepter les cookies
}

?>

On notera que par soucis de sécurité, on préfèrera un nom moins explicite pour le cookie. Le mot "ticket" attirera automatiquement l’œil du hacker. Choisissez donc de préférence un nom qui n'a aucune signification apparente (Ex : gt_e, avr, time, ou encore version). Vous avouerez que ceci :

gt_e : 5a2fb5772e35641024303c5a79163a63f9670cabb534d13737826a [...]

est beaucoup moins explicite que ceci :

ticket : 5a2fb5772e35641024303c5a79163a63f9670cabb534d13737826a [...]

Vous pouvez également vous amuser à rajouter des choses inutiles dans les cookies pour complètement brouiller les pistes. Veillez cependant à ne pas saturer les cookies des utilisateurs, cela risque de ne pas plaire à tout le monde.

Voilà donc un moyen de protection accessible à tous qui ajoutera une bonne dose de sécurité. Bien que ce genre de système n'assure pas une sécurité maximale, il est difficile de faire mieux pour un programmateur lambda. La solution ultime consiste à passer en HTTPS avec un chiffrement SSL/TLS ce qui rendrait impossible tout type d'écoute. Mais cette solution est couteuse et donc pas accessible à tous. Si vous voulez en savoir plus sur comment passer en HTTPS, je vous invite à consulter la partie 2 de ce cours :)

L'empoisonnement de session

Le principe est très simple. C'est exactement le même problème que pour les injections SQL. A partir du moment où vous autorisez l'utilisateur à envoyer des données qui seront stockées dans des variables de session, il en profitera pour injecter toute sorte de choses (Si ce n'est pas clair, je vous invite à relire la partie sur les injections SQL).

Un htmlspecialchars() devrait suffire à sécuriser tout ça. Si vous avez envie d'aller plus loin avec les filtres et d'avoir un contrôle total sur les entrées utilisateurs, je vous invite à aller voir ce cours qui détaille très bien les différentes solutions qui s'offrent à vous.

Exemple de certificat de réussite
Exemple de certificat de réussite