Angular, N’Tier et HttpOnly
Avec l’apparition au cours de la décennie 2010 des environnements de travail Javascript de plus en plus puissants, l’architecture N’Tiers, si elle était déjà une norme dans le contexte d’application d’entreprises au cours des années 2000, a pu voir son modèle s’étendre à de nombreuses solutions Web. Ce modèle repose sur l’utilisation de technologies exécutées par le navigateur. Or, il arrive parfois que cette couche doive gérer une partie de l’authentification de l’utilisateur, pourtant une recommandation courante sur l’authentification est qu’elle ne doit jamais être côté client. Aussi, les cookies devraient toujours posséder l’attribut HttpOnly, empêchant leur lecture par une couche Javascript et ce afin d’empêcher tout vol de session lors d’une attaque de type XSS. Pourtant, cet attribut empêche littéralement l’application front-end de travailler avec ces éléments. Comment gérer au mieux ces questions sur ce type de déploiement ?
L’architecture N’Tier
Pour rappel, ce type d’architecture divise une application en plusieurs niveaux distincts (ou tiers), chacun étant responsable d’une fonction spécifique. La présentation (le front-end), le niveau logique (back-end) et le niveau de données. Les avantages d’une structure de ce type sont multiples, on sépare les responsabilités, on évolue rapidement, les équipes de développement peuvent être cloisonnées, la maintenance est facilitée. Le prix à payer pour l’introduire résulte principalement dans la complexité de mise en œuvre. En effet, la conception et le déploiement peuvent être terriblement complexes et demandent une gestion de projet minutieuse, s’ajoute à cela une certaine latence de l’application.
Javascript le seul côté client
La technologie phare des environnements de travail “front-end”, est Javascript. Le code de ce langage est téléchargé et exécuté sur le navigateur de l’utilisateur. C’est ensuite le navigateur qui se charge d’aller chercher sur la couche logique les informations dynamiques liées à l’application. Durant la décennie 2010 plusieurs “framework” ont fait leur apparition :
- React.js
- Vue.js
- Angular
Dans une structure où l’application “front” serait hébergée sur un serveur A et la couche logique sur un serveur B, l’authentification devrait-être généralement gérée uniquement sur le serveur B. Cette structure simple, fonctionne correctement, car lors de l’appel à l’API du serveur B, ce dernier dispose sur le navigateur de l’utilisateur le cookie de session au moment de l’authentification.
- Authentification :
- L’utilisateur se connecte à l’application en fournissant ses informations
- Le serveur B vérifie les informations d’identification, génère un jeton ou un cookie de session, et renvoie ce jeton au client (navigateur).
- Stockage du cookie :
- Le navigateur stocke automatiquement le cookie de session localement.
- Appels à l’API :
- Lorsque l’application frontend sur le serveur « A » effectue des appels à l’API sur le serveur « B », le navigateur inclut automatiquement le cookie de session associé au domaine du serveur « B » dans les requêtes HTTP.
- Vérification côté serveur :
- Le serveur « B », recevant une requête avec le cookie de session, vérifie la validité du cookie. S’il est valide, le serveur considère l’utilisateur comme authentifié et traite la requête.
Dans ce cas, la couche “front-end” ne manipule pas le cookie, et n’en pas besoin, les cookies peuvent être définis avec les attributs de sécurités recommandés, “HttpOnly”, empêchant sa consultation par le Javascript.
Des cas spécifiques
Il existe pourtant des scénarios spécifiques dans lesquels l’accès au cookie côté front-end est souvent nécessaire, en particulier dans le contexte de l’authentification et de l’interaction avec des API sécurisées.
- Authentification : Lorsqu’un utilisateur se connecte à une application, le serveur d’authentification peut générer un jeton d’authentification et le stocker dans un cookie. Le front-end peut avoir besoin d’accéder à ce cookie pour inclure le jeton dans les entêtes des requêtes API ultérieures afin d’authentifier l’utilisateur.
- Gestion de session : Si les informations de session sont stockées dans des cookies, le front-end peut avoir besoin d’accéder à ces données pour personnaliser l’expérience utilisateur en fonction de l’état de la session (par exemple, afficher un panier d’achats, des préférences utilisateur, etc.).
- Suivi d’état : Certains cookies peuvent être utilisés pour suivre l’état de l’application côté client, par exemple pour mémoriser les préférences utilisateur ou d’autres données liées à l’expérience utilisateur.
- Utilisations d’API tierces : Le cookie peut être partagé entre plusieurs sous-domaines, et peut avoir une nécessité d’être modifié par l’application “front” selon les contraintes métiers.
Dans ces cas précis, il n’existe aucune solution pour sécuriser le cookie contre des attaques de type injection de code Javascript (XSS). Aussi, c’est sans surprise, que la recommandation est, et doit-être, de ne pas gérer les informations sensibles côté client. Aussi, une fois cet état de fait annoncé, que faire des autres cookies ? Et plus délicat, dans le cas d’une architecture déjà mise en place, où cette procédure aurait déjà été appliquée, il est irraisonnable, même pour un pentester, d’imaginer qu’une société va pouvoir changer le mécanisme d’authentification d’une structure N’Tier complexe en quelques semaines, voire quelques mois. Il est par exemple possible d’imaginer une application mobile, procédant à son authentification via le stockage de ses cookies, et l’application Web jumelle imitant le fonctionnement. Les équipes de développement gagnant du temps (et de l’argent) en reproduisant un mécanisme d’authentification via deux vecteurs, sans se rendre compte qu’elles ne respectaient pas les bonnes pratiques en matière de sécurité. La correction d’une telle erreur demande du temps et de l’investissement, comment limiter la casse ?
Le JWT dans le SessionStorage ou des durées de vie de Cookies extrêmement courtes
Il n’y a en vérité pas de recette miracle. Si de tels cas ont pu être observés, proposer une recommandation rapide n’est pas aisé, voire impossible. Une solution temporaire à moindre coût n’empêchant pas tout vol du cookie réside en premier lieu dans la réduction de sa durée de vie. L’autre solution, toujours temporaire et ne servant qu’à pallier un problème en attendant sa résolution finale, peut-être l’utilisation d’un JWT stocké dans le SessionStorage.
En réalité, ces deux solutions (qui n’en sont pas), sont identiques, puisque notre élément de connexion ne peut pas être sécurisé correctement, limitons sa durée de vie au maximum. Cet état de fait de négociation avec la sécurité ne devrait bien évidemment jamais se produire, mais se produit hélas bien trop souvent.
Cookies à durée de vie limitée :
L’avantage principal de cette solution réside dans sa facilité de mise en œuvre. En effet, les cookies sont envoyés automatiquement avec les requêtes HTTP. De plus, un cookie est révocable côté serveur. L’inconvénient principal, autre que le problème lié à sa lecture par Javascript, réside dans le risque d’attaque CSRF. Il faudra prévenir ce risque via l’utilisation de jeton à durée de vie limitée pour les formulaires et actions sensibles du site.
JWT dans le Session Storage :
L’utilisation d’un JWT permet une manipulation aisée côté client et apporte une meilleure protection contre les attaques de type CSRF. Néanmoins, le secret du JWT doit-être changé régulièrement, il nécessite un soin particulier quant à sa configuration, les attaques sur ce jeton étant nombreuses.
Il est inutile de rappeler que dans ce contexte, ces deux solutions sont sensibles aux attaques d’injections de code Javascript.
Mais le JWT ? N’est-ce pas le Cookie du futur ?
Il peut être intéressant à ce niveau de réfléchir à l’existence même du JWT. Ce dernier avait été pensé comme un cookie “intersites”, un élément de connexion auprès de différentes entités, hébergées sur des domaines différents. Son envoi dans les entêtes de requête étant manuel, sa lecture par le serveur distant n’était pas soumise aux mêmes contraintes qu’un cookie. La protection du JWT résidant dans un algorithme de chiffrement et de signature via un secret fort, servant à empêcher la modification des données qu’il vectorise. Rien dans ce mécanisme ne protège contre un vol de ce jeton, pire si sa durée de vie n’était pas soumise à limitation, un JWT dérobé sur un site tiers, permettait d’avoir un accès à l’ensemble des applications de l’infrastructure. Nous pourrions imaginer une injection de code Javascript sur un site « A », un JWT permettant de s’authentifier sur les sites « A », « B » et « C », le vol du jeton compromettant l’utilisateur sur l’ensemble de ce périmètre et non uniquement sur le site initial.
La réponse usuelle à ce problème, a été de mettre le JWT au sein des cookies… et d’y apposer l’attribut HttpOnly. Perdant ainsi l’avantage initial du jeton intersites.
Il n’est pas rare de voir des JWT injectés dans des cookies, puis, via la technologie “front” être envoyés au sein de l’entête HTTP dans le cadre d’une requête intersites. Ce fonctionnement expose grandement au vol des sessions, à la tentative de force brute sur le JWT et finalement à la compromission du compte.
La chose sensible est toujours côté serveur
Finalement, et ce n’est pas une surprise, la moindre délégation côté client d’un élément aussi sensible que l’authentification reste un risque difficilement maîtrisable. La sécurité n’étant jamais inviolable, mais une succession de couches de protection, à l’image d’une fortification Vauban. Une couche tombante, une autre prend le relais. Si une injection de code Javascript est découverte sur une application, une correcte configuration des cookies, de la CSP et des en-têtes de sécurité HTTP peuvent rendre totalement inexploitable la vulnérabilité.
Les authentifications via le Cloud
Le cloud semble se présenter aujourd’hui comme le futur des solutions Web complexes. Une solution de type SaaS voit son utilisation grandement simplifiée, l’hébergement, la configuration sont à la charge de l’hébergeur. Peut-être verrons-nous dans le futur un attrait pour ces solutions plus simples à maintenir, même pour des logiciels complexes et plus simples à sécuriser. L’authentification peut alors être totalement déléguée à une entité telle que Microsoft ou Google, et utiliser une technologie de type SSO, le cookie sera défini en HttpOnly et on retira la charge de l’authentification à notre technologie front-end.
Derniers articles
Sécuriser votre environnement cloud : stratégies essentielles et tests d’intrusion
Découvrez les meilleures pratiques pour sécuriser vos données cloud avec des stratégies de protection et des tests d’intrusion efficaces.
L’évolution marquante du métier de DPO en 2024 : chiffres clés et nouvelles tendances
Le métier de DPO connaît une croissance fulgurante de 64% et une diversification des profils en 2024. Entre défis et opportunités, découvrez les chiffres clés et les dernières tendances de cette profession essentielle dans la protection des données personnelles.