Join the Dark Side

Tout le monde les connait !

A moins d’avoir vécu dans une grotte depuis la mise en application de la RGPD, tous les internautes d’aujourd’hui ont déjà entendu parler des cookies.
En effet, chaque site qui collecte de la donnée relative à ses utilisateurs, se voit dans l’obligation d’en informer ses utilisateurs au travers de bannières, leurs demandant leur consentement, pour la mise en place et l’utilisation de ses fameux cookies (entre-autre).

Si aujourd’hui on aborde ce sujet, c’est parce que l’usage des cookies est souvent mieux connu que leur fonctionnement technique.
D’ailleurs, si vous demandez à diverses personnes dans la rue s’ils connaissent les cookies des sites internet, il y a fort à parier que les réponses que vous obtiendrez tourneront autour de :

“Ah oui, c’est le truc avec les bandeaux sur tous les sites, non ?”

“Oui, c’est pour la pub, pour surveiller nos faits et gestes, et savoir quelle pub nous afficher sur les sites. C’est du flicage quoi !”

Bien que cela ne soit pas faux, il ne s’agit en réalité que d’une partie des possibilités offertes par les cookies, et surtout, les réponses ci-dessus ne concernent que les usages des cookies, pas leur fonctionnement technique.

Retour aux sources

C’est un moyen de faire persister de la donnée entre chaque appels à un serveur web, depuis un client HTTP.

Le principe des cookies a été mis au point par Lou Montulli et John Giannandrea en 1994, alors qu’ils travaillaient chez Netscape.
A cette époque, ils travaillent sur la mise en place de solutions de e-commerce, et ils font face à ce problème :

Comment garder l’historique des différents éléments qu’un client a ajouté à son panier lorsqu’il navigue sur un site web ?

En effet, HTTP étant un protocole dit stateless (sans mémorisation de l’état de la connexion), chaque navigation vers une nouvelle page induit l’oubli de toutes les actions précédentes.

Ils ont alors proposés une solution permettant de stocker un “état” dans un nouvel objet qu’ils décidèrent d’appeler “Persistent Client State HTTP Cookies” (ou cookie, pour faire court).

L’idée était simplement de permettre au serveur Web de transmettre une donnée textuelle au client, et que ce dernier lui renverrait cette même donnée à chaque requête subséquente, permettant ainsi d’identifier l’utilisateur.

OK, mais à quoi ça sert au juste ?

Et bien puisque que le principe des cookies est de “faire persister de la donnée entre chaque appels HTTP vers un serveur web”, plusieurs scénarios sont envisageables :

  • Stocker des identifiants de sessions utilisateurs
  • Faire transiter des données de personalisation, tel que le thème visuel choisit par l’utilisateur, les préférences d’usages (format d’affichage des heures, fuseau horaire, …), etc.
  • Manipuler des identifiants de suivi des utilisateurs (enregistrement et analyse du comportement)

Les possibilités ne sont limitées que par l’imagination des ingénieurs logiciels 😁

Comment ça fonctionne ?

Techniquement, les cookies HTTP sont représentés uniquement par 2 entêtes HTTP :

  • Set-Cookie : Transmis par le serveur Web à destination du client HTTP (le navigateur)
  • Cookie : Transmis par le client HTTP (le navigateur) à destination du serveur Web

Les cookies sont des dictionnaires de clé/valeur. C’est-à-dire qu’ils sont représentés sous la forme clé=valeur. De plus, chaque cookie peut être complété par différents attributs que nous verrons plus loin dans cet article.
Enfin, plusieurs cookies peuvent être transmis simultanément au serveur Web, ou retourné à un navigateur.

Le cycle de vie des cookies est le suivant :

  1. Un cookie est délivré par un serveur web, à destination du navigateur qui l’a contacté,
  2. Le navigateur stocke le cookie reçu dans ce qu’on appelle la cookie jar (boîte à cookies),
  3. Lors d’un appel ultérieur à destination du “même serveur”, le navigateur ajoute le cookie à la requête HTTP qu’il effectue.

Visitons https://super-site.cloud !

Prenons l’exemple d’un internaute qui visite le site https://super-site.cloud.
Dans notre exemple, le serveur doit absolument savoir quel est le thème visuel que l’utilisateur souhaite utiliser.
S’il n’en a pas, le serveur lui affectera par défaut le thème nommé DarkSide.

Schéma cinématique

Schéma cinématique

Schéma cinématique

Schéma cinématique

Le schéma cinétique de l’exemple ci-dessus est le suivant :

  1. Le client effectue un appel HTTP de type GET sur l’URL https://super-site.cloud, sans passer l’entête HTTP Cookie au serveur.
  2. Le serveur web ne trouve pas le cookie nommé Theme, alors il renvoi l’en-tête HTTP Set-Cookie: Theme=DarkSide, accompagné du contenu HTML de la page. Le cookie renvoyé se nomme “Theme” et a pour valeur “DarkSide”
  3. L’utilisateur clique sur le lien présent sur la page, et est redirigé version l’adresse https://super-site.cloud/dark-side. Il transmet l’entête HTTP Cookie: Theme=DarkSide au serveur, puisque le serveur lui avait précédemment demandé de conserver ce cookie.
  4. Le serveur lui renvoie uniquement le contenu HTML de la page. Le cookie étant déjà positionné, pas besoin de transmettre à nouveau un entête HTTP Set-Cookie.
  5. L’utilisateur revient sur la page principale du site. Il transmet l’entête HTTP Cookie: Theme=DarkSide au serveur, puisque le serveur lui avait précédemment demandé de conserver ce cookie.
  6. Le serveur lui renvoie uniquement le contenu HTML de la page. Le cookie étant déjà positionné, pas besoin de transmettre à nouveau un entête HTTP Set-Cookie.

Par défaut, lorsque le serveur web renvoi un cookie simple (tel que celui ci-dessous), celui-ci est associé à la session de navigation de l’utilisateur.
Set-Cookie: name=value;

Autrement dit :

  • pendant toute la navigation de l’utilisateur sur le site, son cookie est stocké dans la cookie jar et géré par le navigateur
  • dès qu’il ferme son navigateur, le cookie est supprimé de la cookie jar.

Ce mode de fonctionnement peut poser des problèmes aujourd’hui, car les utilisateurs ferment rarement leurs navigateurs.
Mais pas d’inquiétudes, il est possible de contrôler l’expiration de celui-ci 😉

Expiration et âge maximal

Les 2 moyens de contrôler la durée de vie d’un cookie sont soit :

  • de définir la date d’expiration du cookie
  • de définir la durée de vie pour le cookie

La date d’expiration utilise le mot clé Expires, et est représentée comme suit :

Set-Cookie: name=value;
Set-Cookie: Expires=Sat, 1 Jan 2050 00:00:00 +0000;

Note : Ce cookie sera invalidé automatiquement le 1er Janvier 2050 à minuit.

La durée de validité, exprimée en secondes, utilise le mot clé Max-Age, et est représentée comme suit :

Set-Cookie: name=value;
Set-Cookie: Max-Age=3600;

Note : Ce cookie sera invalidé automatiquement 1 heure après avoir été délivré.

Il n’existe aucun entête HTTP servant explicitement à supprimer un cookie.
En revanche, pour supprimer un cookie, le serveur dispose de 2 options :

  1. Renvoyer une date d’expiration se situant dans le passé.
    En spécifiant une date passée, le navigateur supprimera le cookie ciblé.

Set-Cookie: name=value;
Set-Cookie: Expires=Thu, 1 Jan 1970 00:00:00;

  1. Renvoyer un âge maximal égal à zéro.
    La durée de vie maximale du cookie étant automatiquement atteinte dès réception de celui-ci, le navigateur supprimera le cookie ciblé.

Set-Cookie: name=value;
Set-Cookie: Max-Age=0;

Et en pratique ?

Dans le navigateur, les entêtes Set-Cookie sont visibles sur chaque requête HTTP, depuis l’onglet Network des outils de développements des navigateurs.
Ici on voit bien dans la partie Response Headers de la requête que 3 cookies ont été appliqués :

  • 1 sans spécification de durée de vie
  • 1 avec date d’expiration
  • 1 avec âge maximal
    Réponse HTTP

Et pour confirmer leur prise en compte, toujours depuis les outils de développements des navigateurs, il suffit d’aller :

  1. Dans l’onglet Application (ou Stockage, dépendemment de votre navigateur)
  2. D’étendre l’élément Cookies et cliquer sur le site en cours de consultation (ici https://super-site.cloud)
  3. Et consulter que les 3 cookies sont bien présents, avec les bonnes dates d’expiration. Cookie jar

La transmission des cookies

Nous nous sommes pour l’instant concentré sur l’envoi du cookie au client HTTP, mais qu’en est-il de son retour vers le serveur Web ? Quand et sous quelles conditions est-il renvoyé ?

La porté des cookies

Le renvoi se fait en fonction du nom de domaine ayant délivré le cookie.

Note : Depuis le début de cet article, il est fait mention de “serveur Web” pour plus de simplicité, mais dans les faits, un cookie est rattaché à un nom de domaine, et potentiellement de ses sous-domaine.

Par défaut, si rien n’est précisé dans l’entête Set-Cookie, le cookie est associé au nom de domaine qui l’a délivré, et uniquement celui-ci. Toutes les pages de ce nom de domaine auront alors accès à ce cookie.
Si l’on se focalise sur la cookie jar de l’exemple précédent, on peut voir que les 3 cookies délivrés sont tous associés au nom de domaine super-site.cloud. Domaine des cookies

Afin de mieux gérer la surface d’exposition d’un cookie sur leurs noms de domaine, les serveurs Web dispose de l’attribut Domain. Cet attribut s’utilise comme suit :

Set-Cookie: name=value;
Set-Cookie: Domain=super-site.cloud;

Les règles d’usage de cet attribut sont celles-ci :

  • ✔️ Si l’attribut est absent, alors :
    • Le navigateur enregistre le cookie avec un porté limité exclusivement à l’hôte de l’emplacement actuel du document. Seules les pages délivrées sur le domaine courant auront accès au cookie.
    • Tous les sous-domaines sont alors exclus de la portée du cookie, et ne le recevront pas.
  • Si l’attribut est présent et :
    • ✔️ Cible le domaine sur lequel se trouve le client HTTP :
      • Alors ce domaine et tous ses sous-domaines auront accès au cookie.
      • Exemple : Si le site https://super-site.cloud délivre un cookie destiné à super-site.cloud (ou .super-site.cloud) alors le domaine courant et tous ses sous-domaines auront accès au cookie.
    • ❌ Cible explicitement un sous-domaine :
      • Alors le cookie ne sera pas pris en compte par les navitageurs
      • Exemple : Impossible pour le site https://super-site.cloud de délivré un cookie uniquement destiné à sub.super-site.cloud, comme le montre la capture d’écran ci-dessous.
        Portée rejetée des cookies
    • ✔️ Cible un domaine parent :
      • Alors le domaine parent et tous ses sous-domaines auront accès au cookie.
      • Exemple 1 : Le site https://mon.super-site.cloud peut délivrer un cookie destiné à super-site.cloud. Il sera alors disponible pour https://super-site.cloud et tous ses sous-domaines.
      • Exemple 2 : Le site https://voici.mon.super-site.cloud peut délivrer un cookie destiné à mon.super-site.cloud. Il sera alors disponible pour mon.super-site.cloud et tous ses sous-domaines, y compris voila.mon.super-site.cloud.
    • ❌ Cible explicitement un autre domaine :
      • Alors le cookie ne sera pas pris en compte par les navitageurs (cf. capture de Chrome)
      • Exemple : Impossible pour le site https://super-site.cloud de délivré un cookie destiné à google.com.

Précision sur le localhost

Les cookies délivrés sur le domaine localhost sont fontionnels. Uniquement si vous ne mettez pas l’attribut Domain ¯\_(ツ)_/¯

Précision sur les TLDs

Un mécanisme de blocage a été instauré dans les navigateurs pour vous empêcher de poser des cookies sur les TLD (.com, .fr, …), et même sur certains sites.
Cette liste, intégrée par tous les navigateurs, peut être librement consultée ici (entre autre) : effective_tld_names.dat

Le sous-répertoire

En plus de contrôler les domaines et sous-domaines ayant accès à un cookie, il est possible de limiter sa portée à un chemin d’URL. Ceci au travers de l’attribut Path. Cet attribut s’utilise comme suit :

Set-Cookie: name=value;
Set-Cookie: Path=/health;

La valeur du chemin mentionné via cet attribut est considérée comme une URL de répertoire finie. Et le caractère / peut servir de séparateur de répertoire dans l’URL de cet attribut.
De fait, les sous-répertoires de /health, tel que /health/smtp ou /health/database/sql sont acceptés, là où un chemin tel que /health-ui ne l’est pas.

Les cookies et la sécurité

Les cookies, comme beaucoup d’éléments sur une page Web, peuvent faire l’objet de failles de sécurité s’ils sont mal utilisés.
C’est pourquoi des mécanismes de protection ont été mis en place.

L’attribut Secure

L’attribut Secure indique au navigateur qu’il ne doit renvoyer ce cookie au serveur, que si la connection entre le navigateur et le serveur se fait via HTTPS, et uniquement dans ce cas là !
En conséquence, si la connexion utilise du HTTP (non sécurisé), alors le navigateur ne prendra pas en compte les cookies avec l’attribut Secure.

En effet, lorsque l’on utilise HTTPS, les entêtes HTTP se retrouvent chiffrées avec le contenu de la requête HTTP, et sont donc illisibles pour ceux qui surveilleraient les flux réseaux. Ce qui n’est pas le cas avec un flux “en clair”, si l’on utilise HTTP (non sécurisé).

L’attribut Secure s’utilise comme suit :

Set-Cookie: name=value;
Set-Cookie: Secure;

L’attribut HttpOnly

Le cookie peut être lu et manipulé depuis une page web (cf. chapitre suivant).
Si le cooke n’a pas besoin d’être manipulé par le client HTTP, alors l’usage de l’attribut HttpOnly est recommandé.

Cet attribut indique au navigateur que ce cookie ne doit pas être accessible, ni manipulable depuis une page Web.

L’attribut Secure s’utilise comme suit :

Set-Cookie: name=value;
Set-Cookie: HttpOnly;

Bon à savoir : L’un des avantages de cet attribut est qu’il protège des attaques de types XSS (Cross-Site Scripting).

L’attribut SameSite

Comme vu précédemment, tous les cookies délivrés par les serveur Web ont un domaine qui leur est associé, soit explicitement via l’attribut Domain, soit implicitement par le navigateur.

Lors d’une navigation en ligne, si le domaine du cookie transmis par le navigateur est le même que le domaine de la page consultée, alors on considère le cookie comme first-party cookie (aka cookie interne). C’est-à-dire que le cookie est utilisé depuis le site qui l’a délivré.
A l’inverse, si le domaine est différent, alors on considère le cookie comme third-party cookie (aka cookie tiers). C’est-à-dire que le cookie est utilisé depuis une autre site que celui qui l’a délivré.

L’usage des cookies tiers est très répandu dans les régies publicitaires en ligne, puisqu’ils permettent de tracer efficacement le parcours d’un utilisateur.
En effet, si le site https://super-site.cloud place une bannière pulicitaire hébergée chez https://ma-regie-pub.cloud, alors l’hébergeur de la publicité pourra facilement savoir que la publicité a été vue par l’utilisateur, et depuis de quel site.

Il est possible de contrôler l’exposition des cookies via l’attribut SameSite :

Set-Cookie: name=value;
Set-Cookie: SameSite=Strict;

Cet attribut offre 3 valeurs de configuration :

Valeur Description
Strict Les cookies ne seront envoyés qu’avec les requêtes effectuées sur le domaine de même niveau, et ne seront pas envoyées sur les requêtes vers des sites tiers.
Lax Les cookies sont transférables depuis le site actuel vers des sites de niveaux inférieurs et seront envoyés lors de requêtes GET initialisées par des sites tiers.
Note : La valeur Lax est utilisée par défaut par les navigateurs les plus récents.
None Les cookies seront envoyés dans tous les contextes, rendant possibles les requêtes de type cross-origin.
❗❗ Important : La valeur None requiert l’utilisation conjointe de l’attribut Secure. Sans cela, le cookie ne sera pas accepté par le navigateur.

Bon à savoir : L’usage de la valeur Strict vous aide à protéger vos cookies contre les attaques de type CSRF (Cross-Site Request Forgery), dans la mesure où ceux-ci ne peuvent être émis que depuis votre site, et pas depuis des sites tiers.

Comment le manipuler côté code ?

Côté navigateur, vous pouvez manipuler les cookies depuis JavaScript via la propriété cookie de l’objet document :

// Lire les cookies reçus
const myCookies = document.cookie;

// Ecrire un cookie
document.cookie = "Theme=DarkSide; SameSite=Strict; Secure";

Cette propriété vous permet de lire et d’écrire des cookies.

Mais attention, seuls les cookies sans l’attribut HttpOnly sont accessibles depuis le code JavaScript.

Nos recommandations

Suite à tout cela, voici nos recommandations quand à l’usage des cookies :

  1. Ne spécifiez pas de domaine :
    • Cela limitera exclusivement la portée de votre cookie au domaine hébergeant votre site, et pas à ses sous-domaines.
    • Spécifiez un sous-domaine uniquement si vous devez faire redescendre explicitement une information
    • Ne ciblez jamais un domaine parent. Bien que cela soit techniquement autorisé, cela complexifie la propagation des cookies
  2. Utilisez toujours l’attribut Secure :
    • Cela limitera les possibilités de lecture du cookie depuis le réseau grâce au HTTPS
  3. Utilisez toujours l’attribut HttpOnly :
    • Cela vous protégera des attaques XSS associées au cookies
    • Ne l’omettez que si vous avez expressement besoin d’y accéder depuis JavaScript
  4. Utilisez toujours l’attribut SameSite avec la valeur Strict :
    • Cela vous assurera de ne pas avoir de requêtes HTTP provenant d’autres sites (et donc offrira une première zone de défense contre les attaques CSRF).
    • Spécifiez la valeur Lax si votre cookie doit être accessible à des sous-domaines, mais :
      • Sur le serveur Web, contrôlez via les CORS et/ou l’entête Referer que l’appelant est autorisé à utiliser le cookie.
  5. Définissez toujours une durée de vie maximale pour un cookie :
    • Entre Max-Age et Expires, utilisez l’attribut qui vous convient le mieux. La cookie jar fait de toute façon référence à une date en interne.
    • Ne dépassez jamais une semaine !
    • S’il s’agit d’un cookie d’authentification, limitez-le à 1 jour max !

Ce qui donne un cookie du style :

Set-Cookie: sessionId=01FGMBC7794EC7TVX0VXFFXYS2;
Set-Cookie: Secure;
Set-Cookie: HttpOnly;
Set-Cookie: SameSite=Strict;
Set-Cookie: Max-Age=86400;

Conclusion

Que de possibilités pour un mécanisme aussi simple et ancien, n’est-ce pas ?
En définitif le cookie HTTP est un outil puissant, et de surcroit, très largement supporté par les différents navigateurs. Il serait inopportun de ne pas le considérer comme une solution viable.
Nous ne pouvons que vous encourager à les utiliser, en prenant bien soin de les protéger dès que nécessaires.

Enfin, nous évoquerons l’impact de la RGPD sur les cookies dans un prochain article.

Merci à vous, et à bientôt.