Résumé
- Dans la RFC 10017, le BFF est le client OAuth confidentiel : il conserve les jetons d’accès et de renouvellement derrière une session par cookie et les ajoute aux appels sortants. Le navigateur n’a donc aucun jeton existant à extraire et ne peut échanger seul un nouveau code d’autorisation.
- Un JavaScript malveillant exécuté dans l’origine de l’application peut cependant appeler les mêmes endpoints que le code légitime. Le navigateur joint le cookie, puis le BFF traduit la session en requête munie du jeton. Il s’agit d’un détournement du client, plus borné qu’un vol de jeton mais réel.
- La preuve doit suivre la traduction complète : origine et version du frontend, session et cookie, contrôle CSRF, endpoint, hôte/chemin/méthode permis, audience et portée du jeton, autorisation du serveur de ressources, réponse, anomalie et remédiation.
Le premier signe d’un incident BFF peut être l’absence de l’artefact que tout le monde cherche.
Aucun jeton n’apparaît dans le navigateur. Le cookie est HttpOnly. Les secrets du client n’ont pas quitté le serveur. Pourtant, une opération sensible a été exécutée depuis la session d’un utilisateur. La conclusion « aucun identifiant n’a été volé » est exacte et insuffisante.
Le code hostile n’avait pas besoin de devenir propriétaire du jeton. Il s’exécutait dans l’origine autorisée, a reproduit un appel du frontend et a laissé l’architecture fournir les pouvoirs nécessaires. Le navigateur a transmis la session ; le BFF a choisi le jeton ; le serveur de ressources a traité la requête.
La RFC 10017, OAuth 2.0 for Browser-Based Applications, place cette séquence au centre de son analyse. Publiée en août 2026 comme Best Current Practice de l’IETF, elle est signée collectivement par Aaron Parecki, Philippe De Ryck et David Waite. La fiche IETF de Parecki, conservée le 31 août 2026, le présente comme coprésident du groupe SCIM et rattache son nom à deux RFC, dont celle-ci. Son propre site mentionne son travail sur les normes d’identité, la maintenance d’oauth.net et sa participation au groupe OAuth de l’IETF.
Ces éléments attribuent une contribution ; ils ne transforment ni une RFC collective en invention personnelle, ni un auteur en garant des déploiements. La sécurité concrète dépend de la carte d’actions effectivement exécutée par chaque BFF.
La compromission n’a pas besoin d’emporter un jeton
La RFC commence après la rupture que beaucoup d’analyses essaient d’éviter : l’attaquant peut exécuter du JavaScript ou du WebAssembly dans le contexte de l’application. Son code partage alors les privilèges du code légitime. Il peut appeler des fonctions, modifier le déroulement, lire le stockage accessible et contacter le backend depuis l’origine attendue.
Prévenir cette exécution reste indispensable. L’encodage des sorties, la réduction des dépendances tierces, Subresource Integrity, une Content Security Policy stricte et l’isolation des origines limitent la possibilité d’obtenir ce point d’appui. Mais une architecture de jetons doit aussi expliquer les conséquences quand cette prévention échoue.
La RFC distingue le vol ponctuel, le vol persistant des jetons renouvelés, l’acquisition d’un nouveau jeu de jetons et le simple proxy de requêtes par le navigateur. Dans ce dernier scénario, l’attaquant n’extrait rien. Si le navigateur ou un composant externe ajoute automatiquement l’élément d’autorisation, la requête hostile reçoit le même traitement que la requête légitime.
Le stockage non exportable répond donc à une question précise : l’attaquant peut-il emporter le credential ? Il ne répond pas à l’autre : peut-il invoquer l’action pendant que l’application et la session fonctionnent ?
Le BFF change le détenteur du jeton
Parmi les trois architectures principales étudiées par la RFC, le BFF apporte les garanties les plus fortes. Le serveur devient le client OAuth confidentiel, exécute le code flow avec PKCE, conserve les jetons et relaie tous les appels vers les serveurs de ressources. La RFC le recommande fortement pour les applications professionnelles, sensibles ou traitant des données personnelles.
Le navigateur ne reçoit pas le jeton. Il reçoit une session matérialisée par un cookie. Lors d’un appel, le BFF retrouve l’état associé, retire le cookie de la requête sortante, choisit le jeton d’accès adapté et joint celui-ci avant de contacter le serveur de ressources.
Cette séparation détruit plusieurs capacités de l’attaquant. Il ne peut pas lire un access token existant, installer un mécanisme qui copie chaque refresh token ni échanger de son côté un code capturé, car il ne possède pas les credentials du client confidentiel. HttpOnly l’empêche aussi de lire directement l’état de session. Un détournement du client ne devient donc pas automatiquement une session portable utilisable sur une autre machine.
Le pouvoir restant est attaché au navigateur actif. Tant que le script s’exécute dans la bonne origine, il peut appeler les routes offertes au frontend. L’intérêt du BFF n’est pas d’identifier moralement le script ; il est de supprimer l’autorité autonome et exportable du navigateur, puis de contraindre la partie encore invocable.
Le proxy doit connaître toutes ses sorties
Le BFF est un traducteur d’autorité : à gauche, une requête porte une session ; à droite, une autre requête porte un jeton. Une destination contrôlée par l’entrée ferait de ce traducteur un service de fuite.
La RFC impose donc la validation des hôtes sortants et une liste explicite de serveurs de ressources autorisés. Les routes dynamiques doivent rester à l’intérieur de chemins approuvés. Restreindre les méthodes HTTP par endpoint réduit encore la surface : un chemin de consultation ne doit pas acquérir un DELETE parce que le proxy transmet aveuglément la méthode reçue.
Une liste d’hôtes seule ne suffit pas. Un domaine peut héberger l’API publique et l’administration. Un paramètre ou un corps peut contenir une URL. Une redirection peut quitter l’hôte vérifié. La politique reproductible relie donc hôte, scheme, modèle de chemin, méthode, schéma de la requête, règle de redirection, audience, scopes et classe de réponse.
Le serveur de ressources conserve son propre rôle. Il valide issuer, audience, expiration et permissions, puis décide l’objet et l’action. Un BFF étroit devant un serveur qui autorise trop largement ne fournit pas la même garantie qu’un BFF étroit suivi d’une autorisation objet par objet. La session authentifie une relation avec l’application ; elle ne confère pas un mandat universel.
Le cookie protège la session, pas l’intention
La RFC exige Secure et HttpOnly. Elle recommande SameSite=Strict, le chemin /, l’absence d’attribut Domain et, lorsque le navigateur le permet, un préfixe tel que __Host-Http-. Une session côté client contenant des jetons devrait être chiffrée afin que ces valeurs ne résident pas en clair sur le disque.
Chaque réglage ferme une voie identifiable : lecture par script, transport non chiffré, partage avec des sous-domaines, fixation ou exposition locale. Aucun ne prouve qu’une action correspond à l’intention présente de la personne.
L’authentification par cookie oblige aussi à traiter le CSRF. SameSite=Strict ne suffit pas toujours, car deux sous-domaines peuvent être same-site tout en étant cross-origin. La compromission d’un sous-domaine frère crée alors une voie de requête forgée.
CORS peut jouer le rôle de défense à condition de forcer un preflight. Les requêtes dites safelisted peuvent être envoyées avant que le navigateur interdise à l’origine appelante de lire la réponse. La RFC recommande donc un en-tête personnalisé et exige sa présence sur chaque requête si cette méthode est retenue. Les protections anti-forgery du framework constituent une autre option.
Ces défenses distinguent une origine externe de l’origine légitime. Elles ne distinguent pas, à l’intérieur de cette dernière, le code prévu du code hostile. Un contrôle CSRF réussi n’est pas un reçu de consentement humain.
Mesurer le pouvoir encore invocable
La RFC décrit le détournement du client comme moins puissant que le vol direct d’un jeton. L’attaquant reste soumis aux routes du BFF, aux politiques CORS et à l’autorisation du serveur de ressources ; il dépend également d’un navigateur et d’une exécution active. Cette différence doit être préservée, pas gommée par une formule alarmiste.
Mais elle doit être démontrée. Il faut inventorier chaque endpoint BFF, sa destination, son chemin, sa méthode, le token choisi, ses scopes, la règle d’objet attendue et les données renvoyées. Un test avec du code hostile de même origine doit tenter les combinaisons refusées, et non seulement vérifier un parcours normal de connexion.
Le BFF voit aussi le trafic complet. C’est un bon emplacement pour limiter le débit et détecter une séquence d’actions inhabituelle, un volume incompatible avec une interaction humaine, une nouvelle version du frontend qui appelle une ancienne route, ou une session qui continue après invalidation du refresh token. La même visibilité crée un enjeu de vie privée, surtout si le composant est opéré par un tiers : minimisation, durée de conservation, accès opérateur et séparation des tenants deviennent des contrôles de premier rang.
La durée de la session doit suivre le pouvoir qui la soutient. La RFC conseille de l’aligner sur la durée maximale du refresh token et d’invalider la session lorsque ce dernier n’est plus valable. Une session serveur offre une révocation directe mais exige réplication ou affinité ; une session côté client s’étend plus facilement mais dépend davantage de l’expiration et de la révocation des jetons.
Constituer le reçu de la requête à la décision
Le reçu ne doit jamais copier le jeton, le secret du client ou le cookie complet. Il doit conserver des liens sans créer de nouveaux credentials.
Pour une action sensible, enregistrer un identifiant de corrélation de session, sa création et son échéance, la version de politique du cookie, l’authentification et la transaction de code, l’identité du client BFF et la version du frontend. Ajouter endpoint entrant, méthode et modèle de chemin normalisés, résultat CSRF/origine/CORS et validation du schéma.
Puis décrire la traduction : serveur de ressources, chemin et méthode sortants, version de l’allowlist, identifiant ou empreinte non secrète du jeton, issuer, audience, scopes, expiration et événement de renouvellement ou de révocation pertinent. Conserver enfin la décision du serveur de ressources, le statut, la transformation de réponse, la décision d’anomalie ou de rate limit, le propriétaire du changement et la voie de remédiation.
Ce joint distingue l’exfiltration d’un jeton, le vol d’une session opaque, le CSRF, l’usage hostile de même origine, l’évasion du proxy et une autorisation aval trop large. Ces incidents n’ont ni le même responsable ni le même correctif.
Running-Code Primacy fournit l’épreuve finale. Exécuter un script hostile contrôlé dans l’origine. Vérifier qu’il ne lit ni jeton ni session, n’obtient pas de nouveau jeton, ne sort pas du tuple hôte/chemin/méthode, ne franchit pas l’autorisation objet, et laisse une alerte compréhensible lorsqu’il effectue une action autorisée mais anormale.
Le BFF est correctement borné lorsque le jeton ne peut pas sortir et que le pouvoir restant est étroit, observable et révocable.
Sources
- RFC 10017 — OAuth 2.0 for Browser-Based Applications
- RFC 9700 — Best Current Practice for OAuth 2.0 Security
- OAuth.net — OAuth 2.0 for Browser-Based Apps
- IETF Datatracker — Aaron Parecki
- Aaron Parecki — profil public
- Heng Lu — primauté du code exécuté
- Heng Lu — spécification initiale minimale
- Heng Lu — le problème d’agence
Briefing des membres
Contexte approfondi du profil
Connectez-vous avec le bon niveau d'adhésion pour débloquer le briefing complet et les notes de source.
Réservé à Strategic Circle
Strategic Circle
Ouvert à tous les lecteurs. Débloquez les briefings de profil après adhésion et connexion.
Rejoindre Strategic CircleRéservé aux membres de Leadership Alliance
Leadership Alliance
Réservé aux propriétaires et dirigeants qualifiés d'actifs IP ; connectez-vous pour débloquer les briefings Alliance.
Rejoindre Leadership Alliance
