Malheureusement, l’histoire nous montre que les applications Web frontend sont difficiles à sécuriser. XSS tourmente les applications Web depuis presque vingt ans. Alors que les structures modernes JavaScript l’améliorent un peu, il existe toujours de nombreux vecteurs d’attaque XSS potentiels dans les applications modernes. Ces récapitulatifs fournissent des précisions sur la sécurisation des applications React et Angular.
Alors le jeu est-il terminé ? Oui et non.
Du point de vue de la sécurité, il est virtuellement impossible de sécuriser des jetons dans une application Web frontend. Un code JavaScript malveillant peut faire tout ce qu’une application fait, donc si une application peut accéder à des jetons, le code malveillant le peut également. Les schémas de sécurité, consistant par exemple à cacher les jetons d’actualisation dans un Web Worker, peuvent aider mais ne sont pas une solution définitive pour lutter contre les scénarios présentés ci-dessus.
Concrètement, les applications frontend non sensibles peuvent s’appuyer sur des jetons d’actualisation avec rotation des jetons d’actualisation. Par exemple, une application qui gère les commentaires sur un restaurant n’est pas considérée comme sensible, ce qui réduit l’impact d’une attaque XSS réussie. Pour les applications sensibles, ce conseil n’est pas valable. Par exemple, les applications qui gèrent des informations personnelles, des données de santé ou des opérations financières sont extrêmement sensibles. Dans ces applications, une attaque XSS réussie a un impact considérable.
C’est pourquoi les applications frontend sensibles devraient éviter de gérer des jetons d’actualisation dans le navigateur. Au lieu de cela, elles peuvent s’appuyer sur un schéma Backend for Frontend (BFF), où la gestion des jetons est reportée sur un composant minimaliste du côté du serveur. L’image ci-dessous illustre le concept d’un BFF :
Les BFF sont traditionnellement utilisés pour agréger plusieurs API en une seule API cohérente pour servir une application client. Dans notre scénario, le BFF assume aussi un rôle de sécurité minimal. Il accepte les demandes de l’application client, les enrichit avec des jetons d’accès OAuth 2.0, et transfère les demandes à l’API. De même, toute réponse de l’API est transférée à l’application client.
Comment un BFF fonctionne en pratique ?
Les détails d’un BFF
Dans ce scénario, le BFF devient l’application client OAuth 2.0. Étant donné que le BFF fonctionne sur un système de backend, il peut être configuré comme un client privé. Le BFF est le client, donc il initialise le flux OAuth 2.0 qui circule dans le navigateur de l’utilisateur. Après la première étape du flux, le BFF reçoit un code d’autorisation, qu’il échange contre des jetons avec le serveur d’autorisation utilisant l’authentification client. Avec le jeton d’accès, le BFF peut transférer des demandes d’API. Avec le jeton d’actualisation, le BFF peut obtenir un nouveau jeton d’accès lorsque cela est nécessaire. Notez que pour utiliser un jeton d’actualisation, il faut que le BFF s’authentifie sur le serveur d’autorisation.
Un BFF est partagé entre des centaines voire des milliers d’exemples de clients, chacun fonctionnant au nom d’un utilisateur différent. Le BFF garde la trace de ces utilisateurs avec une session basée sur un cookie. Le BFF peut garder la session sur le serveur (par exemple dans une simple mémoire de stockage) ou la pousser vers le client (par exemple dans un objet de session chiffré). Le premier entraîne un BFF avec un statut, tandis que le second permet au BFF de ne pas avoir de statut. Les deux approches sont valables.
Notez que le BFF doit suivre les bonnes pratiques de sécurité des cookies pour garantir la sécurité de ce cookie. Concrètement, cela signifie que pour établir un cookie avec le nom « MyBFFCookie », l’en-tête suivant doit être utilisé : Set-Cookie: __Host-MyBFFCookie=…; Secure; HttpOnly; SameSite. Obtenir plus d’informations sur la sécurité des cookies.
Lorsque le client envoie une demande, le BFF utilise les informations de la session dans la demande pour récupérer les jetons de l’utilisateur. Si le jeton d’accès est toujours valide, le BFF peut transférer directement la demande. Si le jeton d’accès a expiré, le BFF utilise le jeton d’actualisation de l’utilisateur pour obtenir un nouveau jeton d’accès avant de transférer la demande.
Enfin, notez que du point de vue de l’utilisateur, rien ne change. L’expérience utilisateur entre une application client frontend et une application frontend soutenue par un BFF est identique.
Les avantages d’un BFF
Un backend-for-fronted offre des avantages de sécurité considérables par rapport aux applications basées sur des navigateurs. Le BFF agit comme le client OAuth 2.0, en lui permettant d’appliquer les bonnes pratiques de sécurité pour les clients privés. Concrètement, cela signifie que :
Le BFF doit s’authentifier auprès du serveur d’autorisation lorsqu’il échange un code d’autorisation ou un jeton d’actualisation.
Le BFF peut s’appuyer sur des mécanismes d’authentification solides basés sur des clés (par ex. mTLS).
Le BFF peut utiliser des jetons d’accès sender-constrained et des jetons d’actualisation sender-constrained.
Les jetons d’accès et les jetons d’actualisation ne sont jamais exposés au navigateur.
Mais qu’en est-il des codes JavaScript potentiellement malveillants fonctionnant dans l’application frontend ? Dans ce scénario, le code malveillant ne peut plus accéder aux jetons puisqu’ils ne sont disponibles que pour le BFF. Les mesures de sécurité des cookies (par ex. l’attribut HttpOnly) empêchent le code malveillant de voler la session avec le BFF.
Le code malveillant peut toujours modifier le comportement de l’application client. Concrètement, l’attaquant peut réaliser une attaque par détournement de session ou session riding, en envoyant des appels d’API malveillants à travers le BFF. Ces appels d’API ne peuvent pas être distingués des demandes légitimes envoyées par le client.
Toutefois, ici, le BFF contrôle tout. Par conséquent, le BFF peut limiter la surface d’API en empêchant le client d’accéder à certains terminaux. De plus, le BFF peut appliquer des schémas d’analyse du trafic pour détecter des comportements douteux. Il peut s’agir par exemple de détecter un nombre étonnement suspect d’opérations ou d’observer des opérations sensibles réalisées dans un ordre inattendu.
Enfin, il ne faut pas oublier que le BFF ne fait rien pour arrêter l’exécution du code malveillant. L’attaquant peut toujours extraire des informations sensibles ou réaliser des attaques par social engineering sur l’utilisateur. Le seul moyen d’empêcher ces attaques est de suivre des directives de codage sécurisé pour l’application frontend.