web-dev-qa-db-fra.com

Est-il sûr de stocker le mot de passe dans HTML5 sessionStorage?

J'essaie d'améliorer l'expérience utilisateur lors de l'inscription en n'obligeant pas l'utilisateur à retaper son mot de passe si la validation sur d'autres champs échoue. Il existe plusieurs façons de l'implémenter, par exemple en utilisant un cookie de session et en stockant un hachage du mot de passe côté serveur. J'explore cette alternative de stockage temporaire du mot de passe utilisateur côté client sans que le serveur en garde la trace. Cette méthode est-elle réalisable? Quels sont les risques encourus?

16

En principe, les valeurs stockées dans sessionStorage sont limitées au même schéma + nom d'hôte + port unique, et si le navigateur a une sortie propre, ces valeurs doivent être supprimées à la fin de la session. Cependant, selon cet article il peut survivre à un redémarrage du navigateur si l'utilisateur choisit de "restaurer la session" après un crash (ce qui signifie que ses valeurs existent également dans la mémoire persistante jusqu'à ce qu'elles soient effacées, alors gardez cela à l'esprit). S'il est bien implémenté, je dirais qu'il est suffisamment sûr - en particulier par rapport à votre alternative d'utiliser un cookie (qui présente de nombreux pièges que je ne considérerais même pas). La spécification W3C indique également que le stockage Web peut en effet être utilisé pour stocker des données sensibles (bien qu'il ne soit pas clair si cette pratique est approuvée ou non).

Quant aux risques, c'est simplement une question de compromis: vous rendez votre site un peu plus pratique pour vos utilisateurs, tout en augmentant un peu la fenêtre d'opportunité pour la saisie du mot de passe (soit au moyen d'une vulnérabilité XSS, par la valeur qui persiste dans un stockage persistant plus longtemps que prévu, ou par l'utilisateur laissant l'ordinateur sans surveillance avant de terminer l'enregistrement). Idéalement, les mots de passe ne devraient jamais quitter la RAM, mais ce n'est généralement pas pratique à faire, donc un compromis est nécessaire. Je conseillerais simplement d'effacer le mot de passe de sessionStorage dès que l'enregistrement réussit, et de garder un œil sur les vulnérabilités sur les implémentations de sessionStorage qui pourraient éventuellement apparaître.

14
mgibsonbr

Je suggère une autre approche: au lieu de soumettre le formulaire au serveur, utilisez un XMLHttpRequest pour créer le compte. Si la validation côté serveur échoue, le formulaire et tout son contenu sont toujours disponibles. S'il a réussi, redirigez vers la page cible.

Cela nécessite que JavaScript soit activé, mais vous pouvez toujours revenir à la soumission de formulaire normale. L'accès à SessionStorage nécessite également JavaScript de toute façon.

8

Vous aurez du mal à décider laquelle des deux valeurs stockées utiliser comme mot de passe prévu par l'utilisateur (celui du stockage local ou celui du champ de saisie), si aucune d'entre elles n'est vide mais diffère pour une raison quelconque.

Cela peut potentiellement fournir un vecteur d'attaque d'ingénierie sociale, où l'attaquant prépare un piège en ouvrant le formulaire d'inscription, en remplissant le stockage local/de session soit en utilisant votre propre code, puis en supprimant toute trace de celui-ci (notifications d'erreur d'entrée) avec un DOM éditeur, ou entrer le mot de passe souhaité directement dans le stockage local/de session (les deux sont pris en charge sur certains navigateurs et extrêmement faciles à faire), puis demander plus tard à la victime de s'inscrire sur votre site Web et, bien, de l'utiliser. Étant donné que votre code peut être facilement inspecté/testé pour voir comment vous gérez de tels cas, l'attaquant pourrait le faire légèrement différemment de ce que j'ai décrit (même les injections de script directement dans le stockage local/de session ne sont pas hors de question, si vous traitez plus tard cette valeur localement sur le formulaire POST), mais au même effet.

La victime ne soupçonnera rien tant qu'elle ne se déconnectera pas et n'essayera pas de se reconnecter. Selon la persistance de la session utilisateur, ce processus de déconnexion et de reconnexion peut ne pas être nécessaire et la victime ne l'aurait pas remarquée. le mot de passe n'était pas celui qu'elle avait entré dans le champ du mot de passe, mais le mot de passe de l'attaquant de son choix a été utilisé pour créer son nouveau compte.

Inutile de dire que l'attaquant vient d'accéder au compte nouvellement créé de la victime et à toutes les données saisies par la victime, même si la victime était prudente et s'assurait qu'il n'y avait pas de surf sur l'épaule.

Donc, le point à retenir ici est que vous devrez potentiellement traiter avec deux emplacements différents des mêmes données d'enregistrement du système, qui pourraient, pour une raison quelconque, différer, et décider lequel utiliser d'une manière sûre pour votre système, ainsi que l'utilisateur final qui s'inscrit. Cela pourrait s'avérer assez difficile à faire correctement, donc je le déconseille.

Au lieu de cela, assurez-vous plutôt que votre formulaire d'inscription est servi via HTTPS, puis remplissez simplement le champ du mot de passe, comme il a été entré pour la dernière fois sur la demande de l'utilisateur POST et s'il satisfait à vos contraintes, même si certains des autres champs de saisie sont mal remplis et le formulaire doit être republié.

6
TildalWave

J'utiliserais une communication inter-onglets pour distribuer le mot de passe au lieu de le stocker dans un stockage persistant (cookie, stockage local, etc. il existe d'innombrables solutions, vérifiez evercookie). De cette façon, le mot de passe restera dans le navigateur jusqu'à ce que vous fermiez le dernier onglet du domaine réel.

Vous pouvez effectuer une communication intertab en toute sécurité avec BroadcastChannel ou SharedWorker ou postMessage probablement là sont d'autres méthodes que je ne connais pas, elles réinventent toujours la roue. Les deux premiers envoient les messages à chaque onglet, le dernier envoie uniquement aux onglets ouverts à partir du même onglet parent, il est donc quelque peu restrictif, mais pris en charge par plus de navigateurs.

Si vous stockez vos mots de passe dans la mémoire js, vous devez empêcher XSS avec en-têtes spéciaux . Et ofc. vous devez vérifier le contenu affiché pour les balises HTML et vous devez toujours coder JSON les données que vous souhaitez injecter directement dans javascript en tant que variable.

Le message de TildalWave est intéressant, je pense que ces méthodes ne sont pas vulnérables à cela, car la synchronisation est presque instantanée et vous pouvez également synchroniser la connexion, la déconnexion, etc.

Si vous décidez quand même d'utiliser localstorage, il est préférable d'utiliser un ID utilisateur signé, un délai d'expiration et un sel au lieu du mot de passe lui-même. Vous pouvez envoyer les informations d'identification au serveur, qui peut les vérifier, et renvoyer les données avec la signature. Ils peuvent être stockés dans un cookie ou tout autre stockage persistant que vous souhaitez. Ces jetons sont parfois utilisés par les API REST s'il existe un client de navigateur, car cette solution est sans état et donne toujours l'impression d'avoir une session classique. Parfois, ils signent chaque demande, pas seulement l'utilisateur id pour améliorer la sécurité.

0
inf3rno