Cookies HTTP & sessions PHP

Alexandre Niveau
GREYC — Université de Caen
En partie adapté du cours de Jean-Marc Lecarpentier
TODO:
  * vraie démo cookie, en montrant outils FF  storage
  * exemple cookie: dernière page visitée. avec deux scripts différents.
  * idem avec session
  * simplifier exemple session, pour ne pas confondre session php et session au sens général
  * avec ces détails en plus le cours peut durer une heure 

Le problème d'HTTP

  • HTTP est un protocole sans état :
    • ne garde aucune trace des requêtes faites au serveur
    • exécute chaque requête indépendamment des autres
  • impossible de conserver le contexte en cours !

Conservation du contexte

  • Problème : entre deux pages d'un même site, on a souvent besoin de conserver le contexte, c'est-à-dire des informations sur l'internaute et ses actions
  • Exemples :
    • identification de l'internaute
    • statut de l'internaute (visiteur, administrateur, etc.)
    • son parcours dans le site
    • les choix effectués (panier d'achats, préférences, etc.)

Les solutions

  • Utiliser les paramètres d'URL pour passer les informations : limité en taille, pas très agréable pour l'internaute, valeurs visibles dans la barre d'adresse, pas propre
  • Utiliser des champs cachés de formulaire POST sur chaque page : alourdit le code HTML (et donc le poids du fichier à transférer), et ne marche pas si l'internaute quitte le site puis revient
  • Ces problèmes sont réglés par l'utilisation de cookies :
    • le serveur stocke des données chez le client dans un fichier appelé cookie
    • à chaque requête vers ce serveur, le client transmet les données dans l'en-tête HTTP
    • les cookies peuvent survivre à la déconnexion au site
  • Attention : aucune de ces techniques n'empêche l'internaute de modifier les données envoyées au serveur !

Fonctionnement des cookies

  • Les cookies HTTP ont été créés en 1994, pour implémenter un panier d'achats
  • Ajoutés officiellement à HTTP en 1997 (RFC 2109)
  • Exemple de fonctionnement (adapté de Wikipédia) :
    Le client demande une page au serveur
    GET /index.html HTTP/1.1
    Host: www.example.org
    

Réponse du serveur

  • Le serveur lui envoie la page, en demandant au navigateur de créer un cookie :
    HTTP/1.0 200 OK
    Content-type: text/html
    Set-Cookie: name=value
    Set-Cookie: name2=value2; Expires=Wed, 09 Jun 2021 10:18:14 GMT
     
    <!DOCTYPE html>
    <html lang=fr>
    (suite de la page…)
    
  • Le navigateur stocke les informations dans un nouveau cookie, qui restera valable jusqu'à la date demandée

Nouvelle requête du client

  • Chaque nouvelle requête du client vers ce serveur sera accompagnée du contenu du cookie :
    GET /toto.html HTTP/1.1
    Host: www.example.org
    Cookie: name=value; name2=value2
    
  • Le serveur peut modifier une valeur, toujours avec Set-Cookie

Diagramme de séquence

Diagramme de séquence illustrant le fonctionnement des cookies
Fonctionnement des cookies (lien vers l'image SVG) (lien vers l'image PNG)

Cookies avec PHP

  • PHP possède des fonctions permettant de manipuler les cookies
  • Ces fonctions vont s'occuper de modifier les en-têtes HTTP des réponses pour ajouter Set-Cookie, et de lire les informations du champ Cookie dans les requêtes
  • Pour créer un cookie : setcookie (voir manuel)
    setcookie('prenom', 'Toto', time() + (86400 * 7)); 
    
    crée un cookie valable 7 jours et contenant l'information prenom=Toto.
  • Les cookies envoyés par le client sont accessibles dans le tableau $_COOKIE :
    if (key_exists('prenom'$_COOKIE))
      echo 
    "Bienvenue, " htmlspecialchars($_COOKIE['prenom']) . " !";
  • Ne jamais supposer qu'un cookie existe : les navigateurs peuvent les refuser, les clients peuvent les supprimer…
  • Attention aux caractères interdits dans les noms de cookie : espaces, guillemets, virgule, point-virgule, et antislash. Peut générer des bugs difficiles à trouver.

Limites des cookies

  • Les cookies sont plus pratiques que l'utilisation de paramètres d'URL ou de champs cachés, mais pas si différents
  • En particulier, l'internaute peut les modifier à loisir
  • Solution : n'utiliser les cookies que pour identifier l'internaute (par exemple en lui associant un numéro), et ne stocker les informations que côté serveur
  • Quel stockage côté serveur ? Utiliser une BD est lourd et peu efficace si on veut simplement conserver quelques variables d'une page à l'autre
  • PHP permet de faire ceci simplement et sans passer par une BD grâce aux sessions

Principe d'une session PHP

  • L'utilisation d'une session revient à pouvoir garder des variables d'une page à l'autre, de manière transparente
  • Lors de l'initialisation de la session : génération d'un identifiant unique par le serveur, transmis au client par un cookie
  • À chaque nouvelle requête du client, l'identifiant est transmis, et le serveur utilise les données liées à ce client
  • Les sessions ont une durée de vie limitée (configurable) : en cas d'inactivité prolongée, les données sont effacées du serveur
Diagramme de séquence illustrant le fonctionnement d'une session PHP
Fonctionnement d'une session PHP (lien vers l'image SVG) (lien vers l'image PNG)

Sessions sans cookies

  • L'identifiant de session est normalement stocké dans un cookie qui s'efface à la fermeture du navigateur
  • Ça ne peut pas marcher si le client refuse les cookies
  • Dans ce cas le serveur utilise la technique dite des « URL longues » : toutes les URL des liens locaux sont réécrites automatiquement, pour y ajouter un paramètre contenant l'identifiant de session
  • Moins sécurisé, car les attaques de type « session fixation » sont plus faciles si l'identifiant est dans l'URL que dans un cookie
  • On peut forcer l'utilisation de cookies avec l'option session.use_only_cookies
  • Liste des options PHP pour les sessions

Utilisation des sessions PHP

  • Il faut explicitement demander l'utilisation d'une session : session_start() sur chaque page
  • Si aucune session n'existe : génération d'un identifiant, création d'un fichier de données sur le serveur
  • Si déjà une session : les variables enregistrées sont chargées en mémoire dans le tableau $_SESSION
  • À la fin du script, le contenu du tableau $_SESSION est sauvegardé sur le serveur

Exemple

<?php
session_start
();
// teste si l’internaute est connu ou non
if (!key_exists("nom"$_SESSION) ||
    !
key_exists("prenom"$_SESSION) ||
    !
key_exists("date"$_SESSION)) {
  echo 
"Vous n’êtes pas identifié·e sur le site";
} else {
  echo 
"<p>Bienvenue " $_SESSION["prenom"] . " " 
       
$_SESSION["nom"] . "</p>";
  echo 
"<p>Dernier accès : " .  $_SESSION["date"] . "</p>";
  
$_SESSION["date"] = date("Y-m-d H:i:s");
}
// ... suite du script
?>

Sessions PHP ≠ session utilisateur

Les sessions PHP sont typiquement utilisées pour implémenter des sessions utilisateur

On demande à l'internaute de s'authentifier, et une fois que c'est fait, on stocke ses données dans le tableau $_SESSION

Cependant, on peut parfaitement utiliser $_SESSION sans implémenter d'authentification, et on peut faire en sorte que la session soit valable pendant des mois, indépendamment de la fermeture de la page (en changeant le lifetime du cookie de session via session_set_cookie_params)

les sessions PHP sont simplement un mécanisme offert par PHP pour simplifier et sécuriser l'utilisation de cookies

Sessions et objets

  • Les variables de session peuvent être de tout type
  • Elles sont sérialisées à la fin du script, de manière à pouvoir être enregistrées dans le fichier de session du serveur sous forme de texte
  • Lors du chargement des données de session, elles sont donc désérialisées
  • Problème pour les instances de classe : PHP ne sait pas les désérialiser si la classe n'a pas été déclarée avant
  • Toujours inclure les déclarations des classes utilisées avant l'appel à session_start()

Compléments

  • Pour supprimer une variable de session : unset (comme pour une variable normale)
  • Pour effacer toutes les variables de session du serveur : session_destroy() (attention, l'effet ne sera visible qu'à la fin du script)
  • Il est possible de sérialiser soi-même les variables de session sous forme de chaîne, par exemple pour les stocker dans une BD : session_encode(), session_decode()

Remarques

  • Par défaut, le cookie de session s'appelle PHPSESSID
  • Il est recommandé de changer ce nom pour une application réelle
  • Ceci se fait avec session_name("monsiteID");, obligatoirement avant le session_start();. Attention : caractères alphanumériques seulement
  • Lecture/écriture de cookies : se fait dans l'en-tête HTTP. Donc comme pour la fonction header, setcookie et session_start doivent être appelées avant tout envoi de contenu (même une espace ou un saut de ligne !)
  • En cas d'erreur ou de warning avec headers already sent, chercher de ce côté-là

Sécurité des sessions PHP