Guide de lecture des recommandations OpenID Connect de l’ANSSI
L’ANSSI a publié début septembre des « recommandations pour la sécurisation de la mise en œuvre du protocole OpenID Connect« .
Comme toutes les publications de l’ANSSI, ce document regorge de conseils pertinents. L’application de l’ensemble des recommandations est souhaitable et renforcera un niveau de sécurité déjà élevé.
Or le document est aussi très théorique et sa lecture est parfois ardue. On sent qu’une étude minutieuse de la norme a été conduite, mais il manque un recul pratique soutenu par du vécu et de l’expérience.
C’est bien normal pour des recommandations, qui ne sont pas des exigences à remplir obligatoirement. Elles doivent être comprises dans le contexte des applications à protéger et, comme le rappelle le document, après une étude et une analyse de risques.
On résume ici notre analyse de cette publication de l’ANSSI et on essaie d’apporter des éléments de réflexion pour éclairer le lecteur dans les décisions qu’il sera amené à prendre pour ses projets concrets.
Les relations complexes entre OpenID Connect et OAuth 2
On a coutume de dire comme l’ANSSI que « la norme OIDC complète le protocole OAuth 2.0 ». C’est vrai, mais c’est plus compliqué. Les deux protocoles n’ont pas du tout la même finalité.
OAuth 2 est apparu d’abord, dans un contexte d’autorisation d’accès à des services web par une application tierce, soit pour son compte propre, soit pour le compte de l’utilisateur de l’application. Dans ce schéma, on retrouve la notion de client (l’application) et de Resource server (le service web).
OpenID Connect s’applique à un autre cas : l’authentification à une application. Dans son cas d’usage strict, le Resource server disparaît et il reste plus que le client (l’application). Il ne s’agit plus d’ouvrir l’accès à un service web, mais d’authentifier un utilisateur auprès d’une application.
La finalité des normes est donc très différente :
• OAuth 2 donne des autorisation d’accès à un service web (sans interaction directe avec un utilisateur qui n’existe pas toujours), sous la forme d’un jeton d’accès
• OpenID Connect transmet des informations sur l’identité d’une personne qui souhaite se connecter à une application, grâce à un jeton d’identité
Schématiquement, OAuth 2 manipule des jetons d’accès et OpenID Connect des jetons d’identité.
On a donc deux notions bien distinctes, mais avec des points de conjonction. OpenID Connect reprend en effet les concepts et les cinématiques d’OAuth 2, en les adaptant pour son cas d’usage. Ensuite, OpenID Connect fait usage de services web dans ses cinématiques et les sécurise par OAuth 2. Elle fait donc usage en interne de jetons d’accès.
Les deux protocoles sont d’ailleurs souvent utilisés en conjonction, dans la situation où une application doit à la fois authentifier ses utilisateurs et faire appel à des services web. La proximité des normes simplifie l’architecture en rassemblant dans un même serveur les fonctions d’authentification et d’autorisation.
On notera au passage que l’on parle ici d’authentification par abus de langage. Il s’agit en fait techniquement de transmettre à l’application l’identité de l’utilisateur. Les recommandations de l’ANSSI le soulignent avec raison : la phase concrète d’authentification n’est pas couverte par la norme OpenID Connect. Elle est laissée à l’appréciation du fournisseur d’identité, qui fera la vérification par mot de passe, par authentification à facteurs multiples, ou qui pourra même la déléguer à un autre serveur.
Cette délégation se fait d’ailleurs elle-même par OIDC : le fournisseur d’identité devient alors l’application qui confie son authentification à un autre fournisseur d’identité. Qui peut à son tour continuer le mouvement en se tournant vers un troisième fournisseur d’identité.
C’est par exemple la manière de fonctionner de France Connect.
Le fournisseur de données n’a pas sa place dans la liste des acteurs
Le chapitre précédent permet de clarifier une petite confusion dans la liste des acteurs des recommandations. Elle contient l’utilisateur, le fournisseur de service (l’application), le fournisseur d’identité et le fournisseur de données (Resource server).
Or si ce dernier est en jeu dans la norme OAuth 2 (c’est le service web), mais il n’intervient en aucune manière dans OIDC qui réalise l’authentification de l’utilisateur d’une application.
Les nouvelles cinématiques OpenID Connect
Les recommandations de l’ANSSI présentent les trois cinématiques initiales de la norme : authorization code, implicit et hybrid.
La cinématique authorization code a été conçue pour les applications web classiques, où les traitements se font au niveau d’un serveur d’application qui a besoin de l’identité de l’utilisateur pour vérifier ses habilitations. Pour cela, l’application récupère un jeton d’identité directement du fournisseur d’identité, sans qu’il passe par le navigateur, dans une relation de serveur à serveur qui limite les possibilités d’usurpation d’identité et d’élévation de privilège.
Or avec les applications modernes s’exécutant directement dans les navigateurs (SPA pour Single Page Application), la notion d’échange serveur à serveur n’a pas de sens. Et d’ailleurs la notion même d’authentification auprès de l’application n’a pas tellement de sens. L’utilisateur ayant le contrôle de son navigateur, il peut modifier toutes les données qui s’y trouvent.
En revanche, ce qui est important, c’est que ces applications SPA (ou mobiles) se connectent à un backend par des services web, et là la notion d’habilitation retrouve tout son sens. Mais on sort du périmètre OpenID Connect pour entrer dans celui d’OAuth 2. Pour une application SPA, le jeton d’identité n’est pas utile à la sécurité, mais le jeton d’accès l’est.
Il n’est pas inutile à ce stade de faire un petit détour vers la sécurisation des SPA. Ce type d’application s’est développé de manière importante car elles permettent une réactivité inégalée de l’interface et donc une amélioration sensible de l’expérience utilisateur. Les applications se sont alors séparées en deux : la présentation au niveau du navigateur (frontend) et les traitements sur le serveur (backend). Il n’est pas illégitime de pousser la logique jusqu’au bout et de casser le lien entre les deux composantes pour en faire deux applications distinctes : une SPA sur le navigateur qui appelle des API sur le serveur.
Le backend se transforme alors en service web indépendant, et il peut même se démultiplier en microservices. Le nouveau service web entre alors en plein dans le champ d’application d’OAuth 2 et du jeton d’accès.
Sauf que le jeton d’accès est une information critique car s’il est intercepté il peut être rejoué sans qu’il soit la plupart du temps possible de trouver le moyen de s’y opposer. Dans l’architecture SPA + API, l’application qui s’exécute sur le navigateur doit détenir le jeton d’accès pour le présenter à l’API. Or il est impossible à l’heure actuelle de garantir la protection du jeton d’accès dans le navigateur.
Le moyen le plus efficace de protéger l’accès d’une SPA à un backend reste la session HTTP et son cookie HttpOnly qui le rend inaccessible. Il est illusoire de vouloir conjuguer de manière sécurisée SPA et jeton d’accès. L’architecture avec un frontend et un backend dédié reliés par une session HTTP est donc préférable du point de vue de la sécurité.
Les applications mobiles sont un cas différent car avec le modèle actuel, on ne s’attend pas à s’authentifier à chaque fois qu’on accède à une app. On dispose de moyens de protections dédiés (keystore Android et keychain iOS) et on déporte une partie de la sécurité au niveau de l’équipement qui se déverrouille par PIN ou par biométrie.
Il est donc acceptable que les app mobiles conservent en propre non seulement des jetons d’accès, mais encore des jetons de rafraîchissement donnant accès aux backend dans la durée.
Pour en revenir à OpenID Connect, la norme a proposé pour les SPA (malgré les réserves présentées ci-dessus) et pour les app mobiles une cinématique appelée implicit calquée sur la cinématique OAuth 2 correspondante. L’application récupère directement deux jetons en retour d’authentification : un jeton d’accès pour sécuriser les appels au backend et un jeton d’identité pour afficher des informations sur l’utilisateur.
Or la cinématique implicit d’OAuth 2 a été abandonnée en 2018 à cause de problèmes de sécurité (possibilité de fuite ou d’injection de jeton).
Il ne reste alors plus que la cinématique authorization_code. Mais appliquée strictement aux SPA et app mobiles, elle pose un problème de diffusion de mot de passe. La cinématique requiert en effet un secret pour sécuriser l’échange du code contre les jetons. Il faudrait alors que le mot de passe soit présent dans les navigateurs et sur les mobiles, ce qui ferait basculer son statut de secret à public.
Pour résoudre le problème, OAuth 2 a ajouté à la cinématique authorization code une méthode de vérification alternative lors de l’échange, appelée Proof Key for Code Exchange (PKCE). On donne plus de détails un peu plus bas.
Du fait de la grande proximité des cinématiques entre les deux protocoles, PKCE a pu être adapté à OpenID Connect. Face à un rival mieux sécurisé, la cinématique implicit d’OpenID Connect n’est plus recommandée (même si elle est plus sécurisé que son pendant OAuth 2) et les bonnes pratiques lui préfèrent authorization code avec PKCE.
Maintenant qu’en est-il de la cinématique hybride ? Elle permet de récupérer directement un jeton d’identité par retour d’authentification et d’obtenir un jeton d’accès de manière sécurisée en échange d’un code à usage unique. Son utilité est cependant discutable. Elle se justifie si l’application souhaite réaliser un traitement immédiat sur l’identité, avant de récupérer le jeton d’accès par la suite. Certains avancent un cas d’usage où le jeton d’identité est intercepté par une SPA sur le navigateur et où le code est récupéré par le backend pour obtention d’un jeton d’accès.
Le jeton d’accès doit alors être considéré comme public, ne contenir aucune information confidentielle et être considéré comme potentiellement falsifié. Il sort du champ de la sécurisation, aux yeux de laquelle la cinématique hybride se comporte comme la cinématiques authorization code.
Il ne reste donc plus effectivement que la seule cinématique authorization code (avec ou sans PKCE).
La recommandation R1 est donc correcte (utiliser en priorité authorization code), et pourrait avantageusement être complétée par des considérations sur la sécurité des SPA et des app mobiles, et par une référence à PKCE.
HTTPS est la fondation d’OpenID Connect
La recommandation R3 demande que toutes les communications soient sécurisées par le protocole TLS.
C’est en effet fondamental, car l’essentiel de la sécurité d’OAuth 2, et par extension d’OpenID Connect, repose sur HTTPS.
Les concepteurs d’OAuth 2 sont partis du retour d’expérience mitigé de la norme SAML, qui a réussi à s’imposer pour l’authentification des applications cloud, mais qui avait du mal à se généraliser aux autres applications. La complexité des exigences de sécurité ont limité le nombre de bibliothèques disponibles. Pendant longtemps, il a même été difficile de trouver un module SAML pour Java (pourtant langage le plus populaire). La raison en était qu’il fallait coder des fonctions de sécurité avancées, en particulier la signature et le chiffrement de documents XML. Or la cryptographie n’est pas à la portée de tout le monde.
Avec OAuth 2, une partie importante de la sécurité a été déportée vers le protocole HTTPS. Il a l’avantage d’être implémenté dans tous les langages ; c’est un composant facile à mettre en place, sécurisé et bien compris. On limite par là-même la possibilité de vulnérabilités introduites par l’inexpérience.
Il n’a cependant pas été possible de couvrir toute la sécurité par HTTPS. Il reste au moins une fonction de cryptographie : la vérification de signature des JWT.
Pour en revenir à HTTPS, la recommandation R7 sur le certificate pinning est difficile à mettre en oeuvre. Elle consiste à installer une référence au certificat du serveur au sein de l’application qui demande l’authentification. On en perçoit bien les bénéfices théoriques, mais la mise en pratique s’annonce laborieuse. L’expiration du certificat devra être anticipée à l’avance pour s’assurer d’installer le nouveau dans toutes les applications, avant de l’installer sur le serveur, puis de repasser sur toutes les applications pour retirer celui qui n’est plus valable.
Augmenter la sécurité des demandes d’authentification par des contraintes supplémentaires risque d’avoir l’effet inverse
La demande d’authentification est le point de départ de la cinématique d’authentification. Elle correspond à la redirection de l’utilisateur vers le fournisseur d’identité qui doit l’authentifier. A cette occasion, une demande est formalisée, sous la forme d’une requête d’authentification.
Cette requête donne au serveur des précisions sur le processus à suivre : essentiellement le protocole, la cinématique et l’URL de retour (pour savoir où, au sein de l’application, renvoyer l’utilisateur une fois qu’il sera identifié).
Les recommandations R8 et R8+ conseillent de signer la requête pour éviter toute manipulation de la requête. Ça part d’un bon sentiment. En théorie, plus on signe et plus on chiffre, et plus on est sécurisé.
Mais ça, c’est la théorie. Dans la pratique, trop de signature et trop de chiffrement a l’effet inverse. Comme partout en sécurité, à mesure que les exigences augmentent, les utilisateurs trouvent des moyens de contournement qui abaissent le niveau général.
C’est ce qu’illustre l’expérience SAML, qui était la norme d’authentification avant qu’apparaisse OIDC.
Replaçons nous dans le contexte. On partait d’une situation où les applications géraient elles-mêmes leur authentification, avec les conséquences qui ont fait les titres de la presse informatique : fuite de mots de passe mal protégés, vulnérabilités exploitées des fonctions d’authentification, difficultés à mettre en place des authentifications fortes, impossibilité d’adapter l’authentification au contexte de l’utilisateur.
Replaçons nous dans le contexte. On partait d’une situation où les applications géraient elles-mêmes leur authentification, avec les conséquences qui ont fait les titres de la presse informatique : fuite de mots de passe mal protégés, vulnérabilités exploitées des fonctions d’authentification, difficultés à mettre en place des authentifications fortes, impossibilité d’adapter l’authentification au contexte de l’utilisateur.
La fédération des identités, avec SAML, a proposé une avancée concrète en déléguant la fonction d’authentification à des serveurs spécialisés et sécurisés, intégrant des mécanismes de protection contre les attaques et ouverts vers les différentes méthodes d’authentification. Mais son adoption s’est largement limitée aux services dans le cloud.
La raison en est évidente pour qui a interfacé une application en SAML : la lourdeur et la complexité de la norme. Il faut échanger des métadonnées, faire de la signature et du chiffrement XML, préciser tous les types de données. En cas d’incompatibilité, l’authentification tombe en erreur. Résultat : il existait très peu de bibliothèques SAML, qui étaient souvent incomplètes. L’authentification est restée intégrée aux applications, avec tous les problèmes de sécurité associés.
Fort de ce constat, la norme OIDC a été pensée comme simple et efficace, ce qui s’est traduit par une large adoption dans les entreprises. Non seulement l’offre en bibliothèques est pléthorique, mais l’interfaçage d’une application, tout en étant toujours relativement complexe, reste à la portée de chacun.
Les recommandations R8 et R8+ sont dans l’absolu souhaitables, mais dans la réalité elles représentent dans la plupart des cas une barrière inutile qui freinera la diffusion de la fédération des identités. Les applications conserveront plus longtemps leur authentification interne, et leur niveau de sécurité discutable.
Il existe cependant des moyens de renforcer la sécurité sans prôner le tout cryptographie.
L’ANSSI nous indique que le risque le plus important en phase de requête d’authentification, c’est qu’un tiers manipule le champ scope utilisé pour demander des claims, c’est-à-dire des informations personnelles sur l’utilisateur. Effectivement, si quelqu’un écoute les échanges, il ne faut pas qu’il puisse demander subrepticement le numéro INSEE (NIR) de la personne et l’obtenir.
Pour empêcher cela, on conseille de fixer au niveau du serveur la liste des informations transmises à une application donnée. Et c’est d’ailleurs une bonne pratique mise en œuvre par la plupart des fournisseurs d’identité : ce n’est pas parce qu’une application demande une information qu’on va la lui donner.
Faire mieux que la norme n’est pas toujours souhaitable
Les recommandations s’intéressent de près aux capacités de sécurité du fournisseur d’identité, afin de guider les administrations dans le choix du serveur chargé de réaliser l’authentification.
Les conseils sont pertinents, qu’ils soient généraux comme sur les algorithmes de cryptographie, ou plus spécifiques comme sur la conservation des jetons.
Il arrive cependant que les recommandations aillent à l’encontre de la norme OpenID Connect. L’ANSSI relève d’ailleurs le point et avertit le lecteur que « les implémentations certifiées par la fondation OpenID respectent strictement la norme OIDC » et que la recommandation concernée ne pourra pas être mise en oeuvre par un tel fournisseur d’identité.
L’ANSSI est dans son rôle quand elle fait une lecture critique des normes pour pointer leurs insuffisances.
Mais dans le cadre de l’authentification, le respect de la norme est le garant de la bonne interopérabilité entre les systèmes. La décision d’en sortir doit être prise en pleine conscience des conséquences. Elle restreint l’éventail des choix, et impose souvent un développement complémentaire.
Car si les éditeurs et développeurs de fournisseurs d’identité ont en effet intérêt à proposer des fonctions différenciatrices, ils le font toujours dans le cadre de la norme pour des raisons évidentes.
Fort heureusement les recommandations en question portent la plupart du temps sur la possibilité d’imposer un comportement aux applications. Une telle obligation ne passe pas nécessairement par des moyens techniques, elle peut se faire juridiquement dans le cadre du contrat de service avec les applications.
A l’inverse, la recommandation R17 est une obligation déjà imposée par la norme OpenID Connect. Elle s’applique une fois l’authentification réalisée, lorsque le fournisseur d’identité redonne la main à l’application. C’est fait par une redirection vers une URL fournie lors de la demande d’authentification. La norme indique qu’elle ne peut se faire que vers des URL dûment enregistrées au préalable, pour éviter qu’un attaquant ayant réussi à modifier la requête d’authentification ne dirige les utilisateurs vers un serveur qu’il contrôle, d’où il récupèrera les jetons des utilisateurs.
L’authentification du client nécessite quelques compléments
Dans la cinématique d’authentification, les jetons ne sont pas transmis directement lors du retour du fournisseur d’identité vers l’application. Ce retour s’opère en effet par redirection et les jetons transiteraient par le navigateur de l’utilisateur qui est un point faible en termes de sécurité. Les jetons peuvent y être interceptés, possiblement par un attaquant, et très facilement pour l’utilisateur lui-même qui pourra tenter de les altérer à son profit.
A la place d’un jeton, c’est un code à usage unique qui est transmis, et qui est utilisé par l’application lors d’un échange direct avec le fournisseur d’identité pour récupérer les jetons. Pour cela, l’application (appelée client) doit au préalable s’authentifier pour éviter qu’un attaquant ayant récupéré un code puisse s’en servir.
La norme propose plusieurs méthodes : le simple mot de passe ou la signature d’un jeton (HMAC ou clés asymétriques). L’ANSSI ne tranche pas et conseille d’utiliser le moyen le plus approprié dans le contexte de l’application.
Les échanges se faisant en HTTPS entre deux serveurs, on considère souvent que la fourniture du mot de passe est suffisante. On n’envisagera les méthodes par signature que si le risque d’écoute des échanges est fort.
Ce qui est toutefois passé sous silence, c’est la protection du mot de passe par l’application. L’ANSSI semble se placer dans le cadre exclusif de l’application web classique exécutée sur un serveur.
Or OpenID Connect n’est pas utilisé que dans cette unique configuration. Les applications de type page unique (SPA) ou les apps mobiles entrent certes dans le cas d’usage OAuth 2 (récupération d’informations auprès d’un backend), mais ont aussi parfois besoin dans un premier temps de vérifier que l’utilisateur a bien accès à l’application. Le point a été développé plus haut.
Elle commencent donc par vérifier un jeton d’identité et ne font parfois appel au backend que suite à une sollicitation de l’utilisateur.
Dans le cas des SPA, on préfère protéger les jetons (en particulier le jeton OAuth 2 de rafraîchissement) au sein d’un serveur dans un backend dédié, mais certaines applications décident de s’en passer, conservent un jeton d’accès localement et le renouvellent par réauthentification transparente. Les apps mobiles conservent souvent en interne le jeton de rafraîchissement.
Ce qui fait qu’on a bien, en OpenID Connect, des cas légitimes de clients publics, c’est-à-dire de récupération de jeton d’identité directement par une application non protégée : sur un navigateur ou dans un mobile.
La phase d’échange du code contre des jetons pose alors problème, car l’application doit être authentifiée auprès du fournisseur d’identité. Elle devrait donc contenir un secret, mais dans un navigateur ou dans un téléphone, rien n’est secret.
La cinématique implicit avait été prévue pour ce cas d’usage, mais la transmission directe des jetons pose problème. Un complément à la norme OAuth 2, repris par OIDC, a ensuite été produit pour adresser ce problème. Il est appelé PKCE et au lieu d’authentifier le client en tant que tel, il assure que les jetons sont bien donnés à l’application qui en a fait la demande.
La bonne pratique est maintenant pour les clients publics d’utiliser PKCE (prononcer pixy) pour la récupération des jetons en échange du code à usage unique.
En attente de conseils sur les niveaux de sécurité
La recommandation R29 suggère de vérifier que le niveau de sécurité de l’authentification demandé correspond bien à celui obtenu. On peut en effet exiger dans la requête d’authentification qu’elle soit réalisée avec plusieurs facteurs (authentification forte). Il convient ensuite vérifier que l’authentification qui a été effectivement réalisée correspond bien à l’exigence de départ.
On aurait aimé que l’ANSSI nous éclaire sur ces niveaux de sécurité, en donnant des définitions, en explicitant la manière de les appliquer, en indiquant comment les vérifier, etc.
L’annexe B3 du RGS traite de l’authentification, mais elle date de 2010 et elle n’aborde pas la question.
L’Europe avec eIDAS définit trois niveaux. L’ISO avec ISO/IEC 29115 en définit quatre. L’IANA maintient un registre des niveaux de sécurité où l’on retrouve un peu n’importe quoi. De son côté aux Etats-Unis le NIST a produit une documentation extensive et traite l’identité, l’authentification et la fédération, avec trois niveaux pour chaque.
Dans ce déferlement d’informations pas toujours exploitables, les conseils de l’ANSSI seraient les bienvenus.
Informations personnelles dans le jeton ou par userinfo
La norme définit deux moyens pour une application de récupérer des informations personnelles lors de la phase d’authentification. Le premier consiste à enrichir le jeton d’identité et le second correspond à utiliser un service web (appelé userinfo).
Les recommandations ne se prononcent pas sur ce qu’il convient d’utiliser. Pourtant les deux options ne sont pas équivalentes.
Le jeton d’identité est en effet une entité qui est susceptible d’être diffusée. Dans le cas des clients publics (SPA et app mobiles), il est récupérable facilement par l’utilisateur et risque d’être dérobé.
On préférera donc n’enrichir le jeton qu’avec des informations non confidentielles, à moins qu’on soit certain de sa bonne protection. Le service web userinfo est plus sécurisé et il doit être privilégié pour les données critiques.
Ces principes s’appliquent pleinement dans un cadre OAuth 2 puisque le jeton d’accès est par nature échangé entre l’application et le service web, et qu’il a donc besoin d’être protégé. Si on sort ici du cadre strict d’OpenID Connect, on a d’une manière générale intérêt à étendre les bonnes pratiques aux deux protocoles.
Ces suggestions doivent cependant être tempérés par les capacités techniques des fournisseurs d’identités qui n’offrent pas tous les mêmes libertés dans la configuration des données (claims). Il existe ainsi des systèmes qui n’autorisent pas l’enrichissement du jeton, pourtant prévu par la norme. D’autres publient exactement les mêmes informations dans les jetons et dans le service web userinfo, sans possibilité d’en restreindre le nombre dans le jeton.
On aura donc intérêt à privilégier les fournisseurs d’identité qui se montrent souples dans la configuration de la diffusion des claims.
Bien vérifier la validité du jeton
Ceux qui n’ont jamais touché à la cryptographie sont enclins à vouloir tout chiffrer pour adresser tous les problèmes de sécurité.
Ceux qui l’ont pratiquée vous le diront : « cryptography is hard ». Même pour les experts. En 2013 une base de 38 millions de mots de passe a fuité d’Adobe. Mais heureusement, elle était chiffrée. Ouf. Sauf que ce qui était chiffré, c’était juste le mot de passe, et avec un algorithme réversible et sans « sel ». Une simple analyse statistique aurait permis de découvrir les mots de passe de nombreux comptes (dans les faits, la fuite a aussi concerné les indices de mot de passe associés, ce qui a rendu la tâche des hackers encore plus facile).
L’ANSSI recommande avec R44 de fixer l’algorithme de signature des jetons (quand c’est possible, ce qui n’est pas toujours le cas…). C’est important, car les attaquants ont plusieurs moyens faciles de contrefaire un jeton en jouant sur ces algorithmes.
Le plus simple, c’est de fabriquer son propre jeton et de ne pas le signer du tout. A la place, on indique dans le jeton que l’algorithme none a été utilisé. En application stricte des normes, le jeton est tout à fait valide et sera accepté.
Depuis que ce problème a été découvert, les bibliothèques de vérification des jetons doivent rejeter cet algorithme. La vérification se faisant du côté de l’application, il ne sera pas inutile de s’assurer que la bibliothèque OIDC utilisée est correcte sur ce point.
Les attaquants disposent d’un autre moyen pour profiter des bibliothèques mal sécurisées. Certaines par exemple utilisent la même méthode pour vérifier les signatures HMAC et asymétriques. Or si dans le premier cas la clé est privée (et protégée), dans le second elle est publique. Un attaquant mettant la main dessus, il pourra l’utiliser pour signer son jeton contrefait en HMAC et la bibliothèque validera le jeton.
On devra donc au moins indiquer à la bibliothèque le type de signature que le serveur utilise.
Dans l’immense majorité des cas, les fournisseurs d’identité font des signatures par clés asymétriques, dont ils mettent la clé publique à disposition par l’endpoint JWKS.
Cet endpoint assure la sécurité de la vérification de signature. La clé publique est récupérée en direct depuis l’endpoint protégé par HTTPS (dont on validera le certificat). On s’assure de ce fait de sa validité (l’invalidation des clés compromises est connue en temps réel). De plus, elle est publiée avec ses métadonnées, qui sont utilisées par les bibliothèques de vérification (type de clé, algorithme, finalité).
Il est fortement encouragé de procéder de la sorte. On s’évite les contraintes des certificats (renouvellement, intégration des certificats racines) tout en assurant un niveau de sécurité supérieur.
Conclusion
Les recommandations de l’ANSSI sur la sécurité OpenID Connect sont un outil précieux pour bien choisir un fournisseur d’identité et pour réaliser de manière sécurisée l’authentification des applications.
Elles restent cependant des recommandations dont l’application reste du ressort de chaque projet. Dans cette optique, elles manquent toutefois parfois d’éléments sur lesquels asseoir les décisions.
Avec le recul de plus de 10 ans de mise en place de solutions de fédération des identités, nous espérons avoir éclairé le lecteur sur la mise en place concrète des mesures recommandées.
Et comme tout le monde, nous attendons avec impatience des recommandations similaires sur la sécurisation d’OAuth 2, le protocole d’autorisation des services web, en ces temps où les architectures reposant sur des API sont en vogue.
Auteur : Marc (Directeur technique)
Guide de lecture des recommandations OpenID Connect de l’ANSSI
L’ANSSI a publié début septembre des « recommandations pour la sécurisation de la mise en œuvre du protocole OpenID Connect« .
Comme toutes les publications de l’ANSSI, ce document regorge de conseils pertinents. L’application de l’ensemble des recommandations est souhaitable et renforcera un niveau de sécurité déjà élevé.
Or le document est aussi très théorique et sa lecture est parfois ardue. On sent qu’une étude minutieuse de la norme a été conduite, mais il manque un recul pratique soutenu par du vécu et de l’expérience.
C’est bien normal pour des recommandations, qui ne sont pas des exigences à remplir obligatoirement. Elles doivent être comprises dans le contexte des applications à protéger et, comme le rappelle le document, après une étude et une analyse de risques.
On résume ici notre analyse de cette publication de l’ANSSI et on essaie d’apporter des éléments de réflexion pour éclairer le lecteur dans les décisions qu’il sera amené à prendre pour ses projets concrets.
Les relations complexes entre OpenID Connect et OAuth 2
On a coutume de dire comme l’ANSSI que « la norme OIDC complète le protocole OAuth 2.0 ». C’est vrai, mais c’est plus compliqué. Les deux protocoles n’ont pas du tout la même finalité.
OAuth 2 est apparu d’abord, dans un contexte d’autorisation d’accès à des services web par une application tierce, soit pour son compte propre, soit pour le compte de l’utilisateur de l’application. Dans ce schéma, on retrouve la notion de client (l’application) et de Resource server (le service web).
OpenID Connect s’applique à un autre cas : l’authentification à une application. Dans son cas d’usage strict, le Resource server disparaît et il reste plus que le client (l’application). Il ne s’agit plus d’ouvrir l’accès à un service web, mais d’authentifier un utilisateur auprès d’une application.
La finalité des normes est donc très différente :
• OAuth 2 donne des autorisation d’accès à un service web (sans interaction directe avec un utilisateur qui n’existe pas toujours), sous la forme d’un jeton d’accès
• OpenID Connect transmet des informations sur l’identité d’une personne qui souhaite se connecter à une application, grâce à un jeton d’identité
Schématiquement, OAuth 2 manipule des jetons d’accès et OpenID Connect des jetons d’identité.
On a donc deux notions bien distinctes, mais avec des points de conjonction. OpenID Connect reprend en effet les concepts et les cinématiques d’OAuth 2, en les adaptant pour son cas d’usage. Ensuite, OpenID Connect fait usage de services web dans ses cinématiques et les sécurise par OAuth 2. Elle fait donc usage en interne de jetons d’accès.
Les deux protocoles sont d’ailleurs souvent utilisés en conjonction, dans la situation où une application doit à la fois authentifier ses utilisateurs et faire appel à des services web. La proximité des normes simplifie l’architecture en rassemblant dans un même serveur les fonctions d’authentification et d’autorisation.
On notera au passage que l’on parle ici d’authentification par abus de langage. Il s’agit en fait techniquement de transmettre à l’application l’identité de l’utilisateur. Les recommandations de l’ANSSI le soulignent avec raison : la phase concrète d’authentification n’est pas couverte par la norme OpenID Connect. Elle est laissée à l’appréciation du fournisseur d’identité, qui fera la vérification par mot de passe, par authentification à facteurs multiples, ou qui pourra même la déléguer à un autre serveur.
Cette délégation se fait d’ailleurs elle-même par OIDC : le fournisseur d’identité devient alors l’application qui confie son authentification à un autre fournisseur d’identité. Qui peut à son tour continuer le mouvement en se tournant vers un troisième fournisseur d’identité.
C’est par exemple la manière de fonctionner de France Connect.
Le fournisseur de données n’a pas sa place dans la liste des acteurs
Le chapitre précédent permet de clarifier une petite confusion dans la liste des acteurs des recommandations. Elle contient l’utilisateur, le fournisseur de service (l’application), le fournisseur d’identité et le fournisseur de données (Resource server).
Or si ce dernier est en jeu dans la norme OAuth 2 (c’est le service web), mais il n’intervient en aucune manière dans OIDC qui réalise l’authentification de l’utilisateur d’une application.
Les nouvelles cinématiques OpenID Connect
Les recommandations de l’ANSSI présentent les trois cinématiques initiales de la norme : authorization code, implicit et hybrid.
La cinématique authorization code a été conçue pour les applications web classiques, où les traitements se font au niveau d’un serveur d’application qui a besoin de l’identité de l’utilisateur pour vérifier ses habilitations. Pour cela, l’application récupère un jeton d’identité directement du fournisseur d’identité, sans qu’il passe par le navigateur, dans une relation de serveur à serveur qui limite les possibilités d’usurpation d’identité et d’élévation de privilège.
Or avec les applications modernes s’exécutant directement dans les navigateurs (SPA pour Single Page Application), la notion d’échange serveur à serveur n’a pas de sens. Et d’ailleurs la notion même d’authentification auprès de l’application n’a pas tellement de sens. L’utilisateur ayant le contrôle de son navigateur, il peut modifier toutes les données qui s’y trouvent.
En revanche, ce qui est important, c’est que ces applications SPA (ou mobiles) se connectent à un backend par des services web, et là la notion d’habilitation retrouve tout son sens. Mais on sort du périmètre OpenID Connect pour entrer dans celui d’OAuth 2. Pour une application SPA, le jeton d’identité n’est pas utile à la sécurité, mais le jeton d’accès l’est.
Il n’est pas inutile à ce stade de faire un petit détour vers la sécurisation des SPA. Ce type d’application s’est développé de manière importante car elles permettent une réactivité inégalée de l’interface et donc une amélioration sensible de l’expérience utilisateur. Les applications se sont alors séparées en deux : la présentation au niveau du navigateur (frontend) et les traitements sur le serveur (backend). Il n’est pas illégitime de pousser la logique jusqu’au bout et de casser le lien entre les deux composantes pour en faire deux applications distinctes : une SPA sur le navigateur qui appelle des API sur le serveur.
Le backend se transforme alors en service web indépendant, et il peut même se démultiplier en microservices. Le nouveau service web entre alors en plein dans le champ d’application d’OAuth 2 et du jeton d’accès.
Sauf que le jeton d’accès est une information critique car s’il est intercepté il peut être rejoué sans qu’il soit la plupart du temps possible de trouver le moyen de s’y opposer. Dans l’architecture SPA + API, l’application qui s’exécute sur le navigateur doit détenir le jeton d’accès pour le présenter à l’API. Or il est impossible à l’heure actuelle de garantir la protection du jeton d’accès dans le navigateur.
Le moyen le plus efficace de protéger l’accès d’une SPA à un backend reste la session HTTP et son cookie HttpOnly qui le rend inaccessible. Il est illusoire de vouloir conjuguer de manière sécurisée SPA et jeton d’accès. L’architecture avec un frontend et un backend dédié reliés par une session HTTP est donc préférable du point de vue de la sécurité.
Les applications mobiles sont un cas différent car avec le modèle actuel, on ne s’attend pas à s’authentifier à chaque fois qu’on accède à une app. On dispose de moyens de protections dédiés (keystore Android et keychain iOS) et on déporte une partie de la sécurité au niveau de l’équipement qui se déverrouille par PIN ou par biométrie.
Il est donc acceptable que les app mobiles conservent en propre non seulement des jetons d’accès, mais encore des jetons de rafraîchissement donnant accès aux backend dans la durée.
Pour en revenir à OpenID Connect, la norme a proposé pour les SPA (malgré les réserves présentées ci-dessus) et pour les app mobiles une cinématique appelée implicit calquée sur la cinématique OAuth 2 correspondante. L’application récupère directement deux jetons en retour d’authentification : un jeton d’accès pour sécuriser les appels au backend et un jeton d’identité pour afficher des informations sur l’utilisateur.
Or la cinématique implicit d’OAuth 2 a été abandonnée en 2018 à cause de problèmes de sécurité (possibilité de fuite ou d’injection de jeton).
Il ne reste alors plus que la cinématique authorization_code. Mais appliquée strictement aux SPA et app mobiles, elle pose un problème de diffusion de mot de passe. La cinématique requiert en effet un secret pour sécuriser l’échange du code contre les jetons. Il faudrait alors que le mot de passe soit présent dans les navigateurs et sur les mobiles, ce qui ferait basculer son statut de secret à public.
Pour résoudre le problème, OAuth 2 a ajouté à la cinématique authorization code une méthode de vérification alternative lors de l’échange, appelée Proof Key for Code Exchange (PKCE). On donne plus de détails un peu plus bas.
Du fait de la grande proximité des cinématiques entre les deux protocoles, PKCE a pu être adapté à OpenID Connect. Face à un rival mieux sécurisé, la cinématique implicit d’OpenID Connect n’est plus recommandée (même si elle est plus sécurisé que son pendant OAuth 2) et les bonnes pratiques lui préfèrent authorization code avec PKCE.
Maintenant qu’en est-il de la cinématique hybride ? Elle permet de récupérer directement un jeton d’identité par retour d’authentification et d’obtenir un jeton d’accès de manière sécurisée en échange d’un code à usage unique. Son utilité est cependant discutable. Elle se justifie si l’application souhaite réaliser un traitement immédiat sur l’identité, avant de récupérer le jeton d’accès par la suite. Certains avancent un cas d’usage où le jeton d’identité est intercepté par une SPA sur le navigateur et où le code est récupéré par le backend pour obtention d’un jeton d’accès.
Le jeton d’accès doit alors être considéré comme public, ne contenir aucune information confidentielle et être considéré comme potentiellement falsifié. Il sort du champ de la sécurisation, aux yeux de laquelle la cinématique hybride se comporte comme la cinématiques authorization code.
Il ne reste donc plus effectivement que la seule cinématique authorization code (avec ou sans PKCE).
La recommandation R1 est donc correcte (utiliser en priorité authorization code), et pourrait avantageusement être complétée par des considérations sur la sécurité des SPA et des app mobiles, et par une référence à PKCE.
HTTPS est la fondation d’OpenID Connect
La recommandation R3 demande que toutes les communications soient sécurisées par le protocole TLS.
C’est en effet fondamental, car l’essentiel de la sécurité d’OAuth 2, et par extension d’OpenID Connect, repose sur HTTPS.
Les concepteurs d’OAuth 2 sont partis du retour d’expérience mitigé de la norme SAML, qui a réussi à s’imposer pour l’authentification des applications cloud, mais qui avait du mal à se généraliser aux autres applications. La complexité des exigences de sécurité ont limité le nombre de bibliothèques disponibles. Pendant longtemps, il a même été difficile de trouver un module SAML pour Java (pourtant langage le plus populaire). La raison en était qu’il fallait coder des fonctions de sécurité avancées, en particulier la signature et le chiffrement de documents XML. Or la cryptographie n’est pas à la portée de tout le monde.
Avec OAuth 2, une partie importante de la sécurité a été déportée vers le protocole HTTPS. Il a l’avantage d’être implémenté dans tous les langages ; c’est un composant facile à mettre en place, sécurisé et bien compris. On limite par là-même la possibilité de vulnérabilités introduites par l’inexpérience.
Il n’a cependant pas été possible de couvrir toute la sécurité par HTTPS. Il reste au moins une fonction de cryptographie : la vérification de signature des JWT.
Pour en revenir à HTTPS, la recommandation R7 sur le certificate pinning est difficile à mettre en oeuvre. Elle consiste à installer une référence au certificat du serveur au sein de l’application qui demande l’authentification. On en perçoit bien les bénéfices théoriques, mais la mise en pratique s’annonce laborieuse. L’expiration du certificat devra être anticipée à l’avance pour s’assurer d’installer le nouveau dans toutes les applications, avant de l’installer sur le serveur, puis de repasser sur toutes les applications pour retirer celui qui n’est plus valable.
Augmenter la sécurité des demandes d’authentification par des contraintes supplémentaires risque d’avoir l’effet inverse
La demande d’authentification est le point de départ de la cinématique d’authentification. Elle correspond à la redirection de l’utilisateur vers le fournisseur d’identité qui doit l’authentifier. A cette occasion, une demande est formalisée, sous la forme d’une requête d’authentification.
Cette requête donne au serveur des précisions sur le processus à suivre : essentiellement le protocole, la cinématique et l’URL de retour (pour savoir où, au sein de l’application, renvoyer l’utilisateur une fois qu’il sera identifié).
Les recommandations R8 et R8+ conseillent de signer la requête pour éviter toute manipulation de la requête. Ça part d’un bon sentiment. En théorie, plus on signe et plus on chiffre, et plus on est sécurisé.
Mais ça, c’est la théorie. Dans la pratique, trop de signature et trop de chiffrement a l’effet inverse. Comme partout en sécurité, à mesure que les exigences augmentent, les utilisateurs trouvent des moyens de contournement qui abaissent le niveau général.
C’est ce qu’illustre l’expérience SAML, qui était la norme d’authentification avant qu’apparaisse OIDC.
Replaçons nous dans le contexte. On partait d’une situation où les applications géraient elles-mêmes leur authentification, avec les conséquences qui ont fait les titres de la presse informatique : fuite de mots de passe mal protégés, vulnérabilités exploitées des fonctions d’authentification, difficultés à mettre en place des authentifications fortes, impossibilité d’adapter l’authentification au contexte de l’utilisateur.
Replaçons nous dans le contexte. On partait d’une situation où les applications géraient elles-mêmes leur authentification, avec les conséquences qui ont fait les titres de la presse informatique : fuite de mots de passe mal protégés, vulnérabilités exploitées des fonctions d’authentification, difficultés à mettre en place des authentifications fortes, impossibilité d’adapter l’authentification au contexte de l’utilisateur.
La fédération des identités, avec SAML, a proposé une avancée concrète en déléguant la fonction d’authentification à des serveurs spécialisés et sécurisés, intégrant des mécanismes de protection contre les attaques et ouverts vers les différentes méthodes d’authentification. Mais son adoption s’est largement limitée aux services dans le cloud.
La raison en est évidente pour qui a interfacé une application en SAML : la lourdeur et la complexité de la norme. Il faut échanger des métadonnées, faire de la signature et du chiffrement XML, préciser tous les types de données. En cas d’incompatibilité, l’authentification tombe en erreur. Résultat : il existait très peu de bibliothèques SAML, qui étaient souvent incomplètes. L’authentification est restée intégrée aux applications, avec tous les problèmes de sécurité associés.
Fort de ce constat, la norme OIDC a été pensée comme simple et efficace, ce qui s’est traduit par une large adoption dans les entreprises. Non seulement l’offre en bibliothèques est pléthorique, mais l’interfaçage d’une application, tout en étant toujours relativement complexe, reste à la portée de chacun.
Les recommandations R8 et R8+ sont dans l’absolu souhaitables, mais dans la réalité elles représentent dans la plupart des cas une barrière inutile qui freinera la diffusion de la fédération des identités. Les applications conserveront plus longtemps leur authentification interne, et leur niveau de sécurité discutable.
Il existe cependant des moyens de renforcer la sécurité sans prôner le tout cryptographie.
L’ANSSI nous indique que le risque le plus important en phase de requête d’authentification, c’est qu’un tiers manipule le champ scope utilisé pour demander des claims, c’est-à-dire des informations personnelles sur l’utilisateur. Effectivement, si quelqu’un écoute les échanges, il ne faut pas qu’il puisse demander subrepticement le numéro INSEE (NIR) de la personne et l’obtenir.
Pour empêcher cela, on conseille de fixer au niveau du serveur la liste des informations transmises à une application donnée. Et c’est d’ailleurs une bonne pratique mise en œuvre par la plupart des fournisseurs d’identité : ce n’est pas parce qu’une application demande une information qu’on va la lui donner.
Faire mieux que la norme n’est pas toujours souhaitable
Les recommandations s’intéressent de près aux capacités de sécurité du fournisseur d’identité, afin de guider les administrations dans le choix du serveur chargé de réaliser l’authentification.
Les conseils sont pertinents, qu’ils soient généraux comme sur les algorithmes de cryptographie, ou plus spécifiques comme sur la conservation des jetons.
Il arrive cependant que les recommandations aillent à l’encontre de la norme OpenID Connect. L’ANSSI relève d’ailleurs le point et avertit le lecteur que « les implémentations certifiées par la fondation OpenID respectent strictement la norme OIDC » et que la recommandation concernée ne pourra pas être mise en oeuvre par un tel fournisseur d’identité.
L’ANSSI est dans son rôle quand elle fait une lecture critique des normes pour pointer leurs insuffisances.
Mais dans le cadre de l’authentification, le respect de la norme est le garant de la bonne interopérabilité entre les systèmes. La décision d’en sortir doit être prise en pleine conscience des conséquences. Elle restreint l’éventail des choix, et impose souvent un développement complémentaire.
Car si les éditeurs et développeurs de fournisseurs d’identité ont en effet intérêt à proposer des fonctions différenciatrices, ils le font toujours dans le cadre de la norme pour des raisons évidentes.
Fort heureusement les recommandations en question portent la plupart du temps sur la possibilité d’imposer un comportement aux applications. Une telle obligation ne passe pas nécessairement par des moyens techniques, elle peut se faire juridiquement dans le cadre du contrat de service avec les applications.
A l’inverse, la recommandation R17 est une obligation déjà imposée par la norme OpenID Connect. Elle s’applique une fois l’authentification réalisée, lorsque le fournisseur d’identité redonne la main à l’application. C’est fait par une redirection vers une URL fournie lors de la demande d’authentification. La norme indique qu’elle ne peut se faire que vers des URL dûment enregistrées au préalable, pour éviter qu’un attaquant ayant réussi à modifier la requête d’authentification ne dirige les utilisateurs vers un serveur qu’il contrôle, d’où il récupèrera les jetons des utilisateurs.
L’authentification du client nécessite quelques compléments
Dans la cinématique d’authentification, les jetons ne sont pas transmis directement lors du retour du fournisseur d’identité vers l’application. Ce retour s’opère en effet par redirection et les jetons transiteraient par le navigateur de l’utilisateur qui est un point faible en termes de sécurité. Les jetons peuvent y être interceptés, possiblement par un attaquant, et très facilement pour l’utilisateur lui-même qui pourra tenter de les altérer à son profit.
A la place d’un jeton, c’est un code à usage unique qui est transmis, et qui est utilisé par l’application lors d’un échange direct avec le fournisseur d’identité pour récupérer les jetons. Pour cela, l’application (appelée client) doit au préalable s’authentifier pour éviter qu’un attaquant ayant récupéré un code puisse s’en servir.
La norme propose plusieurs méthodes : le simple mot de passe ou la signature d’un jeton (HMAC ou clés asymétriques). L’ANSSI ne tranche pas et conseille d’utiliser le moyen le plus approprié dans le contexte de l’application.
Les échanges se faisant en HTTPS entre deux serveurs, on considère souvent que la fourniture du mot de passe est suffisante. On n’envisagera les méthodes par signature que si le risque d’écoute des échanges est fort.
Ce qui est toutefois passé sous silence, c’est la protection du mot de passe par l’application. L’ANSSI semble se placer dans le cadre exclusif de l’application web classique exécutée sur un serveur.
Or OpenID Connect n’est pas utilisé que dans cette unique configuration. Les applications de type page unique (SPA) ou les apps mobiles entrent certes dans le cas d’usage OAuth 2 (récupération d’informations auprès d’un backend), mais ont aussi parfois besoin dans un premier temps de vérifier que l’utilisateur a bien accès à l’application. Le point a été développé plus haut.
Elle commencent donc par vérifier un jeton d’identité et ne font parfois appel au backend que suite à une sollicitation de l’utilisateur.
Dans le cas des SPA, on préfère protéger les jetons (en particulier le jeton OAuth 2 de rafraîchissement) au sein d’un serveur dans un backend dédié, mais certaines applications décident de s’en passer, conservent un jeton d’accès localement et le renouvellent par réauthentification transparente. Les apps mobiles conservent souvent en interne le jeton de rafraîchissement.
Ce qui fait qu’on a bien, en OpenID Connect, des cas légitimes de clients publics, c’est-à-dire de récupération de jeton d’identité directement par une application non protégée : sur un navigateur ou dans un mobile.
La phase d’échange du code contre des jetons pose alors problème, car l’application doit être authentifiée auprès du fournisseur d’identité. Elle devrait donc contenir un secret, mais dans un navigateur ou dans un téléphone, rien n’est secret.
La cinématique implicit avait été prévue pour ce cas d’usage, mais la transmission directe des jetons pose problème. Un complément à la norme OAuth 2, repris par OIDC, a ensuite été produit pour adresser ce problème. Il est appelé PKCE et au lieu d’authentifier le client en tant que tel, il assure que les jetons sont bien donnés à l’application qui en a fait la demande.
La bonne pratique est maintenant pour les clients publics d’utiliser PKCE (prononcer pixy) pour la récupération des jetons en échange du code à usage unique.
En attente de conseils sur les niveaux de sécurité
La recommandation R29 suggère de vérifier que le niveau de sécurité de l’authentification demandé correspond bien à celui obtenu. On peut en effet exiger dans la requête d’authentification qu’elle soit réalisée avec plusieurs facteurs (authentification forte). Il convient ensuite vérifier que l’authentification qui a été effectivement réalisée correspond bien à l’exigence de départ.
On aurait aimé que l’ANSSI nous éclaire sur ces niveaux de sécurité, en donnant des définitions, en explicitant la manière de les appliquer, en indiquant comment les vérifier, etc.
L’annexe B3 du RGS traite de l’authentification, mais elle date de 2010 et elle n’aborde pas la question.
L’Europe avec eIDAS définit trois niveaux. L’ISO avec ISO/IEC 29115 en définit quatre. L’IANA maintient un registre des niveaux de sécurité où l’on retrouve un peu n’importe quoi. De son côté aux Etats-Unis le NIST a produit une documentation extensive et traite l’identité, l’authentification et la fédération, avec trois niveaux pour chaque.
Dans ce déferlement d’informations pas toujours exploitables, les conseils de l’ANSSI seraient les bienvenus.
Informations personnelles dans le jeton ou par userinfo
La norme définit deux moyens pour une application de récupérer des informations personnelles lors de la phase d’authentification. Le premier consiste à enrichir le jeton d’identité et le second correspond à utiliser un service web (appelé userinfo).
Les recommandations ne se prononcent pas sur ce qu’il convient d’utiliser. Pourtant les deux options ne sont pas équivalentes.
Le jeton d’identité est en effet une entité qui est susceptible d’être diffusée. Dans le cas des clients publics (SPA et app mobiles), il est récupérable facilement par l’utilisateur et risque d’être dérobé.
On préférera donc n’enrichir le jeton qu’avec des informations non confidentielles, à moins qu’on soit certain de sa bonne protection. Le service web userinfo est plus sécurisé et il doit être privilégié pour les données critiques.
Ces principes s’appliquent pleinement dans un cadre OAuth 2 puisque le jeton d’accès est par nature échangé entre l’application et le service web, et qu’il a donc besoin d’être protégé. Si on sort ici du cadre strict d’OpenID Connect, on a d’une manière générale intérêt à étendre les bonnes pratiques aux deux protocoles.
Ces suggestions doivent cependant être tempérés par les capacités techniques des fournisseurs d’identités qui n’offrent pas tous les mêmes libertés dans la configuration des données (claims). Il existe ainsi des systèmes qui n’autorisent pas l’enrichissement du jeton, pourtant prévu par la norme. D’autres publient exactement les mêmes informations dans les jetons et dans le service web userinfo, sans possibilité d’en restreindre le nombre dans le jeton.
On aura donc intérêt à privilégier les fournisseurs d’identité qui se montrent souples dans la configuration de la diffusion des claims.
Bien vérifier la validité du jeton
Ceux qui n’ont jamais touché à la cryptographie sont enclins à vouloir tout chiffrer pour adresser tous les problèmes de sécurité.
Ceux qui l’ont pratiquée vous le diront : « cryptography is hard ». Même pour les experts. En 2013 une base de 38 millions de mots de passe a fuité d’Adobe. Mais heureusement, elle était chiffrée. Ouf. Sauf que ce qui était chiffré, c’était juste le mot de passe, et avec un algorithme réversible et sans « sel ». Une simple analyse statistique aurait permis de découvrir les mots de passe de nombreux comptes (dans les faits, la fuite a aussi concerné les indices de mot de passe associés, ce qui a rendu la tâche des hackers encore plus facile).
L’ANSSI recommande avec R44 de fixer l’algorithme de signature des jetons (quand c’est possible, ce qui n’est pas toujours le cas…). C’est important, car les attaquants ont plusieurs moyens faciles de contrefaire un jeton en jouant sur ces algorithmes.
Le plus simple, c’est de fabriquer son propre jeton et de ne pas le signer du tout. A la place, on indique dans le jeton que l’algorithme none a été utilisé. En application stricte des normes, le jeton est tout à fait valide et sera accepté.
Depuis que ce problème a été découvert, les bibliothèques de vérification des jetons doivent rejeter cet algorithme. La vérification se faisant du côté de l’application, il ne sera pas inutile de s’assurer que la bibliothèque OIDC utilisée est correcte sur ce point.
Les attaquants disposent d’un autre moyen pour profiter des bibliothèques mal sécurisées. Certaines par exemple utilisent la même méthode pour vérifier les signatures HMAC et asymétriques. Or si dans le premier cas la clé est privée (et protégée), dans le second elle est publique. Un attaquant mettant la main dessus, il pourra l’utiliser pour signer son jeton contrefait en HMAC et la bibliothèque validera le jeton.
On devra donc au moins indiquer à la bibliothèque le type de signature que le serveur utilise.
Dans l’immense majorité des cas, les fournisseurs d’identité font des signatures par clés asymétriques, dont ils mettent la clé publique à disposition par l’endpoint JWKS.
Cet endpoint assure la sécurité de la vérification de signature. La clé publique est récupérée en direct depuis l’endpoint protégé par HTTPS (dont on validera le certificat). On s’assure de ce fait de sa validité (l’invalidation des clés compromises est connue en temps réel). De plus, elle est publiée avec ses métadonnées, qui sont utilisées par les bibliothèques de vérification (type de clé, algorithme, finalité).
Il est fortement encouragé de procéder de la sorte. On s’évite les contraintes des certificats (renouvellement, intégration des certificats racines) tout en assurant un niveau de sécurité supérieur.
Conclusion
Les recommandations de l’ANSSI sur la sécurité OpenID Connect sont un outil précieux pour bien choisir un fournisseur d’identité et pour réaliser de manière sécurisée l’authentification des applications.
Elles restent cependant des recommandations dont l’application reste du ressort de chaque projet. Dans cette optique, elles manquent toutefois parfois d’éléments sur lesquels asseoir les décisions.
Avec le recul de plus de 10 ans de mise en place de solutions de fédération des identités, nous espérons avoir éclairé le lecteur sur la mise en place concrète des mesures recommandées.
Et comme tout le monde, nous attendons avec impatience des recommandations similaires sur la sécurisation d’OAuth 2, le protocole d’autorisation des services web, en ces temps où les architectures reposant sur des API sont en vogue.
Auteur : Marc (Directeur technique)