Accueil > OpenID Connect OAuth Serveur dédié > Développer > Typologie des applications au regard de la sécurité des données

Typologie des applications au regard de la sécurité des données

Application "Web", "publique", "privée", "confidentielle", "avec back-end", "sans-backend", "native", "hybride", "à page unique" (SPA), "Progressive Web App" (PWA) etc. Comment s’y retrouver ? Quelle est leur sécurité selon les flux d’autorisation mis en oeuvre ?

Nos échanges récents avec des développeurs ont montré qu’il importait de bien comprendre la configuration des applications par rapport à l’authentification afin de mettre en lumière les limitations d’OIDC et les risques pour la sécurité des données.


Application de confiance, espace de confiance

Un des dangers d’une compréhension superficielle d’OpenID Connect réside dans le fait qu’il est impossible dans certaines configurations d’authentifier l’application. La sécurité des données ( à quelle application sont-elles transmises ? ), repose alors sur la notion d’espace de confiance.

La proposition de standard RFC 6749 est bien claire sur la nécessité de n’utiliser les jetons d’accès que dans un espace de parties autorisées (§ 10.3.) [1] :

Les identifiants de jeton d’accès (ainsi que tous les attributs de jeton d’accès confidentiels) DOIVENT être gardés confidentiels pendant le transit et le stockage, et partagés uniquement entre le serveur d’autorisation, les serveurs de ressources pour lesquels le jeton d’accès est valide et le client auquel le jeton d’accès est émis.

Voyez ici une approche pratique du sujet : Vérification de l’origine de la requête reçue par un serveur de ressource.

Avant de choisir un flux OpenID Connect, il est important d’identifier la configuration des parties prenantes.

Il faut tout d’abord distinguer la Programmation côté serveur de la programmation côté client, qui produisent respectivement des applications avec ou sans back-end.

Programmation côté serveur (server-side programming)

Voir : MDN : Qu’est-ce que la programmation côté serveur ?.

Les serveurs web attendent des requêtes du client, les traitent quand elles arrivent, et répondent au navigateur web avec une réponse HTTP. La réponse contient un statut qui indique si la requête a pu être traitée avec succès ou non (exemple "HTTP/1.1 200 OK" pour indiquer le succès).

Le corps de la réponse, si la requête réussit, contient alors la ressource demandée (comme une page HTML, une image, etc...), que le navigateur web peut alors afficher.

Site statique
Un site statique est un site qui renvoie du contenu codé en dur, c’est à dire le contenu d’un fichier, quand une ressource donnée est demandée.

Site dynamique
Un site dynamique est un site dont une partie des réponses sont générées dynamiquement, au moment de la requête. Sur les sites dynamiques, les pages HTML sont normalement créées en insérant des données d’une base de données dans des espaces réservés à l’intérieur de templates HTML (c’est une manière beaucoup plus efficace que des fichiers statiques pour stocker de grandes quantités de contenu).

Un site web dynamique peut retourner des données différentes pour une URL, en se basant sur les informations fournies par l’utilisateur final (c’est ici que nous rejoignons notre sujet de l’authentification avec OpenID Connect) ou ses préférences stockées, et peut effectuer des opérations avant de retourner la réponse.

La plupart du code pour maintenir un site web dynamique doit s’exécuter sur le serveur. La création de ce code est ce qu’on appelle la "programmation côté serveur" ou "codage back-end".

Les applications construites sur un tel serveur sont dénommées "application avec back-end".

Puisque notre interrogation porte sur la sécurité de l’authentification, cette citation de MDN nous donne la réponse définitive à la question :

Accès contrôlé au contenu. La programmation côté serveur permet aux sites de restreindre l’accès aux utilisateurs autorisés et de ne servir que les informations qu’un utilisateur a la permission de voir.

Il semble que l’on puisse admettre que seule la programmation côté serveur permette cela.

Mais cela suffit-il à catégoriser les applications par rapport à la possibilité de les authentifier ?

Application "avec" ou "sans back end"

Dans un environnement client-serveur, on considère que le client ou agent utilisateur (user-agent), généralement le navigateur, fait office de front-end alors que le serveur fait office de back end.

Application "avec back end"

Une application "avec back end" fait appel pour l’essentiel de son fonctionnement à un logiciel tournant sur un serveur et produisant des sorties vers l’agent utilisateur.
La forme la plus courante consiste, côté front-end, à limiter l’utilisation du Javascript à l’appel des données (en Ajax) et à leur présentation. Une application avec back-end représente un cas de programmation côté serveur (server-side programming).

Les applications "avec back end" permettent de faire circuler les jetons et les données sensibles sur des liaisons serveur-serveur protégées par TLS et hors de portée de l’agent utilisateur (généralement le navigateur de l’utilisateur final) ou des applications étrangères. Elles répondent à une URL fixe.

Le flux "Authorization Code" permet de s’assurer de l’identité d’une application cliente au moyen de l’URL de rappel (Callback URL ou redirection endpoint URI), enregistrée sur l’OP avec l’application.

Application "sans back_end"

Les copies d’une application "sans back end" sont installées et fonctionnent de façon autonome sur les agents des utilisateur finaux (il s’agit généralement d’une page HTML contenant du code Javascript exécuté par le navigateur).

L’URL de rappel pointe vers l’agent utilisateur, et non vers l’application d’origine. Le flux d’Autorisation avec Code peut être inopérant car on ne peut pas s’assurer que le code qui est exécuté est bien le code original, ce qui ouvre la porte à des applications malveillantes situées sur cet agent. Dans l’état actuel, il faut considérer qu’il n’est pas possible d’authentifier une application sans back-end.

Notons que l’on confie à l’utilisateur le soin de reconnaître l’application comme étant la bonne, ce qui explique que la problématique de l’hameçonnage (phishing) soit au cœur de la sécurité des applications.

Application "confidentielle"

Dans l’optique d’OIDC, une application est dite "confidentielle" si le public ne peut accéder au secret de l’application et aux jetons transmis.

On notera que le caractère confidentiel (ou privé) d’une application ne lui est pas inhérent, mais qu’il résulte d’une configuration permettant d’interdire l’accès au secret de l’application et aux jetons, mais aussi d’une configuration permettant la mise en œuvre de toutes les bonnes pratiques de sécurité aboutissant sur une protection effective.

On considère que les identifiants d’une application sans back-end, qui doivent donc figurer dans le code, sont accessibles, de même que les jetons, par rétro-ingénierie ou par des applications tierces exécutées dans le même environnement. Une application "sans back-end" serait donc "non confidentielle", mais cela est modulé par la notion d’espace de confiance.

Notons que les applications natives sous java (Android, iOS) peuvent masquer avec une certaine efficacité le secret de l’application. Il reste à étudier la sécurité de la transmission du secret entre le mobile et le serveur OIDC (à développer).

Application publique (Public client app)

Par opposition aux applications confidentielles, une application publique est une application dont le code est accessible par des étrangers à l’organisation gérant le serveur d’authentification. Elle est par nature non confidentielle, non de confiance car situé en dehors de l’espace de confiance.
Il semble que, pour les RFC, la notion d’application publique implique que l’application n’a pas de secret (ou ne devrait pas en avoir, en tous cas le secret d’une application publique ne sert à rien) .

IP d’une application avec ou sans backend

Lorsqu’une application émet une demande vers un serveur de ressource (RS) :
- les applications "avec back end", émettent leurs requêtes depuis un serveur : la requête sera émise avec l’IP du serveur de l’application.
- les applications "sans back end", émettent leur requête à partir d’un user-agent (le navigateur de l’utilisateur final, le système d’exploitation de l’ordinateur hôte d’une application native etc.) : la requête sera émise avec l’IP de la connexion de l’user-agent, éventuellement masquée par un proxy. Donc rien de prévisible.

Dans le cas d’une application avec backend, l’IP permet à une ressource d’identifier l’application, ce qui n’est pas possible avec une application sans back-end.

Application "Web"

Une application "Web" est ce à quoi nous avons d’abord été habitués : un navigateur standard permet de naviguer dans les pages de l’application en s’appuyant sur un serveur qui peut fournir la totalité de la page, ou y inscrire du code Javascript qui effectuera au sein du navigateur une partie du travail nécessaire, qu’il s’agisse de présentation ou de calculs "métier". Ce qui caractérise l’application Web, c’est sa dépendance au serveur, exigeant une connexion permanente pour fonctionner : une page ne peut être élaborée s’il n’y a pas connexion du navigateur au serveur [2].

Une application Web est donc une "application avec back-end". La totale dépendance au serveur fait des applications Web le domaine idéal d’application du flux "Authorization Code". C’est une configuration facilitant la protection des données dans un espace privé. De plus, les données circulent sur le Web protégées par TLS. Elles ne sont pas accessibles au niveau du système d’exploitation par les autres applications fonctionnant à côté de l’agent utilisateur.
Une application Web est donc potentiellement confidentielle.

Enfin, seul le code situé sur le serveur (et non le code Javascript téléchargée par les pages) est digne de confiance. Comment le code exécuté a-t-il été installé ? Est-il conforme au modèle ? La problématique de l’intégrité du logiciel est l’objet même de cette discussion sur la typologie des applications.

Il faut garder à l’esprit que certaines vulnérabilité existent (dont l’injection de code, les attaque du type Man-In-The-Middle etc.), notamment lorsque des d’applications Web étrangères sont accédées de façon simultanée avec le même user-agent, ou à partir du même poste de travail, ou à partir du même réseau local. OIDC n’apporte dans ce domaine aucune protection qui se substituerait aux bonnes pratiques de sécurité.

Applications "native", et "hybride"

Le qualificatif "native" est apparu pour désigner une application pour smartphone ou tablette développée spécifiquement pour un système d’exploitation mobile ( iOS ou Android ). Il serait plus exact de dire qu’une application "native" s’exécute sur le système d’exploitation d’un ordinateur hôte ( non nécessairement mobile, aussi bien une application lancée sur le système d’exploitation d’un ordinateur de bureau [3] ) mais qui ne nécessite pas de connexion permanente à internet contrairement à une application Web.

Une application "hybride" est une application enveloppée dans un conteneur natif ayant la capacité de charger du code HTML depuis un serveur et de l’interpréter. L’application est généralement formée de pages contenant du code JavaScript qui charge et élabore les données nécessaires pour un affichage en HTML5. Dans certains cas, le contenu est totalement élaboré côté serveur.

Une particularité très importante est la capacité des applications "natives" à accéder aux ressources du système d’exploitation sous-jacent, (y compris le système de fichier, les bases de données etc.) ainsi qu’à la communication inter-applications, localement ou par le réseau. Par contraste, l’accès aux ressources du système est interdit aux applications Web et leur communication est contrainte par la politique "même domaine" (same domain policy).

Pour ce qui est de la sécurisation de l’accès aux données avec OAuth, on retiendra les observations suivantes :

- Une application native peut être considérée comme étant "avec back-end" s’il revient toujours au serveur d’accéder aux serveurs de ressource (RS). On comprend que ce sera souvent le cas d’une application hybride.

- Une application native est une instance d’une application installée sur une machine particulière. Son code est donc accessible, offrant la possibilité de découvrir le secret de l’application.

Cependant, la conservation du secret dans un espace protégé est possible. La classe Java KeyStore ( implémentée notamment par iOS et Android ) permet de protéger les clés. Cependant, la sécurité de ce dispositif n’est bien réelle qu’avec le stockage des clés et/ou certificats sur un système physique indépendant.

- Les données circulent au niveau du système d’exploitation sans chiffrement TLS et sont donc exposées à une interception. Un appareil mobile, du fait de son usage très varié, offre un contexte très risqué du fait de nombreuses applications plus ou moins sûres.

- En revanche, une application native est à l’abri d’un éventuel malware exécuté sur un agent utilisateur local.

La distinction "native" - "hybride" n’est pas très significative : la différence réside dans leur plus ou moins grande capacité à élaborer localement les données "métier" et leur présentation. On omet le plus souvent le qualificatif "hybride" pour inclure ces applications sous le seul qualificatif de "native". Il faudra cependant retenir la première des observations ci-dessus en faveur de l’application "hybride", car la relation avec un back-end permet l’authentification avec le flux Authorization Code qui offre la meilleure sécurité.

Application cliente publique native (public native app clients)

Ce terme désigne les applications natives qui ne sont pas situées dans l’espace de confiance d’une organisation dans lequel se situe également le serveur d’authentification.

Une application "avec back-end" est-elle nécessairement "confidentielle" ?

On classe souvent une application "avec backend" comme application confidentielle ou "privée" et une application "sans back-end" comme application publique.

L’équivalence "avec-backend" <=> "confidentielle" résulte de la capacité à protéger les identifiants de l’application et les jetons. En effet, une application "avec backend" peut être gérée de façon privée (sur un serveur privé d’accès réservé) ce qui interdit au public d’accéder au code et donc aux identifiants.

Cependant, il est nécessaire d’utiliser le flux "Authorization Code" pour que le secret de l’application et les jetons circulent de serveur à serveur et puissent être considérés comme non divulgués.

Une application "sans back-end" est-elle nécessairement non confidentielle ?

Le terme "sans back-end" qualifie une application téléchargée et installée par un utilisateur sur son navigateur ou comme "application native" fonctionnant sur le système d’exploitation d’un mobile ou d’une machine de bureau.

Dans un cas comme dans l’autre, on considère que les identifiants de l’application (qui figurent dans le code) sont accessibles, de même que les jetons, par rétro-ingénierie ou par des applications tierces exécutées dans le même environnement. Une application "sans back-end" serait donc "non confidentielle".

La méthode PKCE (Proof Key for Code Exchange) ou "clé de vérification pour l’échange de code" permet à une application d’éviter d’incorporer dans son code le secret de l’application et de le transmettre. Voir : Clé de vérification pour l’échange de code (PKCE). Beaucoup se l’accordent à dire : ce n’est pas pour autant un apport à la sécurité. En effet, ceci permet d’éviter de propager un secret, mais n’apporte aucune information nouvelle sur l’identité de l’application puisque c’est une instance publique qui est ainsi identifiée. La conformité au modèle original n’est pas garantie.

On pourrait aussi considérer que la sécurité d’une application sans back-end est acquise dans un espace de confiance. On observera alors que la sécurité dépend de l’environnement, non de la nature de l’application.

Application à page unique (Single Page Application, SPA)

Une application à page unique (SPA) est une application Web qui charge une seule page HTML à partir du serveur Web, puis la met à jour de manière dynamique (avec du code Javascript exécuté localement) en réponse à l’interaction de l’utilisateur et à d’autres événements.

Plusieurs architectures permettent de créer des applications à page unique. La tendance est l’architecture "serveur léger", qui fournit la page initiale contenant du code Javascript qui assurera la logique et les transitions d’état de l’application, celle-ci obtenant ses données d’API RESTful protégées par OAuth 2.0.

Une application à page unique, bien qu’étant issue d’un serveur, doit être considérée comme étant publique, et non comme une application avec back-end, car tout son code se trouve transféré sur l’user-agent. Pour en savoir plus : OIDC et les Application à page unique : exemple d’une belle mascarade !.

Progressive Web App (PWA)

Une PWA se consulte comme un site web classique, depuis une URL sécurisée. Elle est donc, du point de vue de la protection des données, de type "avec back-end".

Si les données protégées sont exclusivement accédées depuis le serveur de l’application (et non depuis le navigateur), et que l’on applique le flux d’autorisation avec code, on se trouve dans une excellente configuration : la PWA offre des fonctionnalités proches de celle d’une application native sans les problèmes de sécurité que pose une application publique.

Les PWA offrent tellement d’avantages qu’elles devraient remplacer toutes les applications natives, qu’elles soient installées sur mobile ou sur desktop.

 

Certaines méthode renforcent la sécurité du flux Authorization Code utilisé par des applications sans back-end

L’authentification OpenID Connect concerne la couche applicative. Dans le cas des applications avec back-end, nous avons vu que l’authentification de l’application était effective. Mais dans le cas d’applications mobiles ( sans back-end ), nous sommes devant une difficulté. En effet, la notion d’application "publiques" ( sans secret ) interdirait l’authentification de l’application, ouvrant la porte aux applications malveillantes.

Sans pour autant assurer l’identification des applications sans back-end, il existe des méthodes renforçant la sécurité du flux Authorization Code :

- Les méthodes de "fingerprinting" ( qui sont aussi des méthodes utilisées pour le tracking ), par exemple "Canvas fingerprinting", identifient l’user-agent et la machine hôte, pas l’application. En fait, l’user-agent est une encapsulation qui fait obstacle à l’identification de l’application légitime par le serveur d’authentification.

- La méthode "Proof Key for Code Exchange, PKCE" renforce la sécurité de la délivrance des jetons par le contrôleur Token, en vérifiant que l’application qui demande les jetons est bien celle qui a initié l’authentification. Il n’y a donc pas non plus identification. De plus, cette méthode n’est pas applicable à la vérification par les ressources protégées.

- Les méthodes de type "Proof of Possession, PoP", permettent d’identifier l’application comme étant bien celle qui a fait l’objet de l’authentification initiale, donc celle qui est légitimement associée au jeton JWT qu’elle présente aux ressources protégées. Nous classerons dans cette catégorie la Liaison du jeton à la connexion TLS (TLS Token Binding).

Ces méthodes réduisent le risque [4] d’un vol de jeton, mais ne permettent pas d’authentifier une application cliente sans back-end.

Par ailleurs, des systèmes tels que Active Directory (Kerberos) identifient l’utilisateur et la machine hôte au niveau de la couche de communication. Une fois l’authentification effectuée, toutes les applications exécutées sur la machine du client sont mises sur le même plan, bonnes ou malveillantes. La notion de service (un logiciel installé sur une machine et un port) permet d’ authentifier une application avec back-end. L’authentification des applications sans back-end n’est pas envisageable.

Et l’Internet des Objets dans tout cela ?

Dans l’Internet des Objets (IOT), les objets sont des agents utilisateurs comme l’est un navigateur ou une application native. Les raisonnement faits sur la confidentialité des données échangées ne sont en rien différents dans le cas des objets : leur logiciel doit être fait avec des applications Web (ou des Progressive Web App aussi bien) et mettre en œuvre l’authentification avec Code.

Les objets peuvent aussi communiquer entre eux. S’ils le font en direct (et non en passant par un serveur, ce qui ramènerait au cas général), les canaux de communication doivent être sécurisés point à point. Une approche serait de considérer que l’objet fournisseur de données devra être sécurisé exactement comme n’importe quelle ressource protégée, et devra donc vérifier l’application cliente auprès du serveur OIDC.

Une conclusion s’impose

L’analyse montre que :

Nous ne sommes en mesure d’assurer pleinement la sécurité des données que dans le cas du flux "Authorization Code" pour des applications "avec back-end", autrement dit : les applications Web dont les Progressive Web Apps.

Ou bien encore :
On ne peut faire confiance à un user agent.

Notes

[1L’attention du lecteur est appelée sur le risque qu’il y a à lire le paragraphe qui suit au bord d’un gouffre, en traversant la rue ou, plus généralement, dans toute situation où un vertige pourrait avoir des conséquences fatales. J’ai subi un terrible choc le jour où j’ai lu cela. La thérapie a consisté à écrire la rubrique dont cet article fait partie.

[2Cependant la connexion peut être discontinue, voir les Progressive Web Application (PWA).

[3L’usage commun à de nombreux sites Web consiste à réduire la notion de ’native" aux applications de mobile développées sous iOs ou Android. La RFC 8252 va dans notre sens dans le paragraphe 7.3 en incluant dans les applications natives "celles des systèmes d’exploitation de bureau".

[4Le terme anglais utilisé le plus souvent est "mitigate" (attacks) = atténuer, réduire (les attaques).