Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

CoqBlog

.NET is good :-)
{ Blog de coq }

Actualités

A propos des mots de passe stockés en clair & co

Cet article n'a pas pour but de présenter les meilleures solutions de stockage de mots de passe, que je ne maitrise pas forcément non plus, mais seulement d'avancer des idées/arguments montrant que celle consistant à les stocker en clair (lisible) n'est vraiment pas la bonne.

Dans le cas d'un système autonome, il n'y a à ma connaissance aucune raison valable de le faire. Nous n'avons absolument pas besoin de pouvoir lire ce mot de passe, la seule personne devant en connaître la forme lisible est son propriétaire.
La seule chose qui nous importe est de savoir si le mot de passe que nous fourni l'utilisateur est le même que celui qu'il a défini à l'origine : nous pouvons donc nous contenter de faire notre comparaison sur les empreintes de mots de passe.

Dans le cas d'interconnexion avec d'autres systèmes, on pourrait considérer comme raison valable le fait que notre système doit utiliser ces mêmes informations pour effectuer une authentification sur un autre, mais là je dirais qu'il serait peut être temps de voir pour déléguer cette procédure à un système spécialisé, comme c'est le cas par exemple sur un domaine.
Toutefois si ce n'est pas envisageable et que nous devons transmettre le login/mot de passe de l'utilisateur dans leur forme originelle, nous devons utiliser une forme de stockage cryptée pour limiter au maximum le périmètre dans lequel cette information est lisible.
Et dans ce cas, il serait aussi bon de réfléchir à la réelle nécessité de stocker cette information de façon à pouvoir la retransmettre : ne serait-il pas envisageable de stocker le hash et en cas d'authentification réussie transmettre non pas l'information stockée mais celle saisie ?
Si les transferts doivent être différés, l'information peut être conservée en mémoire volatile, toujours de manière cryptée afin de ne pas avoir de fuite dans des dumps mémoire, durant le transfert vers un cache distribué, etc

Je me placerais pour le restant de l'article dans le contexte d'un système autonome, et prendrais le hash comme alternative au stockage en clair en laissant de côté le cryptage.
Nous aborderons aussi quelques éléments plus ou moins liés à cette gestion de mot de passe.

 

 

Quels sont les différentes formes de stockage que nous pouvons utiliser ?

Les différentes formes de stockage envisageables pour un mot de passe sont :

  • en clair :
    l'information est directement lisible sous sa forme originelle
  • sous forme cryptée :
    la forme originelle de l'information peut être récupérée, mais pour cela il faut en posséder la clé
  • sous forme d'un hash : la forme originelle de l'information est perdue, on ne fait qu'en conserver une empreinte

C'est là la principale chose à retenir à propos du hash : c'est une empreinte de la donnée, pas la donnée.

 

 

Mais quel est le problème avec les mots de passe stockés en clair ?

Dit simplement : le vol d'identité est plus simple que si nous stockons un hash.
Sans tenir compte d'éventuelles failles de sécurité permettant de contourner le système d'authentification, on peut relever plusieurs faits.

L'attaquant n'a pas besoin du même niveau d'accès dans les deux cas
Pour se faire passer pour un utilisateur, en utilisant le système cible de manière tout à fait normale, les accès au stockage des données requis sont :

  • mot de passe stocké en clair : accès en lecture suffisant.
    Il suffit de lire le mot de passe pour pouvoir le saisir en entrée du système cible.
  • mot de passe stocké sous forme de hash (non réversible) : accès en écriture nécessaire.
    En partant du principe que l'attaquant connait la méthode de hash utilisée (ne surtout pas partir du principe qu'il ne la devinera pas), il devra pouvoir procéder à l'écrasement du hash avec un nouveau correspondant au mot de passe désiré.

L'attaquant à normalement plus de chances d'obtenir un accès en lecture seule à l'information qu'un accès en écriture, du moins je l'espère.
L'accès en lecture seule peut notamment être indirect, via des backups de base de données qui seraient moins bien protégés que le système principal, le contenu de scripts, des dumps mémoire, etc
Et sans avoir l'accès direct au stockage des backups, il peut aussi y avoir accès via le moyen de transport de ces derniers s'il n'est pas sécurisé.
S'il dispose d'un accès en lecture aux hashs, il devra encore mettre en oeuvre des traitements pour déterminer quelle chaine de caractères donne ce hash. Ceci peut être couteux en temps, et avec une bonne politique de changement de mot de passe il trouvera peut être la version en clair trop tard pour l'exploiter.

Et si l'attaquant faisait partie de notre service informatique ?
En quoi les personnes ayant, par leur fonction, accès à nos bases de données sont plus digne de confiance qu'une personne externe ?
Ne vont t'il jamais quitter notre entreprise ? Sont-ils seulement directement nos employés ?

Cela nous amène à un autre fait.

La détection du vol d'identité est moins évidente dans un cas que dans l'autre
Les chances que l'utilisateur dont l'identité a été volée s'aperçoive du problème sont moins élevées dans le cas du stockage en clair :

  • mot de passe stocké en clair : si l'attaquant ne laisse pas de trace de ses actions, l'utilisateur ne s'en apercevra peut être jamais
    Dans le meilleur des cas il change son mot de passe régulièrement, mais si l'attaquant a toujours accès en lecture au stockage, cette politique de changement ne fera que le ralentir sans l'arrêter.
  • mot de passe stocké sous forme de hash (non réversible) : suivant la fréquence d'utilisation du service par l'utilisateur ce peut être rapide, vu qu'il n'arrivera plus à s'authentifier avec son mot de passe habituel.
    Il y a de grandes chances qu'il finisse par râler, le tout étant que les équipes de support ne fassent pas un simple changement de mot de passe forcé sans creuser/tracer.

 

 

Inconvénients du stockage du mot de passe sous forme de hash par rapport au stockage en clair ?

Un "inconvénient" de ce mode de stockage est que nous perdons toute possibilité de renvoi de son mot de passe originel à l'utilisateur.
S'il déclare l'avoir perdu, nous sommes obligés de lui en fournir un nouveau que nous générons. 
Nous assortirons cette génération d'une gestion de péremption et nous obligerons l'utilisateur à changer de mot de passe au premier accès : nous l'aurons probablement transmis par mail ou un autre moyen potentiellement non sécurisé.

Avantage de cet inconvénient : nous avons de fait perdue toute possibilité de comportement dangereux du type rappel régulier de son mot de passe à l'utilisateur, système que vous avez probablement déjà observé pour des comptes du genre abonnement à une newsletter par exemple : envoi régulier du mot de passe avec la newsletter.

 

 

Comportement dangereux : incorporation du mot de passe en mail de confirmation

Même si nous stockons des hashs, il reste une chance pour ce comportement dangereux d'incorporation en clair dans une communication : insertion du mot de passe dans le mail de confirmation de création de compte. 
Nous avons encore une "chance" de le faire si jamais notre procédure d'envoi de mail de confirmation est directement liée au processus de création de compte utilisateur.
C'est mal.

Pourquoi donner à l'utilisateur l'information qu'il connait car il vient de la saisir 2 fois ?
A quoi bon changer de mot de passe si le simple fait de le faire oblige l'utilisateur à le refaire (boucle infinie...) car il a été dévoilé ?

Voulons-nous vraiment obliger l'utilisateur à considérer notre système comme à risque et à nous fournir un mot de passe simple car il n'a pas envie d'en retenir un qu'il sait en danger ?

Au pire si l'utilisateur oublie entre temps, que ce soit parce qu'il est parti longtemps avant de traiter le mail ou juste par manque de célérité de notre système d'envoi, ça lui donnera une bonne occasion d'utiliser notre fonctionnalité de récupération (qui pour rappel génère avec délai de péremption et oblige à changer de mot de passe au premier accès).

 

 

La règle "Utiliser un mot de passe par système" et la réalité...

Cette bonne pratique part d'un bon sentiment, mais dans les faits a, à mon avis, peu de chances d'être respectée.

L'utilisateur lambda :

  • ne sais pas qu'elle existe
  • sais qu'elle existe mais n'en a rien à faire
  • n'a pas conscience que son mot de passe peut être connu de quelqu'un d'autre
  • a déjà suffisamment de mal à en retenir un compliqué, alors il le met partout

L'utilisateur avancé ayant connaissance de cette bonne pratique a quand à lui trop de différents comptes utilisateur sur différents système pour retenir une telle masse de mots de passe.

On peut à mon avis avoir dans ce cas affaire à deux écoles :

  • celle consistant à stocker les mots de passe uniques de manière sécurisée par un mot de passe global y donnant accès.
  • différents mots de passe sont utilisés plusieurs fois selon l'importance des systèmes et le niveau de "sacrifiabilité" du mot de passe (si nous avons envoyé son mot de passe en clair à ce type d'utilisateur, je vous laisse deviner de quel type de mot de passe nous allons écoper...).

Ceci nous amène à l'importance du concept de "salt" lors de l'obtention du hash de mot de passe de l'utilisateur.

 

 

A propos de l'utilisation d'un "salt" lors de l'obtention du hash à stocker

Le salt est une information UNIQUE PAR UTILISATEUR que nous pouvons stocker en clair (à la rigueur cryptée, le tout étant de pouvoir en obtenir sa forme originelle), elle doit justement être lisible.
Le salt n'a pas besoin d'être humainement lisible : nous pouvons utiliser un générateur du type RNGCryptoServiceProvider pour le déterminer.
Cette valeur n'intervient que durant une phase : l'obtention du hash, qu'il s'agisse de celle à l'enregistrement en base ou de celle au moment de la vérification d'identité de l'utilisateur.
Son rôle est tout simplement de compléter le mot de passe fournit par l'utilisateur afin de nous assurer que le hash obtenu pour un même mot de passe sera différent.

Le problème avec le hash sans salt
Pour illustrer, prenons le cas de Jean et Paul.
Ils ne se connaissent pas, mais ont tous les deux les mêmes goûts en terme de mot de passe : "toto#titi!tata". 
Nous utilisons un hash SHA512 sans salt, nous obtenons en sortie (Base64) :

Jean :
7KWJOnnYabt9pmwzP/qRAiPAplLlG/vZ37G7NlRh+J8rrE+7jcgF0rGQcXPeMiuQEOXZlaRqeIo+h15aJEwWEw==
Paul :
7KWJOnnYabt9pmwzP/qRAiPAplLlG/vZ37G7NlRh+J8rrE+7jcgF0rGQcXPeMiuQEOXZlaRqeIo+h15aJEwWEw==

Ils sont bien entendu identiques, c'est là tout l'intérêt du hash : à jeu de données identique, hash identique, sinon impossible d'authentifier l'utilisateur.
Vous devez maintenant avoir compris l'intérêt du hash.

Si jamais nous avons plusieurs utilisateurs possédant le même mot de passe, l'attaquant peu le deviner grâce aux hashs : il ne sait pas encore ce qu'est le mot de passe réel, mais sait maintenant que s'il parvient à déterminer le mot de passe correspondant à ce hash, il aura accès à plusieurs comptes.
En se concentrant sur les comptes possédant des hash identiques, il augmente ses chances de réussite car si Jean change son mot de passe entre temps, peut être que Paul ne le fera pas.

Mais il y a pire : il y a de fortes chances que quelqu'un d'autre utilise le même algorithme de hash que nous, au sein de notre SI comme ailleurs.
Si nos utilisateurs ont aussi un compte là bas (ou tout simplement que d'autres utilisateurs ont le même mot de passe) et que l'attaquant à déjà compromis cet autre système, il a déjà accès à plusieurs de nos comptes utilisateur.

Sans aller jusqu'à ce "manque de chance", il y a d'autres menaces : il existe de grosses bases de données (connues sous le nom de "Rainbow tables") contenant des valeurs de hashs calculés à partir de mot de passe potentiels. Elles permettent ainsi de faire rapidement le parallèle entre un hash et le mot de passe correspondant.

Donc, utilisons un salt
Le principe est simple : nous allons tout simplement générer une valeur unique (j'insiste bien : unique, un salt commun à tous les utilisateurs serait bien entendu aussi efficace que pas de salt) que nous ajouterons au mot de passe saisi par l'utilisateur avant d'obtenir le hash.

En prenant les salts suivants (vous n'êtes bien sûr pas obligé de passer par un salt sous forme de chaîne de caractères) :
Jean : "Jpf0ZrIOSX2ZebuI52nfow=="
Paul : "kcbIrxcdNC7pQMCkR+pazQ=="

Pour Jean, nous demandons le hash de "toto#titi!tataJpf0ZrIOSX2ZebuI52nfow==" :
70bQc07fYCDVyduPajGQ5piprIROrBEw7oY8tP/hczwqtYSTJFBi5jsqEywShb7+dhb5xujkn9rejeMWWj0hZQ==
Pour Paul, nous demandons le hash de "toto#titi!tatakcbIrxcdNC7pQMCkR+pazQ==" :
uW/oOqh0R/JPBloWsMASmYAmHwVsZo+VuNRN4FXuJFPwACZ/BHH/wvrrkdDBgLAO+D3HvdnLkDcZ9M5j39WsBg==

Pour un même mot de passe, les 2 hashs sont distincts : nos utilisateurs peuvent maintenant avoir des mots de passe identiques sans que cela soit devinable dans la liste des hash stockés.
Comme nous stockons le salt de manière lisible, nous pouvons renouveler l'opération au moment de la tentative d'authentification de l'utilisateur : si le mot de passe saisi est bon, le hash sera identique à celui stocké.

Nous avons aussi réduit les chances de réussite de l'attaquant lors de l'utilisation d'une Rainbow table : il faudrait démultiplier le volume de la liste de référence pour avoir les combinaisons de mot de passe avec salt, et vu que notre salt est quelque chose totalement aléatoire...

L'utilisation d'un algorithme de hash produisant une quantité de données importante peut aussi être bénéfique dans le sens que ce type de table de correspondance devra stocker une énorme quantité de données, alors que de notre côté un doublement de volumétrie sur les comptes utilisateurs n'est peut être pas très important.
Il en va de même avec le temps nécessaire au calcul du hash (temps naturel : ralentir artificiellement le code de calcul ne sert à rien car l'attaquant n'utilisera pas notre code mais une version optimisée) : si nous utilisons un algorithme gourmand en temps, nous ajouterons un peu de temps sur nos opérations (probablement insignifiant au regard du reste de nos traitements), mais énormément de temps sur celles de l'attaquant en cas de brute force. Au pire, par mesure de prudence, prévoir tout de même une limitation du nombre de tentatives de logon par laps de temps.

 

 

Une fonctionnalité dangereuse : la "phrase secrète"

S'il y a bien une fonctionnalité que je déteste c'est celle là, du moins dans sa forme automatique.
On nous demande de définir une question et la réponse à cette question afin de pouvoir procéder à la récupération de notre mot de passe.

A mes yeux le seul intérêt réel de cette fonctionnalité est du côté de l'attaquant : ça peut lui faire gagner du temps.

Déjà, cette fonctionnalité ne peut fonctionner qu'avec un mode de stockage permettant de récupérer le mot de passe sous sa forme lisible : en clair ou crypté donc, nous pouvons oublier le hash du coup.
Ensuite, on le récupère pour en faire quoi ?
L'envoyer à l'utilisateur par mail ? Voir remarques plus haut.
L'afficher à l'utilisateur au travers d'une connexion sécurisée ? Affiché... à l'écran... et si quelqu'un d'autre regarde dans le dos de l'utilisateur ?
Une chose est sûre : si nous donnons son mot de passe à l'utilisateur, il ne risque pas de la changer après l'avoir récupéré... Et même dans le cas contraire, autant passer quand même par une génération de mot de passe temporaire.

Soyons réalistes : je doute que l'utilisateur lambda pense toujours à spécifier une question et une réponse compliquées.
Quand à l'utilisateur avancé je pense qu'il risque fortement de procéder un peu comme moi quand on m'oblige à spécifier ces éléments (...) : question "Hu ?" et réponse que même moi je serais incapable de donner.
Intéressant comme système, surtout quand certains d'entre eux ne nous laissent même pas la question libre mais nous fournissent à la place une liste de question d'une simplicité plus ou moins consternante du genre :

  • Prénom de la grand mère / du grand père
  • Nom du premier animal de compagnie
  • Prénom du premier enfant
  • ...

Nous partons donc du principe que l'attaquant n'est en aucun cas un proche plus ou moins direct de l'utilisateur ?
Et même sans cela : n'oublions pas qu'à notre époque les réseaux sociaux sur internet sont à la portée de n'importe qui, du coup obtenir des informations sur la vie de l'utilisateur n'est pas bien compliqué si ce dernier n'est pas un minimum prudent et si l'attaquant sais ce qu'il cherche.

Petit bémol :
Si la récupération du mot de passe réel est nécessaire, par exemple pour des raisons de perte de données en cas d'écrasement du mot de passe (cryptage dont la clé serait le mot de passe, ...), il faut alors que la procédure de récupération ne soit pas automatique : nous devons faire intervenir dans le processus un être humain à même de vérifier l'identité du demandeur, et obliger ce dernier à changer de mot de passe après récupération.

 

 

Conclusion

Je pense qu'on peut dire que le stockage en clair est à proscrire totalement.

Le choix de stocker un hash et non une forme lisible (en clair ou cryptée) n'est pas seulement une histoire de limitation des risques de vol d'identité, il y a aussi une notion de respect de l'utilisateur : le mot de passe est quelque chose que vous devez considérer comme faisant partie de la sphère très privée que seul lui doit connaitre (sauf choix volontaire de sa part).

 

Merci à Vincent pour la relecture et les compléments !

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: samedi 4 avril 2009 22:15 par coq
Classé sous : ,

Commentaires

KooKiz a dit :

Toujours bon de faire un rappel, trop de sites encore utilisent des mots de passe stockés en clair.

Et rien ne m'horripile plus que de recevoir mon mot de passe dans le mail de confirmation. Surtout que ça m'oblige à faire un tour dans les éléments supprimés de ma boite GMail pour m'assurer d'en supprimer toute trace... :s

# avril 6, 2009 09:45

coq a dit :

Le pire étant surtout qu'avec un peu de bol il a choisi une publicité contextuelle basée sur le mot de passe en question... :s

# avril 6, 2009 19:45

Renfield a dit :

Clair que le nombre de softs qui font en gros:

SELECT Password FROM Comptes WHERE Login = @login

If @Password = @Rs.Password Then

  ...

End If

quel bétise !

# avril 7, 2009 14:32
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01