Avancé Intermédiaire

Sécuriser une API pour vos applications mobiles via OAuth 2.0

Lorsque l’on parle de développement mobile, de nombreuses contraintes nous viennent à l’esprit. Le choix de la technologie : natif, cross-platform, web ? Viennent ensuite les problématiques de développement pur. Et enfin le déploiement sur les stores qui n’est pas une mince affaire.
Bref, le boulot d’un développeur mobile est déjà bien complexe.
Mais voilà que s’ajoute la problématique de sécuriser et d’authentifier les connexions à un service de BackEnd.

Problématique

Les utilisateurs doivent pouvoir se connecter à une application mobile en utilisant des fournisseurs d’authentification externes tels que Google, Microsoft ou Facebook.
L’application mobile utilise un service web de BackEnd et doit partager cette authentification de l’utilisateur de manière sécurisée avec le webservice pour autoriser les requêtes à ce service depuis l’application mobile.
Ce partage d’authentification est utilisé pour mettre en place l’autorisation sur les requêtes transmises depuis l’application “en tant qu’utilisateur” et non “en tant qu’application”.
Une fois l’utilisateur authentifié, l’application peut donc par exemple lister les données récupérées depuis le webservice.
Le service doit renvoyer une erreur d’authentification quand cette identité n’est pas transmise depuis l’application mobile dans ses requêtes.

Cet article démontre l’approche théorique face à cette problématique et le suivant démontrera un exemple d’implémentation avec une application Xamarin et un webservice basé sur ASP.NET Core 2 et ASP.NET Identity.

L’objectif de cet article est de démontrer l’approche à utiliser pour mettre en place ce workflow entre une application native ou Xamarin et un service web.
Cet article se concentrera donc sur la délégation d’identité et la protection des ressources d’un service web sécurisé de type API et non sur la récupération de ressources protégées du fournisseur d’accès externe, tels que les amis Facebook de l’utilisateur, etc.

TLDR 😉 Pour connaître le workflow final sans les détails sur les limitations des autres workflow, sautez au chapitre “Implicit Grant ET Code Grant”.

OAuth Flow

Pour que vos utilisateurs se connectent via leurs comptes de réseaux sociaux, vous devez utiliser une délégation d’identité par API. Cela est vrai sur le mobile comme sur les applications web et le standard est OAuth Flow. Le protocole OAuth 2.0 standardisé en 2012 notamment via les RFC 6749 et RFC 6750 a permis de définir des workflows d’autorisation spécifiquement destinés aux applications web, de bureau ou aux applications mobiles.

Voyons les types de workflow qui s’offrent à nous.

Authorization Code Grant

Depuis des années, les développeurs web ont intégré la nécessité de proposer à l’utilisateur de se connecter aux sites via leurs comptes Google, Facebook, Microsoft, etc.
Pour ce faire, ils respectent une implémentation OAuth intitulée Authorization Code Grant détaillée dans la RFC 6749 => https://tools.ietf.org/html/rfc6749#section-4.1
Cette implémentation permet au navigateur web de l’utilisateur de récupérer un code d’Autorisation qu’il transmet à l’API afin qu’elle valide l’identité de l’utilisateur auprès du Provider et récupère un Access Token ainsi qu’un Refresh Token qui, comme son nom l’indique, permet de renouveler le code lorsque le premier arrive à expiration.
Une fois l’utilisateur authentifié sur l’API, il ne lui est donc plus nécessaire de se ré authentifier à chaque appel à l’application Web cliente selon la politique de session de l’API.
Si des ressources du provider doivent être récupérées, c’est l’API qui le fera “en tant que” l’utilisateur, via l’Access Token qu’elle aura stocké.

Si vous souhaitez mettre en place ce type d’authentification en ASP.NET Core, je vous invite à consulter l’article de Vincent Bourdon sur le sujet => http://blog.soat.fr/2016/10/introduction-a-lauthentification-oauth2-avec-aspnet-core-et-github/

Il faut noter que la validation d’identité auprès du Provider nécessite un Client Secret qui est embarqué côté serveur dans l’API.

Malheureusement pour nous, il existe une subtilité dans le cadre des applications côté client telles que les applications mobiles ou les Single Page Application. L’application mobile ou Javascript est considérée comme moins digne de confiance que notre webservice.
Lorsque l’on veut proposer une authentification depuis une application mobile il est donc fortement déconseillé de stocker le Client Secret sur l’appareil puisque cela entraîne une faille de sécurité importante si celui-ci venait à être récupéré par un tiers malveillant. Or celui-ci est nécessaire au Code Grant.
Il faut donc utiliser l’Implicit Grant.

Implicit Grant

L’Implicit Grant, à la différence du Code Grant ne nécessite pas de Client Secret et permet de récupérer directement un Access Token.
=> https://tools.ietf.org/html/rfc6749#section-4.2

Oui mais voilà via l’Implicit Flow, vos utilisateurs seront authentifiés dans votre application mobile (ici matérialisée par le User-Agent) car c’est elle qui stocke désormais l’access token, mais votre BackEnd ne connaît pas cette authentification. Cela ne nous aide pas beaucoup dans notre contexte d’API à sécuriser.

La solution qui semble naturellement s’offrir à nous est de transférer l’access token du fournisseur d’authentification à chaque requête au BackEnd et laisser celui-ci valider ce token auprès du fournisseur avant de traiter la requête.

Cette solution implique que votre BackEnd contactera l’autorité d’authentification à CHAQUE requête et vous voyez probablement les problématiques qui se profilent à l’horizon :

  • Chaque appel à votre API se verra ajouter un aller-retour au fournisseur d’identité en plus du traitement métier. Au niveau performance on a connu mieux.
  • Votre API risque rapidement de vous retrouver sur la liste noire de ces fournisseurs.

Mais alors comment fait-on de l’Implicit Flow pour respecter la sécurité tout en évitant de plomber notre API ?!

Implicit Grant ET Code Grant

La solution est d’utiliser Grant Flow pour connecter l’utilisateur à votre propre service BackEnd alors que votre service se connectera au fournisseur externe d’authentification, recevra sa réponse et, en cas de succès, créera son propre token qu’il renverra à l’application.

Toute la subtilité est là : votre webservice devra créer son propre token et le fournir à l’application en mode Code Grant, et c’est celui-ci qui sera validé en interne à chaque requête. On évitera ainsi de devoir contacter le fournisseur d’identité à chaque requête de l’application pour valider le token.

Vous voilà parti pour implémenter un Code Flow encapsulé dans un Implicit Flow.

Voici un schéma détaillant les différentes requêtes et donc le workflow réalisé par le navigateur natif :

De prime abord cela ressemble fortement au code grant classique mais les subtilités se trouvent dans la première étape durant laquelle le webservice va encapsuler l’état de l’application mobile et une URL de callback, ainsi que dans la dernière étape durant laquelle le webservice va créer un token d’implicit grant qu’il fournira en réponse à l’application.

Ci-dessous le schéma simplifié représentant le workflow de cette implémentation.

Voyons en détail les différentes étapes :

1) Pour s’authentifier et récupérer un token, l’application appelle une page HTML de votre API (/account/login). Dans cette page, l’utilisateur a le choix entre les différents fournisseurs d’authentification externes (Google, Facebook, Microsoft). Dans cette page votre API encapsule également un Client ID et une URL de redirection (A) représentant un callback dans votre application mobile et éventuellement un state représentant l’état de l’application. Cette callback sera nécessaire en fin de workflow pour fournir le token à votre application.
La page est alors affichée dans un navigateur natif du mobile, pas dans une webview.

2) Une fois que l’utilisateur choisit le fournisseur, il est redirigé vers la page de connexion du fournisseur choisi. La redirection contient une deuxième Redirect URL (B) représentant un callback dans votre API et un state contenant l’état du serveur et l’URL A que nous devons faire transiter jusqu’au bout.

3) Quand l’authentification de l’utilisateur est validée par le fournisseur externe, le fournisseur redirige l’utilisateur vers l’URL de callback B. Le fournisseur d’identité ajoute à cette URL de redirection le token d’authentification ainsi que le state créé en étape 2 .

4) De retour sur l’API, l’authentification ASP.NET vérifie le state, examine le token et détermine si l’utilisateur est déjà connu de l’API.
Si ce n’est pas le cas, l’API créé un nouvel utilisateur dans l’application. L’API récupère les informations “credentials” de l’utilisateur depuis le fournisseur d’identité externe, tels que le user name, profile picture et autres données.

5) L’API créé ensuite un access token. Puis elle redirige l’utilisateur directement dans l’application grâce à l’URL A.
Elle ajoute à l’URL le state de l’application mobile définie en étape 1 ainsi que le token d’authentification nouvellement créé. L’URL de redirection permet à l’application d’extraire l’état ainsi que le token.

6) À partir de cette étape, l’application mobile doit envoyer le token d’authentification ainsi reçu dans chaque requête au serveur d’API en utilisant l’authentification de type Bearer. Le serveur peut vérifier ce token et le rattacher à un utilisateur, et ainsi décider de fournir les ressources protégées selon une politique interne de gestion des droits.

Je vous donne rendez-vous dans le prochain article pour étudier ensemble la mise en place de ce type de sécurité dans une application Xamarin et une API de Backend en ASP.Net Core.

© SOAT
Toute reproduction interdite sans autorisation de l’auteur

Nombre de vue : 755

AJOUTER UN COMMENTAIRE