Sécurité des sites web : L’utilité des flags Secure et HttpOnly
Sommaire
I. Présentation
Nous allons dans cet article nous intéresser à l'intérêt et au fonctionnement des flags Secure et HttpOnly dans le contexte de la sécurité des applications et des sites web.
Si vous avez déjà utilisé un scanner de vulnérabilités tel que Nessus, Acunetix, Nikto ou encore WP-scan sur une application ou un site web, vous aurez certainement remarqué que deux éléments sont très souvent remontés :
- L'absence de flag HttpOnly
- L'absence du flag Secure
Voici quelques exemples, récoltés auprès de différents scanners de vulnérabilités et différents sites web :
II. Les headers Cookies et Set-Cookies
Afin de bien comprendre le rôle et l'importance de ces deux flags, il est intéressant de rappeler ce que sont les headers "Cookies" et "Set-Cookies", tout deux normalisés dans le RFC 2109 "HTTP State Management Mechanism" en février 1997. Ce RFC décrit plus globalement la façon dont sont à gérer les sessions lors de la navigation d'un utilisateur, et c'est là l'intérêt principal du cookie. Les éléments notables d'une session sont :
- Une session a un début et une fin
- Une session a une durée de vie relativement courte
- La session peut être terminée par l'user-agent (le client) ou pas le serveur
- La présence d'une session est implicite dans l'échange d'information d'état
Globalement, la vie d'une session va se dérouler comme ceci :
- Le client visite le serveur pour la première fois, le serveur crée une session (côté serveur) pour stocker des informations
- Le serveur, dans sa première réponse, va envoyer au client avec un numéro de session (Exemple : AECOC42584dZQZDK)
- Le client, à chaque nouvelle requête, enverra en header son Cookie, permettant au serveur de retrouver les informations concernant l'utilisateur dans sa base de session
Côté serveur, on pourra par exemple trouver cette relation :
Session n°AECOC42584dZQZDK : { Nom : John, Age: 23, Ville : Paris }
Ainsi, lorsque l'utilisateur naviguera, il pourra voir le menu du site "Bonjour John, il est 13h48 à Paris". Cela parce que la relation suivante se sera faite :
Utilisateur envoie son cookie contenant son ID de session au serveur > Serveur retrouve les informations grâce à l'ID de session reçu > Serveur peut utiliser les informations pour le traitement l'affichage
Voilà pour ce retour très basique et non exhaustif sur le fonctionnement d'une session. Intéressons nous maintenant à la phase 2 de la procédure décrite précédemment. Il faut donc savoir que la déclaration d'une session à un navigateur se fait justement via le header "Set-Cookie". Voici, pour illustrer la chose, la réponse d'un serveur sur lequel je me connecte pour la première fois aujourd'hui et qui m'assigne donc un ID de session :
Nous pouvons déjà voir que certains paramètres supplémentaires sont passés lors de la définition du cookie, par exemple le flag "path" qui permet de dire "ce cookie est valable pour tout le site à partir de /", c'est à dire à partir de la racine. Dans certains contextes, on pourra donc définir la validité d'un cookie pour certains sous-répertoires. Également, le flag "domain" peut être utilisé pour définir la validité d'un cookie pour un nom de domaine (exemple ".information-security") ou bien pour un sous domaine précis uniquement (exemple "www.ogma-sec.fr"). Là aussi, des notions de sécurité sont à prendre en compte mais ce n'est pas l'objet de cet article. Un flag va donc être, dans notre contexte, une information passée lors de la définition du cookie. Les principaux flags sont décrits dans le RFC 2109 mis en liens plus haut, d'autres ont été ajoutés au fur et à mesure.
En listant mes cookies, je pourrais voir qu'un cookie nommé communément PHPSESSIONID (parfois JSESSIONID, parfois autrement...) est créé et qu'il contient un identifiant qui peut sembler aléatoire :
Lors de mes prochaines requêtes, le contenu de ce cookie sera systématiquement envoyé au serveur en mode clé:valeur par mon navigateur, voyez plutôt le contenu de mon header lors de ma prochaine requête :
Envoi du cookie de session dans la requête par le navigateurAinsi, si je m'authentifie une fois, le serveur pourra (en schématisant) passer la variable "Est Identifié" de ma session côté serveur à "Oui" et ainsi agrémenter les informations de ma session avec les informations de mon compte.
Nous voyons donc tout l'intérêt des headers Set-cookie (utilisés par le serveur) et Cookie (utilisés par le client) dans le rôle de la session. Si je supprime mon cookie de session dans mon navigateur, ma prochaine requête sera faite sans session et le serveur n'aura alors aucun moyen de savoir qui je suis, et plus précisément si je suis authentifié. En revanche, si un autre utilisateur vol mon cookie de session, il pourra se faire passer pour moi auprès du serveur, qui ne regarde que le contenu du cookie de session pour vérifier cela. C'est ici que les flags Secure et HttpOnly deviennent intéressants.
Rappelez vous donc que le cookie est une information stockée dans votre navigateur, et que celui-ci transite à chaque requête vers le serveur. Cette simple phrase expose les deux principaux vecteurs d'attaque pour voler un cookie de session : le stockage et le transport. Détaillons cela.
Nous avons vu que le navigateur qui possède un cookie pour le nom de domaine qu'il visite va systématiquement l'envoyer dans ses requêtes au serveur. Or, tout ce qui est envoyé à un serveur transite au niveau réseau et peut donc être lu et intercepté par un éventuel pirate (ceci est plutôt facile à faire, notamment dans un LAN d'entreprise standard). Le pirate est alors en capacité de décomposer la trame réseau et notamment d'y retrouver le cookie de session de l'utilisateur afin de le copier dans son navigateur et ainsi d'usurper (de voler) la session de cet utilisateur. Voici une capture d'écran qui expose comment le cookie est visible au travers un capture réseau (Wireshark) :
On voit ici bien que toute la requête HTTP est visible, et notamment le header HTTP "Cookie".
Également, nous avons vu que le cookie de session, et les autres cookies aussi d'ailleurs, est stocké dans le navigateur. Il est d'ailleurs relativement impressionnant de visionner le nombre de cookies actuellement stockés dans nos navigateurs, certains sites nous en assignent des dizaines alors que nous ne sommes même pas authentifié :
En l’occurrence, il est également possible de demander au navigateur d'aller chercher des informations dans les cookies qu'il possède, cela notamment en JavaScript, qui est un langage qui peut s'exécuter côté client.
L'exécution côté client signifie que c'est le navigateur qui exécute les instructions, on peut donc demander à JavaScript de traiter les objets du navigateur comme le DOM (Document Object Model) ou les cookies. JavaScript est un langage aux nombreuses possibilités, si bien qu'il est vecteur de nombreuses failles de sécurité, dont les fameuses XSS (Cross Site Scripting) qui permettent à un attaquant de contrôler le code JavaScript exécuté côté client, et donc de voler le contenu des cookies.
Voici une vidéo, réalisée par mes soins, dans laquelle j'exploite une vulnérabilité de type XSS dans le but de voler le cookie de session d'un administrateur :
Rassurez-vous, cette faille de sécurité est maintenant corrigée. Néanmoins, on peut voir que grâce à l'exécution de code JavaScript contrôlé par l'attaquant (moi dans cette vidéo), j'arrive à m'envoyer le contenu du cookie de ma victime, à le réinsérer dans mon navigateur et ainsi à voler la session de l'administrateur. C'est ici le deuxième plus important vecteur d'attaque dans le cadre du vol de cookie, bien qu'il en existe d'autres !
Bien, que viennent donc faire c'est deux flags "Secure" et "Http-only" dans cette affaire ? C'est la question que vous commencez à vous poser. Et bien voilà la réponse : ils permettent tout simplement et très facilement de se protéger contre les vols de cookies, et cela peu importe que l'application soit remplie de failles de type XSS ou que votre navigateur fasse transiter des informations sur le réseau !
A. Secure : Protection contre le vol durant le transport
Selon le RFC 2019 "HTTP State Management Mechanism" du février 1997 qui décrit l'utilisation du flag "Secure" lors de l'émission d'un cookie, l'utilisation de ce flag permet de laisser la décision d’envoi ou non du cookie au navigateur. Plus précisément, ce flag signifie "n'envoie le cookie que sur les moyens de communication que tu considères comme sécurisés". Il est bien décrit dans ce RFC que le navigateur enverra le cookie dans tous les cas si le flag Secure n'est pas actif :
If absent, the user agent may send the cookie over an insecure channel.
Dans un cadre général, le protocole HTTPS est considéré comme un canal de communication sécurisé alors que le protocole HTTP non. Cela signifie donc qu'un cookie avec le flag Secure actif ne sera envoyé au domaine courant uniquement si les requêtes/réponses sont en HTTPS, évitant ainsi le vol durant le transport du cookie comme précédemment décrit.
Il y a néanmoins une attention à porter à ce dernier point. Voici textuellement le contenu qui nous intéresse dans le RFC :
The user agent (possibly under the user's control) may determine what level of security it considers appropriate for "secure" cookies.
Il est ici explicitement indiqué que le niveau de sécurité qui fait que le navigateur détermine un canal de communication comme "sécurisé" est sous le contrôle de l'utilisateur. Outre l'HTTPS, on peut très bien imaginer que d'autres facteurs puissent être volontairement ou involontairement modifiés du côté de l'utilisateur, afin de faire en sorte de baisser le seuil de sécurité du navigateur. Mais d'une manière générale, ce flag est utilisé pour empêcher l'envoi des cookies sur un échange HTTP.
Cela peut paraître évident, mais même si un site est entièrement en HTTPS, il est possible d'obtenir des situations dans lesquelles les cookies transitent en clair (HTTP). C'est notamment le cas lorsqu'un utilisateur cherche à joindre le site en HTTP (après avoir cliqué sur un lien par exemple). L'utilisateur est alors immédiatement redirigé vers l'HTTPS mais il aura tout de même effectué une première requête en HTTP, et s'il possédait un cookie à ce moment là, il sera envoyé lors de cette première requête, c'est précisément ce qu'empêche le flag Secure.
Selon le RFC 6265 "HTTP State Management Mechanism" d'avril 2011 qui décrit l'utilisation du flag "HttpOnly" lors de l'émission d'un cookie, le flag "HttpOnly" limite le cadre d'utilisation du cookie aux requêtes HTTP. Autrement dit, tous les accès au contenu du cookie sera refusé si ce n'est pas HTTP. Cela est par exemple le cas lorsqu'un script JavaScript va chercher à accéder au contenu d'un cookie. Si le flag HTTPOnly est actif sur le cookie en question, JavaScript n'y aura pas accès. Cela empêchera donc un attaquant exploitant une XSS de mettre la main sur le cookie de session, par exemple.
Cela permet donc d'éviter, ou au moins de complexifier, le vol du contenu du cookie dans le navigateur.
J'espère que cet article vous aura convaincu de l'utilité et de la nécessité d'utiliser ces flags. Sachez que ce sont ces petites barrières et ces paramètres qu'il suffit de passer à "on" qui découragent la majeure partie des pirates actuels, il est donc nécessaire de les utiliser et des les connaître.
N'hésitez pas à donner votre avis sur ce sujet dans les commentaires.