Utiliser en toute sécurité le OIDC Authorization Code Flow et un client public avec des applications Single Page

11 oct. 2018
-minutes de lecture
Directeur général, Iya CyberSecurity Solutions

Introduction

L’approche traditionnelle pour utiliser OAuth2 ou OpenID Connect (OIDC) avec des applications Single Page (SPA) est l’OAuth2 Implicit Grant ou OIDC Implicit Flow, une approche toujours utilisée par beaucoup de développeurs. Plus récemment, toutefois, l’utilisation de l’OAuth2 Authorization Code Grant (ou OIDC Authorization Code Flow) avec un client public s’est accélérée. Les fournisseurs d’IdP (Identity Providers - fournisseurs d’identité) et les bloggeurs ont exprimé diverses opinions concernant l’utilisation du OIDC Authorization Code Flow avec un client public pour les SPA, mais cette approche, si elle est correctement sécurisée, est viable et apporte avec elle plusieurs avantages, dont :
 

  • L’utilisation de jetons d’actualisation. (C’est un gros avantage.)

  • Un meilleur contrôle de la durée d’expiration des sessions utilisateur via des mécanismes définis de manière spécifique.

  • Une cohérence sur divers cas d’usage (SPA, applis mobiles natives, applis de bureau natives, applications Web, etc.)


J’ai examiné ces avantages de façon plus détaillée dans mes précédents articles. Désormais, l’industrie s’oriente vers l’utilisation de l’OAuth2 Authorization Code Grant (ou OIDC Authorization Code Flow) avec un client public. Dans cet article, nous verrons comment garantir au mieux que cette approche soit utilisée de manière sécurisée avec les SPA.

Architecture OIDC Authorization Code Flow (avec un client public)

Pour être sûr que nous parlions tous de la même chose, imaginons une architecture et une interaction qui ressemblent au diagramme suivant.

 

 

De plus, formulons ces hypothèses (certaines d’entre elles, peut-être pas toutes, seront valides pour votre cas d’usage) :

 

  • Utiliser un modèle de sécurité sans statut plutôt qu’un cookie de suivi de session avec le backend de l’application (API Gateway sur l’image ci-dessus). Dans le modèle de sécurité sans statut, le contexte de sécurité est recréé sur le backend pour chaque invocation d’API utilisant des informations dans le jeton d’accès (imaginons des jetons Web JSON : JWT) ou des informations récupérées à partir de la terminaison Info utilisateurs OIDC. Pour plus d’informations sur ce sujet, voir « How To Submit Your Security Tokens to an API Provider Pt. 1 ».

     

  • Le délai d’expiration du jeton d’accès est plus court que le délai d’expiration de la session de l’utilisateur. Le jeton d’actualisation est donc nécessaire. Le jeton d’actualisation est utilisé pour allonger la durée de vie du jeton pour satisfaire un délai raisonnable d’expiration de la session. Il existe plusieurs stratégies de jetons d’actualisation. Un jeton d’actualisation avec « utilisation hors-ligne » destiné à survivre à l’authentification de l’utilisateur n’est pas adapté pour une SPA. Plutôt, l’idée est que l’actualisation échouera lorsque l’utilisateur devra retourner vers l’IdP pour interagir (comme pour se réauthentifier). Le jeton pourrait ne pas avoir une durée de vie fixe, mais l’actualisation échoue à chaque fois que l’intelligence commerciale décide que la vérification de l’utilisateur est requise. La logique commerciale et les données qui se trouvent derrière un jeton d’actualisation sont totalement opaques sauf pour l’IdP ; l’interaction avec l’IdP est principalement gérée par une bibliothèque d’authentification, sauf lorsque l’interaction de l’utilisateur (qui doit par exemple fournir des identifiants) est requise.

     

  • La SPA agit comme le client OAuth2 et non comme un composant côté serveur. Le Client OAuth 2.0 est le composant qui obtient les jetons depuis l’enpoint du jeton. Dans notre scénario de SPA, le code Javascript (la SPA) exécuté dans le navigateur est le Client OAuth 2.0, et non un composant côté serveur.

     

  • Le serveur d’actif statique répondra à l’URI de redirection enregistré avec index.html (ou équivalent). De cette manière, la SPA est rechargée et initialisée, et un composant comme Angular Router détecte que l’URI de redirection a juste été appelé (et prend les mesures appropriées pour finaliser le flux OIDC).

     

  • Cet article n’aborde pas les capacités d’un fournisseur d’identité spécifique. De ce fait, les informations disponibles ici s’appliquent au plus grand public et nous nous concentrons sur les capacités définies dans les spécifications.

Remarque : cet article n’explore pas l’interaction entre le SPA et l’API Gateway. Si ce sujet vous intéresse, consultez les précédents articles « How To Submit Your Security Tokens to an API Provider Pt. 1 » et « How To Submit Your Security Tokens to an API Provider Pt. 2”.

Implications en termes de sécurité

Maintenant, j’aborde la question depuis une vision du monde axée sur la spécification. Cela signifie que je pose vraiment la question « Comment résoudre X dans les limites des spécifications concernées A, B, C, etc. ? » La plupart des IdP fournissent des mécanismes pour contrôler la durée des sessions authentifiées, obtenir de nouveaux jetons sans que l’utilisateur soit incité à se réauthentifier à travers une session de sécurité suivie par un cookie, et une fonctionnalité supplémentaire qui est utile, mais propriétaire.

 

Quelles sont donc les implications en termes de sécurité ? Les spécifications OAuth2, OIDC et JWT (et compatible) fournissent plusieurs moyens de contrôles pour aider à garantir l’intégrité d’un flux de connexion OIDC, notamment :

 

  1. Le certificat du serveur de fournisseur d’identité du Transport Layer Security (TLS/SSL) est vérifié par le navigateur pour s’assurer que le navigateur communique avec l’IdP réel.

     

  2. La bibliothèque d’authentification (utilisée par la SPA) valide le jeton d’identification (y compris la validation de la signature numérique et la validation de confiance sur le certificat du signataire) pour les spécifications JWT et OIDC. Utiliser l’endpoint Discovery OIDC et l’endpoint JWKS pour obtenir et mettre à jour de manière dynamique le truststore utilisé pour valider le certificat du signataire JWS (la plupart des bibliothèques d’authentification Javascript des navigateurs que j’ai utilisées jusque-là ne le font pas). Cette vérification procure une couche supplémentaire d’assurance que le jeton vient de là où nous pensons qu’il vient.

     

  3. Utilisation d’une URL de redirection pré-enregistrée. De cette manière, il est certain que seul le ou les endpoints d’application visés ont accès aux jetons.

     

  4. Le certificat du serveur Web de contenu statique TLS/SSL (qui héberge les actifs de la SPA) est vérifié par le navigateur pour s’assurer que le navigateur communique avec l’URI de redirection réel (et l’application). Un pas supplémentaire peut être franchi pour aller plus loin que cet article et utiliser le TLS à chaque saut de réseau (network hop) où passent les jetons de sécurité.

     

  5. L’utilisation du paramètre d’état (et sa validation lorsque le code d’autorisation est reçu) pour l’endpoint d’autorisation, le flux d’autorisation, le consentement d’accès délégué et tout autre endpoint de redirection impliqué.

     

  6. Conformément aux spécifications OAuth2, les stratégies de protection CSRF devraient être utilisées par l’endpoint d’autorisation de l’IdP, le flux d’authentification et les écrans de consentement d’accès délégué. En réalité, les utiliser en général sur tous les endpoints est une bonne idée.

     

  7. L’utilisateur sera incité à donner (déléguer) son consentement pour que l’application (SPA) accède à ses informations (profil sur le serveur d’autorisation, IdP). Normalement, cela ne serait réalisé qu’à la première connexion de chaque utilisateur. Pour renforcer la sécurité, cela pourrait être réalisé également à chaque connexion. Cela permettrait de garantir que l’utilisateur accède bien à l’application qu’il faut. Cela n’est pas possible avec tous les serveurs d’autorisation OAuth2.

     

  8. Sans que cela soit précisément défini dans les spécifications, l’utilisation de Cross-Origin Resource Sharing (CORS) sur l’endpoint du jeton par le biais d’un mécanisme qui situe les origines valides sur le client décrit procurerait une couche supplémentaire de sécurité, qui empêcherait une application d’usurpation (chargée depuis une origine non enregistrée) de pouvoir obtenir un ensemble de jetons. Il est possible de contourner les restrictions CORS. Par conséquent, s’appuyer uniquement sur cela n’aide pas vraiment. Remarque : d’autres endpoints d’IdP nécessaires à vos cas d’usage pourraient ou non prendre en charge le CORS.

     

  9. De même, sans que cela soit précisé dans les spécifications, stocker le jeton d’identification, le jeton d’accès et (en particulier) le jeton d’actualisation dans le stockage de la session pour qu’il soit disponible uniquement jusqu’à ce que le navigateur soit fermé. C’est un autre sujet qui a suscité beaucoup de débats sur l’Internet. Malheureusement, il existe peu d’options de stockage sur le navigateur.

Ce qu’il faut retenir

Maintenant que nous avons examiné certaines implications relatives à la sécurité en utilisant le flux de code d’autorisation OIDC (avec un client public) pour une SPA, voici ce qu’il faut garder en mémoire pour être sûr d’avoir un système mieux protégé :

 

  • Tous les IdP ne prennent pas en charge le flux de code d’autorisation OIDC avec un client public. Si c'est le cas de votre IdP, vous devez vous appuyer sur un mécanisme spécifique à un IdP (comme par exemple un cookie de suivi de session) pour obtenir un nouveau jeton d’accès sans demander les identifiants de l’utilisateur. Cela a déjà été réalisé à plusieurs reprises dans le passé, mais ce n’est pas couvert par une spécification.

     

  • Certains IdP n’autorisent pas CORS sur l’endpoint du jeton. Cela empêchera le navigateur de lire la réponse de l’endpoint du jeton. Donc, une SPA avec un flux de code d’autorisation OIDC et un client public n’est pas prise en charge. Si un proxy peut être utilisé (juridiquement et techniquement), toutes les difficultés liées au CORS et l’endpoint du jeton peuvent être résolues. Autrement, l’Implicit Grand (ou Flux implicite) sera la meilleure approche.

     

  • Les scénarios incluant un délai d’expiration de la session utilisateur assez court pourraient utiliser le flux implicite OIDC. Si le délai total d’expiration de la session de l’utilisateur est relativement court et que le jeton d’accès n’expire jamais, alors un jeton d’actualisation n’est pas nécessaire. Donc, utiliser un flux implicite est une option simplifiée.

     

  • Dans certains cas, les Grants OAuth2 peuvent être préférables aux flux OIDC, et inversement. Pour une présentation plus approfondie, vous pouvez lire mont article sur le moment où utiliser les divers OAuth2 Grants et flux OIDC.

     

  • Même si la SPA (ou n’importe quelle application Javascript fonctionnant dans un navigateur) a un identifiant client et un secret client codé dans le code Javascript, le secret du client ne peut pas être considéré comme une forme fiable d’authentification pour le client. Il est banal pour un tiers d’obtenir le secret du client. Cette approche ne manque pas en soi de sécurité, mais l’IdP doit reconnaître qu’elle n’est pas plus sécurisée qu’un client public sans avoir un secret dans son modèle de sécurité. Pour rappeler ce que nous avons mentionné précédemment, la liste blanche de l’uri de redirection empêchera les applications qui ne contournent pas le navigateur de réutiliser l’identité d’un client.

     

  • Ne pas partager le jeton d’identification ou le jeton d’actualisation avec d’autres composants de votre architecture ni avec des tiers. Si la SPA agit comme un client OAuth2 (partie de confiance OIDC), elle ne devrait passer ces jetons à un composant côté serveur pour aucune raison que ce soit. Si votre architecture implique que cela devrait être fait, le composant côté serveur peut agir comme le client OAuth2 et peut être un client privé qui protège le secret du client. Puis, la SPA devrait utiliser un cookie pour suivre la session de sécurité avec le serveur Web. Partager le jeton d’actualisation avec un autre composant du système compromet la relation de sécurité entre le client OAuth2 (SPA) et l’IdP.  Partager un jeton d’identification ne compromet pas la sécurité entre l’IdP et le client ; cela compromet la sécurité d’autres composants qui en dépendent (étant donné qu’il s’agissait d’une assertion destinée uniquement à ce client). Vous ne souhaitez pas que ces scénarios se produisent.

     

  • La clé de vérification pour l’échange de code (PKCE) vise à être utilisée avec des applications natives. Elle ne procure pas vraiment de sécurité supplémentaire à une SPA (ou application Javascript) fonctionnant dans un navigateur. Toutefois, pour maintenir un ensemble cohérent de règles d’utilisation OAuth2/OIDC, utiliser une PKCE avec les SPA pourrait être conseillé.

     

  • L’enregistrement dynamique de client (RFC 7591) présente quelques limites. L’enregistrement dynamique de client (DCR, Dynamic Client Registration) pourrait apporter une couche de protection supplémentaire dans le cas d’une application SPA, mais le secret client émis dynamiquement pour une SPA constitue d’autres informations devant être protégées avec le jeton d’identification OIDC, le jeton d’accès OAuth2 et le jeton d’actualisation OAuth2. Le DCR ne résout pas le problème de la protection de ces valeurs dans le navigateur. Votre IdP devrait aussi pouvoir s’adapter à de nombreux clients OAuth2 (un par navigateur, utilisateur) ; imaginez votre application avec des millions d’utilisateurs dans ce scénario. Le DCR pourrait également procurer un mécanisme efficace pour identifier les schémas d’utilisation de l’application qui permettraient à un IdP de mieux valider les utilisations légitimes, mais cela est détaché de l’application.

 

N’oubliez pas que tout cela suppose préalablement que le navigateur et l’appareil/OS sous-jacent n’aient été compromis d’aucune manière. S’ils ont été compromis, tout ce que j’ai indiqué plus haut n’aura guère d’importance.

Conclusion

Historiquement, le secteur a utilisé l’Implicit Grant OAuth2 (ou flux implicite OIDC) avec les SPA. Il n’y a aucune exigence de sécurité pour son utilisation continue. L’avenir, l’OAuth2 Authorization Code Grant (ou le flux de code d’autorisation OIDC) devrait être utilisé avec les SPA.

 

Pour en savoir plus sur ces types de sujets, consultez mon article sur la Gestion des API, l’intégration et l’identité sur medium.com.

Partager cet article:
Ressources connexes

Lancez-vous dès Aujourd'hui

Contactez-Nous

sales@pingidentity.com

Découvrez comment Ping peut vous aider à offrir des expériences sécurisées aux employés, partenaires et clients dans un monde numérique en constante évolution.