Développer soi-même la connexion d'une application est une décision qui se prend rarement de façon explicite : on ajoute un formulaire, une table d'utilisateurs, une vérification de mot de passe, et le système existe avant qu'on ait choisi de le construire. Le résultat fonctionne, il laisse passer les bonnes personnes et refuse les autres, ce qui donne l'impression que le travail est terminé. Il ne l'est pas, parce qu'un système d'authentification ne se juge pas à ce qu'il autorise mais à ce qu'il empêche dans des situations que le développement normal ne rencontre jamais. Cet article distingue ce qu'il faut réellement écrire, ce qu'il faut confier à des composants existants et ce qu'il vaut mieux ne pas tenter du tout.
Ce qui relève vraiment du code maison
La première clarification utile consiste à séparer deux choses que l'on confond souvent : la logique métier de l'accès et les primitives cryptographiques qui la soutiennent. La première appartient au projet et personne ne peut l'écrire à votre place, puisqu'elle décrit qui a le droit de faire quoi dans un contexte précis. La seconde est un domaine à part entière, où la moindre approximation produit une faille exploitable, et où toute tentative d'écriture personnelle est une erreur. Cette distinction structure l'ensemble du travail et elle évite les deux dérives classiques, celle qui consiste à tout réécrire et celle qui consiste à tout déléguer à une dépendance mal comprise. Le sujet touche directement aux mécanismes que nous décrivons dans notre article sur les failles de sécurité d'un site Internet.
Ce qui vous appartient, c'est le modèle des comptes et de leurs états. Un utilisateur peut être inscrit sans avoir vérifié son adresse, actif, suspendu, en attente de validation par un administrateur, ou supprimé sans que ses contenus le soient. Chacun de ces états commande un comportement différent au moment de la connexion, et cette matrice ne ressemble à celle d'aucun autre projet. L'écrire soi-même n'est pas seulement légitime, c'est indispensable, car aucune bibliothèque ne connaît vos règles métier. C'est aussi la partie qui contient le plus de bogues fonctionnels, parce qu'elle grandit par ajouts successifs sans que personne ne reprenne l'ensemble.
Vous appartiennent également les règles d'autorisation, qui sont un sujet distinct de l'authentification et que l'on traite trop souvent au même endroit. Savoir qui est l'utilisateur relève de l'authentification ; savoir ce qu'il peut faire relève de l'autorisation. Mélanger les deux dans les mêmes fonctions produit un code où l'ajout d'un rôle oblige à relire des dizaines d'emplacements. Les séparer dès le début coûte une heure et évite un chantier de plusieurs jours au premier changement d'organisation. Cette séparation devient une évidence dès que l'application dépasse deux profils d'utilisateurs.
Enfin, le parcours lui-même vous appartient : les messages affichés, le moment où l'on demande une confirmation, la manière dont on accompagne quelqu'un qui a perdu son accès. Ces choix ont un effet direct sur le taux d'abandon et sur le volume de sollicitations reçues par le support, et ils dépendent entièrement du public visé. Une application interne destinée à trente collaborateurs et une plateforme ouverte au grand public n'appellent pas les mêmes arbitrages. C'est là que le développement sur mesure produit sa valeur, bien plus que dans la réécriture de mécanismes techniques déjà résolus ailleurs.

Le stockage des mots de passe
Le stockage des mots de passe est le point où l'on ne fait aucun choix personnel. Une fonction de dérivation conçue pour être lente est appliquée au mot de passe avec un sel aléatoire, et le résultat est stocké. Cette fonction doit venir du langage ou d'une bibliothèque reconnue, jamais d'un assemblage maison de primitives, même si l'assemblage paraît solide. Les fonctions modernes intègrent le sel dans leur sortie, gèrent le coût de calcul et permettent de le relever plus tard sans invalider les comptes existants, trois propriétés qu'une implémentation personnelle n'aura pas. La question du chiffrement sous-jacent est développée dans notre article sur le standard de sécurité AES-256-GCM.
Le coût de calcul mérite un réglage explicite plutôt qu'une valeur par défaut acceptée sans réflexion. Trop bas, il rend une attaque hors ligne réalisable ; trop haut, il permet de saturer le serveur en enchaînant les tentatives de connexion. Un temps de calcul de l'ordre de deux à trois cents millisecondes sur le matériel de production constitue un repère raisonnable, à revérifier après chaque changement d'hébergement. Ce réglage se mesure, il ne se devine pas, et la mesure prend quelques minutes avec un script de test. Beaucoup d'applications tournent avec le paramétrage par défaut d'une bibliothèque installée il y a cinq ans, ce qui ne correspond plus au matériel actuel.
La possibilité de rehacher au moment de la connexion est une fonction souvent ignorée et pourtant essentielle. Lorsque l'utilisateur se connecte, son mot de passe est disponible en clair pendant l'instant de la vérification ; c'est le seul moment où l'on peut le stocker à nouveau avec un algorithme ou un coût mis à jour. Une vingtaine de lignes suffisent à implanter cette migration progressive, qui permet de faire évoluer le stockage sans jamais demander à personne de changer son mot de passe. Sans ce mécanisme, un changement d'algorithme impose une réinitialisation générale, opération pénible et coûteuse en support. C'est typiquement le genre de détail qui distingue un système écrit avec méthode d'un système écrit dans l'urgence.
Reste la question des règles imposées à l'utilisateur, où l'usage a nettement évolué. Les contraintes de composition, majuscule, chiffre, caractère spécial, produisent des mots de passe prévisibles et difficiles à retenir, donc réutilisés d'un site à l'autre. Les recommandations actuelles privilégient une longueur minimale généreuse, une vérification contre les listes de mots de passe déjà compromis, et l'absence de renouvellement périodique obligatoire. Ces trois règles sont plus simples à implanter que les anciennes et nettement plus efficaces. Elles se heurtent parfois à des exigences internes héritées, qu'il vaut la peine de discuter plutôt que d'appliquer sans examen.
La session et son identifiant
Une fois l'identité vérifiée, il faut la porter d'une requête à l'autre, et c'est là que se logent la plupart des défauts observés en audit. L'identifiant de session doit être suffisamment long et produit par un générateur cryptographique, jamais par une fonction de hasard ordinaire. Il doit être régénéré au moment précis où le niveau de privilège change, c'est à dire à la connexion et à toute élévation de droits, faute de quoi un identifiant obtenu avant la connexion reste valide après. Ce mécanisme est détaillé dans notre article sur les sessions PHP, leur durée de vie et leur régénération.
Le cookie qui transporte cet identifiant demande trois attributs et leur absence est immédiatement exploitable. L'attribut interdisant l'accès par script protège contre le vol par injection de code. L'attribut restreignant l'envoi aux connexions chiffrées empêche la transmission en clair. L'attribut contrôlant l'envoi lors des requêtes provenant d'autres sites limite une classe entière d'attaques. Ces trois attributs se posent en une ligne de configuration et leur oubli est pourtant l'un des constats les plus fréquents sur les applications développées sur mesure.
La durée de vie mérite deux notions distinctes plutôt qu'une seule. Une session peut expirer après une période d'inactivité, ce qui protège un poste laissé sans surveillance, et elle doit aussi expirer de façon absolue au bout d'un délai maximal, ce qui limite la valeur d'un identifiant volé. Combiner les deux est simple et rare. L'ajustement de ces durées dépend entièrement du contexte : une application bancaire et un outil de rédaction interne n'appellent évidemment pas les mêmes valeurs. La bonne pratique consiste à les rendre configurables plutôt qu'écrites en dur.
Le stockage côté serveur enfin détermine ce qu'il est possible de faire ensuite. Conserver les sessions dans une base plutôt que dans des fichiers permet de lister les sessions actives d'un utilisateur, de les révoquer individuellement et de déconnecter tout le monde après un incident. Ces fonctions sont attendues par les utilisateurs, qui les rencontrent sur les grands services, et elles deviennent obligatoires dès qu'un incident survient. Les ajouter après coup demande de migrer le stockage, opération sans difficulté mais que l'on préfère éviter en production. Prévoir dès le départ une table de sessions coûte très peu et ouvre toutes ces possibilités.
| Élément | À coder soi-même | À déléguer |
|---|---|---|
| États des comptes | Oui | Aucune bibliothèque ne les connaît |
| Règles d'autorisation | Oui | Propres au métier |
| Hachage du mot de passe | Non | Fonction native du langage |
| Génération d'aléa | Non | Générateur cryptographique |
| Gestion des sessions | Partiellement | Socle du langage, logique maison |
| Second facteur | Non | Bibliothèque conforme au standard |
| Envoi des courriels | Non | Service d'expédition dédié |
| Parcours et messages | Oui | Dépend du public visé |
Estimation moyenne observée sur des projets sur mesure de taille moyenne, hors phase de tests de sécurité.
L'inscription et la vérification de l'adresse
Le parcours d'inscription semble anodin et il concentre pourtant plusieurs décisions qui engagent la suite. La première porte sur ce que l'application révèle lorsqu'une adresse est déjà utilisée. Répondre franchement que le compte existe permet à un tiers de tester des adresses et de constituer une liste de clients, ce qui pose un problème réel sur certains services. Répondre de façon uniforme protège cette information au prix d'un parcours moins confortable. L'arbitrage dépend de la sensibilité du service, et il doit être pris consciemment plutôt que subi par défaut.
La vérification de l'adresse repose sur un jeton envoyé par courriel, et ce jeton obéit aux mêmes exigences qu'un identifiant de session. Il doit être long, aléatoire, à usage unique et limité dans le temps, généralement quelques heures. Le stocker haché en base plutôt qu'en clair évite qu'une fuite de la base ne donne accès aux comptes non encore vérifiés. Cette précaution coûte trois lignes et elle est presque toujours absente des implantations maison, parce que le jeton est perçu comme moins sensible qu'un mot de passe. Il l'est autant, puisqu'il permet exactement la même chose.
La question du compte non vérifié demande une décision explicite. Certaines applications laissent l'accès complet et rappellent la vérification, d'autres bloquent tout, d'autres encore autorisent la consultation et interdisent les actions. Les trois choix se défendent selon le contexte, et l'important est que le comportement soit cohérent sur l'ensemble des points d'entrée, y compris les interfaces programmatiques. C'est souvent là que se glisse un contournement, parce que la vérification a été posée sur les pages et oubliée sur l'interface de service.
Le nettoyage des inscriptions abandonnées mérite enfin d'être prévu dès l'origine. Une table d'utilisateurs qui accumule des comptes jamais vérifiés devient rapidement inexploitable, fausse les statistiques et complique les envois. Une tâche planifiée supprimant les inscriptions non confirmées après quelques jours règle la question, à condition de la mettre en place avant que le volume ne devienne important. Cette maintenance discrète fait partie du système au même titre que le formulaire de connexion, et elle est systématiquement oubliée dans les développements initiaux.
La réinitialisation du mot de passe
La procédure de réinitialisation est le maillon le plus attaqué de tout système d'authentification, pour une raison simple : elle permet, par construction, de prendre le contrôle d'un compte sans connaître le mot de passe. Toute faiblesse à cet endroit annule le soin apporté ailleurs. Le principe est pourtant établi et ne demande aucune invention : un jeton aléatoire, haché en base, valide une heure, utilisable une seule fois, invalidé dès qu'un nouveau est demandé. Chacune de ces cinq propriétés répond à une attaque documentée, et en omettre une seule rouvre le chemin correspondant.
La réponse affichée après la demande doit être identique que l'adresse existe ou non, sans quoi le formulaire devient un outil de vérification d'existence de comptes. Cette uniformité doit aussi porter sur le temps de réponse, détail auquel on pense rarement : si l'envoi d'un courriel prend deux secondes et que l'absence de compte répond immédiatement, l'information fuit malgré le message identique. Confier l'expédition à une file d'attente règle ce point tout en améliorant la robustesse générale. C'est un bon exemple de correction qui sert deux objectifs à la fois.
Le changement effectif du mot de passe doit entraîner deux effets souvent négligés. Toutes les sessions actives de l'utilisateur doivent être invalidées, puisque la réinitialisation survient fréquemment après une compromission suspectée. Et une notification doit partir vers l'adresse enregistrée, indiquant que le mot de passe vient d'être changé, ce qui donne à la personne légitime une chance de réagir si ce n'est pas elle. Ces deux comportements représentent quelques lignes et ils transforment la valeur défensive de la procédure. Leur absence est la règle sur les systèmes écrits sans revue.
Une limitation du nombre de demandes s'impose enfin, par compte et par adresse réseau. Sans elle, la fonction devient un moyen d'inonder la boîte aux lettres d'un utilisateur et de faire classer vos courriels comme indésirables par les fournisseurs de messagerie. Une demande toutes les quelques minutes suffit largement à l'usage légitime. Cette limitation protège autant la réputation d'expéditeur du domaine que les comptes eux-mêmes, ce qui en fait une mesure doublement rentable.
Résister à l'automatisation
Un formulaire de connexion accessible publiquement subit des tentatives automatisées dans les jours qui suivent sa mise en ligne, quel que soit le trafic du site. Ces tentatives ne visent pas le site en particulier : elles rejouent des identifiants issus de fuites en espérant que quelqu'un ait réutilisé son mot de passe. La limitation du nombre d'essais est donc une nécessité fonctionnelle et non une précaution facultative. Elle doit porter sur le couple identifiant et adresse réseau, avec des seuils différents, pour ne pas bloquer un bureau entier partageant une sortie commune.
Le verrouillage pur et simple d'un compte après quelques échecs pose un problème qui lui est propre : il offre à un tiers le moyen de bloquer n'importe qui en échouant volontairement. Un délai croissant entre les tentatives constitue une réponse plus équilibrée, qui rend l'attaque automatisée impraticable sans donner ce pouvoir de nuisance. Combiné à une vérification supplémentaire au delà d'un certain nombre d'échecs, il couvre la quasi totalité des cas rencontrés. Ce type de réglage se surveille dans les journaux pendant les premières semaines pour être ajusté au trafic réel.
La journalisation des tentatives, réussies comme échouées, mérite d'être prévue dès l'écriture du système plutôt qu'ajoutée après un incident. Sans elle, une compromission ne laisse aucune trace et l'analyse devient impossible. Ce journal ne doit évidemment contenir aucun mot de passe, même partiel, ni aucun jeton, et sa durée de conservation doit être définie en cohérence avec les obligations applicables au traitement des données personnelles. Nous ne sommes pas juristes et cette question mérite d'être posée à un conseil compétent selon le contexte de l'application.
Le second facteur constitue enfin la protection la plus efficace contre le rejeu d'identifiants volés, et c'est précisément le composant qu'il ne faut pas écrire soi-même. Le standard des codes temporels est implanté par des bibliothèques éprouvées dans tous les langages, avec la gestion de la dérive d'horloge et des codes de secours. Le travail restant consiste à décider quand l'exiger, comment gérer la perte du téléphone et comment accompagner les utilisateurs peu à l'aise. Ce travail là, en revanche, vous appartient entièrement et conditionne l'adoption effective de la mesure.
Savoir renoncer au code maison
Il existe des situations où écrire son propre système est un mauvais calcul, et les reconnaître fait partie de la compétence. Dès que l'application doit rejoindre un annuaire d'entreprise, accepter une identité fédérée ou s'intégrer à un ensemble d'outils partageant la même connexion, les protocoles concernés sont trop denses pour être implantés correctement en quelques jours. Les bibliothèques certifiées existent et leur usage n'a rien de honteux. Le sur mesure garde alors sa place dans l'intégration et dans la logique métier, pas dans le protocole.
Le second signal est le volume d'exigences réglementaires ou contractuelles. Un client imposant des durées de conservation précises, une traçabilité complète des accès et une politique de mots de passe documentée demande un système dont la conformité doit pouvoir être démontrée. Repartir d'un socle reconnu, dont les propriétés sont documentées, simplifie considérablement cette démonstration. À l'inverse, un système maison oblige à produire soi même toute la documentation associée, travail rarement anticipé dans le devis initial.
Le troisième signal est la taille de l'équipe et sa continuité. Un système d'authentification demande une maintenance de sécurité pendant toute la vie de l'application, avec des mises à jour lorsque les recommandations évoluent. Une personne seule sur un projet destiné à durer dix ans place l'application dans une situation fragile, quelle que soit la qualité du code initial. Adosser l'authentification à un composant maintenu par d'autres réduit cette dépendance. C'est un raisonnement de gestion de risque autant que de technique.
Reste le cas le plus courant, celui d'une application interne ou d'un service de taille modeste avec des besoins simples. Là, un système maison écrit avec méthode, appuyé sur les fonctions natives du langage et sur deux ou trois bibliothèques bien choisies, est parfaitement défendable et souvent plus lisible qu'une dépendance lourde mal maîtrisée. La condition tient en une phrase : coder la logique, jamais la cryptographie, et se relire à partir d'une liste de points de contrôle plutôt qu'à partir de son intuition. C'est cette discipline, plus que le choix entre maison et bibliothèque, qui fait la différence à l'usage.
💬 0 commentaires
✍️ Laisser un commentaire
Créez un compte gratuit ou connectez-vous pour commenter.