Blog Zenika

#CodeTheWorld

Architecture

Quel identifiant exposer vers l’extérieur ?

Que ce soit au sein d’un système d’information d’entreprise (SI) ou sur le WEB, via des flux de fichiers, des API ou encore des files de messages, nos applications communiquent toujours plus avec « l’extérieur », c’est-à-dire avec d’autres programmes. Ceux-ci peuvent ne pas se baser sur les mêmes technologies, ne sont pas plus supposés connaître le fonctionnel ni les spécificités de nos applications, que nous ne connaissons les leurs.
Lorsque plusieurs applications doivent interagir de concert pour manipuler des données, la première question qui se pose a l’air toute bête : comment faire référence à ces données? Quelle information connue, même de l’application client si elle est l’instigatrice de la communication et interprétable sans ambiguïté par les deux parties, utiliser ?

Que choisir, technique ou fonctionnel ?

Le technique et le fonctionnel 

Nos applications identifient usuellement en interne leurs principaux objets métiers grâce à des identifiants : les identifiants techniques, souvent les clés primaires des tables principales et les identifiants fonctionnels.
Note : les termes “technique” et ”fonctionnel” sont certes très utilisés dans le monde de l’informatique de gestion, mais leurs définitions changent selon l’interlocuteur. On est souvent tenté de considérer que ce que l’on maîtrise mal relève forcément de l’autre « bord » … Histoire d’éviter toute ambigüité, définissons pour la suite ces termes :

  • La partie fonctionnelle: la partie émettrice des besoins et exigences définissant le produit (sous réserve de budget et délais suffisants et du respect des process admis).
  • La partie technique: l’équipe en charge de la conception technique, de la réalisation  et parfois de l’exploitation du produit. La partie technique a un aussi un rôle de conseil vis-à-vis de la partie fonctionnelle, mais cette dernière reste seule décisionnaire des choix fonctionnels.
  • (Domaine) fonctionnel : Ensemble des notions découlant des besoins et exigences exprimés par la partie fonctionnelle. Chaque élément de cet ensemble a du sens du point de vue du métier. La partie fonctionnelle est responsable de sa formalisation (spécification) explicite et est libre de le faire évoluer. La partie technique n’est pas censée faire d’hypothèses le concernant sans la validation de la partie fonctionnelle.
  • (Domaine) Technique : Ensemble des notions n’appartenant pas au fonctionnel mises en place par la partie technique pour implémenter les besoins et respecter les besoins et exigences de la partie fonctionnelle. Une notion est donc soit technique, soit fonctionnelle.

Attention :

  • Le technique et le fonctionnel n’ayant pas d’élément commun, la partie fonctionnelle ne doit pas avoir besoin de se référer aux notions techniques pour spécifier le fonctionnel : si une notion lui manque, elle doit l’introduire et donc la définir. La partie technique verra comment la gérer. « Voler » une notion technique est toujours à éviter, car cela peut induire des incompatibilités entre les nouvelles ou futures règles fonctionnelles et les partis pris techniques antérieurs.
  • Pour paraphraser la chanson, les mélanges des genres finissent mal, en général. La mauvaise pratique la plus commune est, en base de données (BDD), de confondre hâtivement la notion technique de clé primaire et celle de clé fonctionnelle…
  • Seules les notions (données, choix …), techniques et fonctionnelles, sont à distinguer! La collaboration et les interactions entre la partie technique et la partie fonctionnelle sont bien entendu à favoriser sans réserve: si chacun a son domaine de compétence, personne ne doit se priver d’informer, de débattre, ni de se renseigner.

Quel type d’identifiant exposer de préférence ? 

Un identifiant technique est un identifiant à priori sans aucun sens fonctionnel (ou seulement par effet de bord, qu’il ne faudrait pas exploiter dans ce sens s’il existe un identifiant fonctionnel), et dont les principales caractéristiques sont :

  • Toujours valorisé,
  • Unique, jamais réattribué à une autre entité (distincte),
  • À priori immuable (ne devant pas être modifié une fois attribué)
  • (dans son usage interne, il est techniquement « pratique », optimisé pour les jointures…)

Il s’agit typiquement d’une séquence, ou du détournement d’autres valeurs tenues pour uniques et non nulles par ailleurs.
Un identifiant fonctionnel est un identifiant dont l’attribution de la valeur se conforme à des règles métiers, dont les principales caractéristiques sont :

  • Toujours valorisé,
  • Unique,
  • Son recalcul devrait toujours mener à la même valeur (idéalement). A minima, une valeur distribuée ne devrait jamais mener à des ambiguïtés (entre plusieurs entités),
  • Sa valeur est humainement compréhensible, indépendante des technologies employées.
  • À la marge, si le fonctionnel change, il pourrait éventuellement changer sous réserve du respect des règles précédentes (exemple : si l’ID fonctionnel de mon abonnement téléphonique est mon numéro de téléphone et que je demande à en changer). Ne surtout pas abuser de ce point

Notons que les entités que l’on stocke ne sont pas nécessairement les mêmes que celles que l’on expose (limitation à certains champs, agrégation d’autres données, traitements métiers…). Ne retenons pas aveuglément les identifiants internes pour identifier les entités que l’on exposera (à nos partenaires).
De façon générale, un identifiant technique ne devrait pas avoir à être utilisé par le fonctionnel (CI, règles métiers…), ni exposé à l’extérieur pour les raisons suivantes.

La reprise sur incident

En cas d’incident nécessitant une restauration des données (récupération d’une sauvegarde potentiellement incomplète) et le rejeu du différentiel (archive log, import de fichiers…), une même entité fonctionnelle recréée peut se voir attribuer un autre identifiant technique que celui de l’entité initialement créée. De même, la première valeur d’ID technique peut se voir affectée à une autre entité fonctionnelle.
Citons par exemple les cas suivants (liste non exhaustive) :

  • L’identifiant est valorisé par une séquence Oracle dont certains appels (manuels, comme SELECT ma_sequence.nextval from dual) en lecture seule n’auraient pas été répercutés dans les log bin. Ou cette séquence a été invoquée au travers de sessions pour lesquels la gestion des log bin aurait été désactivée. Lors du rattrapage, on observera alors un décalage des identifiants techniques distribués,
  • Les entités ont été créées par des jobs d’imports s’exécutant en parallèle créant nos entités, sans synchronisation particulière. Rien ne garantit que les différents processus s’exécutent au même rythme les uns par rapport aux autres et donc que les mêmes identifiants techniques seront réattribués aux mêmes entités.

Si cet identifiant a déjà été propagé dans le SI ou vers l’extérieur (à un client?), cela peut provoquer de lourdes conséquences métier et d’importants coûts de chantiers correctifs. Ce point est à mon sens suffisant pour trancher ce sujet.

La complexité à propager les Id

L’identifiant technique n’ayant aucun sens hors de son application, cela ajoute une donnée supplémentaire à transmettre, que les partenaires devront connaître…
Par exemple, quand on appelle son FAI, on donne de façon générale son numéro de téléphone (identifiant  fonctionnel) plutôt qu’un identifiant obscur que l’on ne saura pas forcément où chercher à chaud.
Pour aller plus loin, si chaque application d’un SI impose aux autres ses propres numéros de séquences ou équivalent au lieu d’une information dont le fonctionnel transverse garantit déjà la diffusion et la compréhension… on n’en sort plus!

Les problématiques de typage

Même si ce n’est pas une règle absolue, les identifiants techniques sont souvent numériques ou de types natifs spécifiques à nos technologies, comme les ObjectID MongoBD par exemple. Avec les numériques, quid du respect des formats (les 0 en premiers caractères, le nombre de chiffres après la virgule, les espaces de confort…), et du dépassement de capacité d’une techno à l’autre… Quant aux types natifs spécifiques, les autres applications ont-elles vraiment à subir nos choix techniques ?
Les identifiants fonctionnels devraient quant à eux toujours être typés de façon stable (indépendamment des technologies utilisées), par exemple avec des chaînes de caractères.
Note : Afin d’éviter des difficultés prévisibles et aisément contournables, l’ensemble des caractères autorisés pour un identifiant fonctionnel devrait être restreint au jeu de caractère le plus stable possible (pour garantir l’indépendance vis-à-vis des technologies utilisées, je recommande personnellement de se restreindre à minima aux 95 caractères imprimables du jeu de caractères ASCII) et d’exclure tout caractère pouvant en gêner l’usage de l’identifiant, dans des URL notamment. Ce point est un exemple du rôle de conseil de la partie technique à la partie fonctionnelle qui épargnera à celle-ci comportements dégradés et  surcoûts.

Identifiants et sécurité

Au risque d’enfoncer des portes ouvertes, le rôle d’un identifiant, c’est d’identifier. Ne faisons pas peser sur eux les problématiques de sécurité, ce n’est pas leur job ! Dans le cas des web services, notamment des API REST, il faut bien veiller à distinguer obfuscation (rendre la bidouille d’URL complexe et espérer que cela suffise) et sécurisation.
Obfuscation : La connaissance de l’URL d’une action sur une entité m’est fournie, me permettant de l’invoquer. L’URL est supposée assez complexe pour ne pas que je puisse en déduire une autre provoquant une autre action et/ou visant une autre entité.
Cette approche est intrinsèquement déficiente pour pas mal de raisons :

  • Détenir l’URL permet l’action (même si on l’a acquise par l’interception d’une trame, d’un mail, d’un cookie, de l’historique du navigateur du voisin… qui ne nous était pas destiné !),
  • Une attaque de masse a toujours des chances de provoquer quelques coups chanceux (enfin chanceux, ça dépend pour qui…),
  • Révocation de droits (je ne suis plus habilité, puis-je utiliser une URL transmise lorsque j’avais encore les droits correspondants?)

Sécurisation, pour un service
Dans le cadre d’une API exposant un service, tout le monde n’est pas forcément censé pouvoir manipuler n’importe quelle ressource. De plus, à l’échelle d’une ressource donnée, tout le monde n’a pas toujours les mêmes privilèges (lecture, création, modification, suppression, actions spécifiques…). La sécurisation consiste à minima à nous assurer que l’origine de la requête est légitime dans sa demande.
A minima, l’exécution du traitement d’un service à sécuriser doit toujours être précédée des trois phases suivantes :

  • Identifier l’origine (déclarative) de la requête (par un login par exemple) – c-à-d déterminer à qui on est censé avoir affaire,
  • Authentifier cette identification (certificat, cookie de session en https, mot de passe…) c-à-d vérifier que l’on a la preuve que l’on a bien affaire à qui l’on croit,
  • Contrôler en fonction de la connaissance propre du serveur que l’origine identifiée et authentifiée a bien le droit d’effectuer l’action demandée sur la ressource demandée (les droits ne sont pas déclaratifs via l’URL !)

Par exemple, si je veux accéder à l’un de mes mails, le serveur passe par les étapes :

  • Quel est ce login ? Ah c’est celui de Pierre.
  • Et le mot de passe est correct. C’est donc bien lui.
  • Il demande de voir tel mail ? Oui, Pierre a bien le droit de visualiser ce mail.

Note : c’est au serveur exposant une fonctionnalité d’implémenter la sécurisation des ressources qu’il expose. Ne pas reporter cette responsabilité sur l’application client.
On se moque en principe que quelqu’un ayant réellement les droits suffisant pour effectuer une action donnée sur une ressource donnée le demande par une URL manuellement bidouillée. Il nous faut par contre nous protéger des cas suivants :

  • On ne sait pas qui nous appelle,
  • L’appelant tente de se faire passer pour quelqu’un d’autre,
  • L’appelant n’a pas les droits d’effectuer l’action demandée sur la ressource demandée

Notes :

  • La phase d’authentification est critique : si elle est mise en défaut, qu’importe que le pirate puisse ou non deviner comment bidouiller nos URL, puisqu’il peut tout simplement réaliser les actions sur les ressources du compte compromis par le circuit nominal,
  • Si nécessaire, des dispositifs supplémentaires peuvent être mis en place, l’obfuscation elle-même par exemple, mais ils ne dispensent en aucun cas d’une sécurisation rigoureuse des accès,
  • La phase d’authentification nécessite aussi une communication de confiance (quid de la diffusion de token de sessions en clair via http (sans le S), de l’hameçonnage…).

Attention, l’obfuscation (seule) permet de se rassurer, une sécurisation rigoureuse permet de se protéger 😉
Attention à la tentation de rattraper notre impuissance à contrôler les accès à nos ressources en rendant juste nos URL illisibles. La bidouille d’URL n’est qu’une menace parmi tant d’autres.

Choix du bon identifiant fonctionnel externe

On l’a dit, il nous faut un bon identifiant fonctionnel. Or, s’il est facile de décider ce qu’est un identifiant technique (c’est technique – conçu par et pour la partie technique  – et c’est à elle de le générer pour qu’il satisfasse à ses obligations), la question du bon identifiant fonctionnel à exposer à l’extérieur est épineuse, et les ratés sont loin d’être anodins.
On a instinctivement tendance à penser à la « clé » fonctionnelle de la table principale du groupe de tables, du document ou autre unité fonctionnelle stockée dans notre modèle de données, comme une référence de facture ou d’article… Attention, ce n’est pas parce qu’une propriété est « unique not null » que cela en fait un bon identifiant de ressource externe.
Le choix d’un bon identifiant fonctionnel nécessite un sérieux travail de réflexion conjoint entre

  • La partie technique, à priori peu à même de se prononcer sur la pérennité de différents champs fonctionnels et des règles aux limites qui leur sont associées,
  • La partie fonctionnelle, dont les notions d’architecture ne font pas partie du métier et pour qui les problèmes techniques ne se posant pas encore sont souvent abstraits.

Pièges à éviter :

  • La divulgation de données personnelles ou confidentielles sensibles. Le texte des URL sera à un moment ou un autre exposé :
    • Évitez toute information jugée sensible par la CNIL. Leur diffusion dans le système d’information vous obligerait de déclarer chacun de vos partenaires amenés à stocker les embarrassants identifiants, et ceux-ci se verraient obligés de faire une déclaration à cause de vos choix ! Et en cas de diffusion mal maîtrisée sur le WEB, prévoir de désagréables conséquences !
    • Imaginons une application médicale de suivi de traitements administrés aux patients utilisant un identifiant formé du numéro de sécurité sociale et le code CPI du médicament prescrit. L’exposition conjointe  de ces deux données, normalisées donc interprétables par un tiers, peut mener à une violation du secret médical.
    • Imaginons un système de suivi des fournisseurs pour votre entreprise. Supposons que ces entités soient identifiées par leur ICE (identifiant commun de l’entreprise au registre du commerce). Votre patron ne souhaite pas forcément révéler à certains de ses fournisseurs avec lesquels de leurs concurrents votre entreprise traite également…
  • Comme déjà évoqué, les références instables dans le temps, sans au moins se doter de moyens de lever de façon certaine l’ambiguïté,
  • Se baser sur des notions fonctionnelles elles-mêmes potentiellement vouées à disparaître (comme se baser sur l’ID d’une application tierce, qui pourrait disparaître avant la vôtre, muter profondément ou ne plus être liée à toute la population d’entité cible). 
  • Se baser sur des notions fonctionnelles ne concernant pas nécessairement toute la population cible (tout le monde n’a pas un compte Facebook par exemple – Si vous identifiez vos clients avec, ne renoncez-vous pas à la clientèle qui ne s’y est pas mise…)

Note : Les contraintes liées à la confidentialité s’appliquent à toutes les informations que vous exposez (via l’URL notamment), pas seulement à l’identifiant!
Se méfier aussi des informations qu’une tierce partie pourrait déduire de ce que vous exposez (exemple : PUT nomAppli/Client/dupond_jean?religion=XXX : ce n’est pas à nous de révéler la religion de notre client, quand bien même cette catégorisation en interne serait légitime)!
Alors que choisir ?
Il n’y a pas de bonne solution universelle. La nature du métier, la cible du service et parfois l’existant influent sur ce qu’est un bon choix. Votre contexte projet pourra rendre certaines contraintes peu critiques, par exemple si vous développez un service exposant des ressources temporaires: Si leur cycle de vie ne dépasse pas quelques heures par exemple, l’instabilité à long terme des identifiants ne sera pas un drame. Par contre, ne rognez jamais sur la confidentialité, ni sur la sécurité !

Quelques réponses usuelles

Livrons-nous à une petite étude de cas.

L’identifiant naturel 

Parfois, c’est simple et il n’y a pas de piège : l’entité dispose d’un identifiant fonctionnel existant et robuste, dont les propriétés sont garanties par ailleurs,  par exemple :

  • Les livres ont leur ISBN,
  • Les articles d’un organisme de vente ou d’un constructeur ont généralement des références normées (catalogue …), tout ce qui a un code-barre a une valeur associée…
  • Il existe de nombreuses normes permettant l’identification au niveau national, européen, par des organismes normalisateurs…

Limites :

  • Attention à la CNIL et aux problèmes de confidentialité !
  • Se méfier des faux amis…

L’erreur classique à éviter est de tordre le bras à une donnée fonctionnelle pas tout à fait adaptée pour en faire artificiellement un identifiant, car ça cadre à peu près, qu’on n’a pas mieux sous la main et qu’il faut bien avancer… 

La restriction métier (ouille, là il faut être certain de son coup)

Si le problème vient de l’instabilité à la marge des identifiants dans des cas identifiés, la partie fonctionnelle peut s’engager sur des restrictions ou profiter de limitations garanties dans la durée à plus haut niveau.
Exemple : Un FAI peut utiliser les numéros de téléphone pour identifier les abonnements et tous les services, options et fournitures liées. Or un numéro de téléphone est réattribuable.
Toutefois, ils s’interdisent de réattribuer les numéros rendus inactifs avant plusieurs mois, et un numéro inactif ne peut pas être consulté par une telle API. L’ambiguïté est levée à ce prix.
Limites :  introduction de contraintes métiers ou durcissement de contraintes existantes (rendre plus complexe et coûteux encore un futur changement des règles actuelles), ici :

  • Plages de numéros réservés par le FAI non attribué et pourtant inutilisables,
  • Impossibilité de requêter ainsi pour des abonnements résiliés.

La composition

Une approche classique lorsqu’aucune propriété ne suffit à discriminer de façon certaine nos ressources consiste à associer plusieurs de leurs propriétés afin de lever l’ambiguïté.
Exemple : une société de location de voiture veut identifier ses locations. On suppose que les voitures sont au moins louées pour la journée. Chaque location peut donc être identifiée par la voiture et la date à laquelle la voiture a été mise à disposition. On peut alors imaginer le couple : date + numéro de châssis (Vehicle Identification Number, ou VIN).
Notez ma préférence pour le VIN, stable dans le temps, plutôt que pour la plaque d’immatriculation. Cette dernière peut changer pour un même véhicule (notamment lors de changements géographiques pour les vieilles plaques et avec les plaques temporaires) voire être réaffectée à un autre véhicule lié au même propriétaire selon la réglementation du pays l’ayant émise.  Ne jamais négliger les cas à la marge dans notre quête du meilleur identifiant.
Limites :  

  • Chacun de nos partenaires doit connaître chacune des informations choisies pour référencer la ressource (ainsi que la règle de construction de l’identifiant).
  • La pérennité de cet identifiant est au mieux celle de sa composante la moins pérenne (péremption des ID propagés / URL).

L’identifiant historique

Lorsque notre seule difficulté réside dans le changement de valeur de la clé fonctionnelle dans le modèle (BDD) mais qu’un même identifiant fonctionnel n’est jamais réattribué, une solution simple est de stocker la valeur de la clé fonctionnelle (côté BDD) à la création de l’entité sans jamais plus modifier cette propriété par la suite, même lorsque la valeur de clé fonctionnelle change. Ces identifiants sont alors stables dans le temps.
Limites : 

  • Cette valeur ne peut plus systématiquement être déduite de l’état courant métier de l’entité => nécessité de transmission de l’information en avance de phase au consommateur du service ?

Au final cette approche se distingue surtout de l’ID technique par la résolution des problèmes de possible réattribution des Id (techniques) suite à un incident et de typage…

L’identifiant transverse

Un client chez qui je suis intervenu se heurtait aux problèmes suivants pour identifier les ressources de son cœur de métier sur l’ensemble de son SI :

  • Données hétérogènes (peu de fonctionnel commun),
  • Diffusion des informations métiers compliquées (propager toutes les données possibles chez tous les appelants possibles était peu réaliste)
  • Le peu de données fonctionnelles communes, pas stables  à 100% et pouvant être réattribuées dans certains cas à la marge !

Ils ont fait une nouvelle application indexant toutes les entités métiers et ont attribué des identifiants uniques et stables. Chaque référentiel se faisait notifier un UID pour chaque nouvelle entité et devait l’intégrer à chacune des entités concernées de son modèle. Bien que de construction « technique », cet ID, normalisé et adopté par l’urbanisme, est devenu un (bon) ID fonctionnel.
Au besoin, on peut aussi mettre en place une sorte d’annuaire centralisé associant pour chaque identifiant ses métadonnées jugées utiles (application référente, identifiants internes, identifiants internes d’autres applications liées…) afin de limiter la dépendance du SI à chaque sous-référentiel et donc la charge et la criticité de ces derniers.
Limites :  

  • Peut-être onéreux,
  • Délai de mise en œuvre,
  • Demande à certains ou à tous les partenaires la prise en compte de la nouvelle donnée ( évolutions N vers N,  ou l’enfer des énormes DSI),
  • L’application procédant à l’indexation est critique. Quid de sa déficience ?

Dernier conseil pour la route…

Ce choix (de l’identifiant d’une ressource externe) – qu’il soit technique ou fonctionnel – n’a rien d’anodin et peut s’appuyer sur des hypothèses que la partie technique ne maîtrise pas toujours dans la durée. Le faire valider par le bon niveau décisionnel au sein de la partie fonctionnelle!

  • Pour la partie technique: En cas de changement des règles du jeu très impactantes / désagréables, cela empêchera la partie fonctionnelle de se « désolidariser » (responsabilité / pression / image…) ;
  • Pour la partie fonctionnelle : Cela évite de découvrir trop tard qu’un cas suffisamment à la marge pour avoir échappé à la partie technique va induire des surcoûts et des retards qui auraient pu être évités, voire de devoir négocier des changements en retard de phase avec ses partenaires !

Dans le cas général comme dans notre cas, partie technique et partie fonctionnelle sont dans le même bateau. L’écoute est primordiale. Ne mésestimez jamais ce que l’autre partie peut apporter!

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

En savoir plus sur Blog Zenika

Abonnez-vous pour poursuivre la lecture et avoir accès à l’ensemble des archives.

Continue reading