Cookies
- Création d'un cookie
- Options de cookie
- Accès côté serveur
- Accès en JavaScript
- Pistage et vie privée
- En pratique
Référence : MDN
Un cookie HTTP (également appelé cookie web ou cookie de navigateur) est une donnée de petite taille envoyée par le serveur au navigateur web de l'utilisatrice ou de l'utilisateur. Le navigateur peut alors enregistrer le cookie et le renvoyer au serveur lors des requêtes ultérieures.
Généralement, un cookie HTTP sert à indiquer que plusieurs requêtes proviennent du même navigateur où une personne est connectée. Il permet de mémoriser des informations d'état alors que le protocole HTTP est sans état.
Les utilisations principales des cookies HTTP sont :
- la gestion de session (authentification, panier d'achat, etc.)
- la personnalisation (préférences de l'utilisateur, thèmes, etc.)
- le tracking utilisateur (analytics, publicité ciblée, etc.)
Les cookies étant renvoyés à chaque requête, il est important de ne pas les surcharger d'informations inutiles. D'autres mécanismes de stockage côté client existent, comme le Web Storage (localStorage et sessionStorage) et IndexedDB, qui permettent de stocker des données plus volumineuses et plus structurées, qui ne sont pas transmises au serveur à chaque requête.
Création d'un cookie
Côté serveur, un cookie est créé en ajoutant un en-tête Set-Cookie à la
réponse HTTP. Par exemple, en utilisant le framework Bottle, et la méthode
set_cookie de l'objet response (référence :
response.set_cookie)
:
from bottle import response, #...
@route('/set_cookie')
def set_cookie():
# création d'un cookie nommé "hello" avec la valeur "world"
response.set_cookie("hello", "world")
return "Cookie créé !"
La réponse HTTP ressemblera à ceci :
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Set-Cookie: hello=world
Ensuite, le cookie sera envoyé par le navigateur à chaque requête vers le serveur, jusqu'à ce qu'il expire ou soit supprimé. Par exemple :
GET /set_cookie HTTP/2.0
Host: localhost:38083
Cookie: hello=world
Options de cookie
Durée de vie
Un cookie peut avoir une durée de vie définie par l'attribut Max-Age ou un
date d'expiration définie par l'attribut Expires. Si aucun de ces attributs
n'est défini, le cookie sera supprimé lorsque la session du navigateur sera
fermée (cookie de session).
# cookie valable 1 heure
response.set_cookie("hello", "world", max_age=3600)
# cookie valable jusqu'au 1er janvier 2026
response.set_cookie("hello", "world", expires="2026-01-01T00:00:00Z")
# cookie de session (supprimé à la fermeture du navigateur)
response.set_cookie("hello", "world", expires=None, max_age=None)
Chemin et domaine
Un cookie peut être limité à un chemin ou un domaine spécifique. Par défaut, le
cookie est valable pour le chemin de la requête et le domaine du serveur. On
peut modifier ces valeurs avec les attributs Path et Domain.
# cookie valable pour le chemin /app et le domaine example.com
response.set_cookie("hello", "world", path="/app", domain="example.com")
# cookie valable pour tous les chemins et tous les sous-domaines de example.com
response.set_cookie("hello", "world", path="/", domain=".example.com")
On ne peut pas définir un cookie pour un sous-domaine d'un domaine différent.
Par exemple, on ne peut pas définir un cookie pour app.example.com depuis
example.org. En revanche, on peut définir un cookie pour example.com depuis
app.example.com ou www.example.com.
Par défaut, le cookie est valable pour le chemin de la requête et le domaine du serveur qui l'a créé.
Secure et HttpOnly
Un cookie peut être marqué comme Secure pour indiquer qu'il ne doit être
transmis que sur des connexions HTTPS. Cela permet de protéger le cookie contre
une interception par un tiers lors de la transmission sur le réseau (ex: réseau
Wi-Fi public).
# cookie valable uniquement sur HTTPS
response.set_cookie("hello", "world", secure=True)
Un cookie peut également être marqué comme HttpOnly pour indiquer qu'il ne
doit pas être accessible par JavaScript. Cela permet de protéger le cookie
contre les attaques de type cross-site scripting (XSS), où un script malveillant
pourrait essayer de lire le cookie et d'en voler les informations (ex: session,
identifiant de l'utilisateur, etc.).
# cookie non accessible par JavaScript
response.set_cookie("hello", "world", httponly=True)
SameSite
Un cookie peut être marqué comme SameSite pour indiquer qu'il ne doit pas être
transmis avec des requêtes cross-site (requètes faites depuis un autre domaine
que celui qui a créé le cookie). Cela permet de protéger le cookie contre les
attaques de type cross-site request forgery (CSRF), où un site malveillant
pourrait essayer de faire une requête vers un autre site en utilisant les
cookies de l'utilisateur
Valeurs possibles :
Strict: le cookie n'est pas envoyé avec les requêtes cross-site.Lax: similaire àStrict, mais le navigateur envoie le cookie lorsque la personne navigue vers le site (ex: en cliquant sur un lien).None: le cookie est envoyé avec toutes les requêtes, y compris les requêtes cross-site. Dans ce cas, le cookie doit être marqué commeSecure.
Par défaut, la valeur de SameSite est Lax.
# cookie non envoyé avec les requêtes cross-site
response.set_cookie("hello", "world", samesite="strict")
# cookie envoyé avec les requêtes cross-site de navigation
response.set_cookie("hello", "world", samesite="lax")
# cookie envoyé avec toutes les requêtes cross-site
response.set_cookie("hello", "world", samesite="none")
Accès côté serveur
Pour accéder à un cookie côté serveur, on peut utiliser l'objet request du
framework Bottle. Par exemple, pour accéder au cookie hello créé précédemment
:
from bottle import request
hello = request.get_cookie("hello") # accès au cookie "hello"
print(hello) # affiche "world"
On peut également accéder à tous les cookies en utilisant la méthode
request.cookies, qui renvoie un dictionnaire contenant tous les cookies du
domaine courant.
from bottle import request
cookies = request.cookies # accès à tous les cookies
print(cookies) # affiche tous les cookies sous forme de dictionnaire
Accès en JavaScript
Pour accéder à un cookie en JavaScript, on peut utiliser la propriété
document.cookie. Cette propriété renvoie une chaîne de caractères contenant
tous les cookies du domaine courant, sous la forme
nom=valeur; nom=valeur; ....
console.log(document.cookie); // affiche tous les cookies du domaine courant
Les cookies avec les attributs HttpOnly ne sont pas accessibles en JavaScript.
Cela permet de protéger les cookies sensibles (ex: session, identifiant de
l'utilisateur, etc.) contre les attaques de type cross-site scripting (XSS).
Pistage et vie privée
Une page contenant des images ou des scripts provenant d'autres domaines (ex:
page sur example.com et image sur images.com) peut recevoir des cookies de
ces domaines. C'est ce qu'on appelle des cookies tiers. Ils peuvent permettre
(en définissant SameSite à None), de suivre l'utilisateur sur tous les sites
qui utilisent des ressources provenant de images.com. Ceci est utilisé par les
régies publicitaires pour enregistrer les visites de l'utilisateur sur
différents sites, et pour lui soumettre des publicités ciblées. Ces cookies
peuvent être bloqués par certains navigateurs.
En pratique
Compteur
Écrire une vue /compteur qui affiche le nombre de fois que la page a été
visitiée par le navigateur. Le compteur doit être stocké dans un cookie nommé compteur. Le
cookie doit être valable uniquement pour le chemin /compteur. Le cookie
doit expirer à la fin de la session, ne doit pas être accessible en JavaScript.
Correction
from bottle import route, run, template, static_file, get, request, response
@route('/compteur')
def compteur():
# on récupère le cookie "compteur" (s'il existe)
compteur = request.get_cookie("compteur")
if compteur is None:
# si le cookie n'existe pas, on l'initialise à 1
compteur = 1
else:
# sinon, on l'incrémente de 1
compteur = int(compteur) + 1
# on crée ou met à jour le cookie "compteur"
response.set_cookie("compteur", str(compteur), path="/compteur",
httponly=True, max_age=None, expires=None)
return f"Vous avez visité cette page {compteur} fois."