Journal Scorepw, un évaluateur de mots de passe

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes : aucune
34
3
jan.
2018

Sommaire

Un petit journal promotionnel pour annoncer mon dernier projet libre (qui ne devait initialement être qu’un petit de bout de code jamais supposé sortir de chez moi…) : scorepw, un outil permettant d’évaluer la « qualité » d’un mot de passe.

Pour ceux que la théorie intéresse, je les déçois immédiatement : il n’y a rien de novateur dans scorepw — pas de nouvelle méthode d’évaluation révolutionnaire à laquelle personne n’aurait encore jamais pensé. Au contraire, scorepw n’est qu’un peu d’enrobage autour de bibliothèques d’évaluation de mots de passe déjà existantes et bien connues.

J’invite donc ceux que la théorie derrière l’évaluation de mots de passe intéresse à se tourner vers les bibliothèques en question :

Les deux dernières sont deux implémentations différentes, respectivement en C et en C++ comme leur nom l’indique, de Zxcvbn, une bibliothèque CoffeeScript notamment utilisée pour propulser l’évaluateur de mots de passe de Dropbox et présentée lors du 25eme USENIX Security Symposium en 2016. Cette bibliothèque a été ré-implémentée en de nombreux langages depuis, la page Github précédente donne la liste des implémentations disponibles.

Cela étant dit, qu’est-ce donc que scorepw ? Fondamentalement, c’est juste une interface en ligne de commande pour les bibliothèques ci-dessus.

J’ai commis scorepw pour essentiellement deux raisons :

  • il n’y avait à ma connaissance pas d’outil permettant l’utilisation de l’algorithme de Zxcvbn directement depuis la ligne de commande (il y a bien des outils en ligne tout court, mais pas en ligne de commande) ;
  • il y a bien un outil pwscore permettant d’appeler libpwquality depuis la ligne de commande, mais il ne donne rien de plus qu’un score de 0 à 100 sans plus de détails (alors que Zxcvbn fournit une estimation du temps requis pour craquer le mot de passe, ce que je trouve assez cool) ;
  • c’était la fin des vacances et je m’ennuyais.

La principale caractéristique, et à mon sens le principal intérêt, de scorepw est donc qu’il permet d’évaluer un mot de passe donné en utilisant plusieurs bibliothèques d’évaluation (ci-après appelées des estimateurs), permettant d’avoir plusieurs points de vue sur la qualité du mot de passe (contrairement à pwscore qui ne donne que l’évaluation de libpwquality).

Pour l’instant, scorepw utilise comme estimateurs les trois bibliothèques citées plus haut. J’ajouterai éventuellement d’autres bibliothèques du même genre à mesure que je les trouve.

Utilisation

Scorepw prend le mot de passe à analyser en tant que seul argument positionnel sur la ligne de commande, ou le lit depuis son entrée standard en l’absence d’un tel argument. Par défaut, il utilise un seul estimateur (Zxcvbn-C) et sort simplement le score, de 0 à 100, donné par cet estimateur :

$ scorepw correcthorsebatterystaple
100

L’option -e permet de spécifier le ou les estimateurs à utiliser (ici Zxcvbn-CPP et libpwquality):

$ scorepw -e zxcvbncpp,pwquality correcthorsebatterystaple
Zxcvbn-CPP: 100
Pwquality: 100

L’option -a (--all) est un raccourci pour -e zxcvbn,zxcvbncpp,pwquality, c’est-à-dire que tous les estimateurs disponibles sont sollicités :

$ scorepw -a 'tr0ub4dour&3'
Zxcvbn: 75
Zxcvbn-CPP: 50
Pwquality: 87

On voit ici l’intérêt qu’il peut y avoir à ne pas se contenter d’un seul estimateur : le mot de passe est presque parfait pour Pwquality alors qu’il est « bof-bof » pour Zxcvbn-CPP…

Même Zxcvbn-C et Zxcvbn-CPP, qui sont en principe deux implémentations différentes du même algorithme au départ, donnent des résultats parfois très divergents. D’après mes tests, Zxcvbn-CPP donne régulièrement des résultats plus proches de ceux obtenus avec la Zxcvbn originale (celle en CoffeeScript). D’ailleurs, le développeur de Zxcvbn-C ne cache pas qu’il a fait des choix différents et que son implémentation se comporte différemment.

Enfin, l’option -f permet d’obtenir plus de détails sur le mot de passe analysé (avec les estimateurs qui le supportent, c’est-à-dire pas Pwquality) :

$ scorepw -af 'tr0ub4dour&3'
Estimator: Zxcvbn
Score: 75
Entropy: 28.951
Guesses: 5.18873e+08
Attack times:
  Online throttled attack (100/h) ...........: centuries
  Online unthrottled attack (10/s) ..........: one year
  Offline attack with slow hashing (10k/s) ..: 14 hours
  Offline attack with fast hashing (10G/s) ..: less than one second

Estimator: Zxcvbn-CPP
Score: 50
Entropy: 23.185
Guesses: 9.534e+06
Attack times:
  Online throttled attack (100/h) ...........: 10 years
  Online unthrottled attack (10/s) ..........: 11 days
  Offline attack with slow hashing (10k/s) ..: 15 minutes
  Offline attack with fast hashing (10G/s) ..: less than one second

Estimator: Pwquality
Score: 87

Problèmes connus

De l’importance du dictionnaire

Les trois bibliothèques utilisées vérifient toutes la présence du mot de passe dans un dictionnaire (y compris sous une forme modifiée). Dans l’exemple ci-dessus, 'tr0ub4dour&3' se voit attribuer un score de seulement 50 par Zxcvbn-CPP, parce que la bibliothèque a correctement reconnu (après « dé-leetification ») le mot troubadour. Mais 'tr0ub4dor&3', pourtant plus court d’un caractère, est considéré comme bien meilleur, cette orthographe n’étant pas dans le dictionnaire :

$ scorepw -fe zxcvbncpp 'tr0ub4dor&3'
Score: 100
Entropy: 36.541
Guesses: 1e+11
Attack times:
  Online throttled attack (100/h) ...........: centuries
  Online unthrottled attack (10/s) ..........: centuries
  Offline attack with slow hashing (10k/s) ..: 3 months
  Offline attack with fast hashing (10G/s) ..: 10 seconds

Le choix et le contenu du dictionnaire n’est donc pas anodin.

Zxcvbn-C et Zxcvbn-CPP utilisent un dictionnaire constitué des mots extraits de la Wikipédia anglophone, d’une compilation de prénoms usuels, d’une compilation (réalisée par les contributeurs de Wiktionary des mots les plus usités dans les scripts des films et séries TV américaines, et d’une compilation de mots de passe réels publiée par Mark Burnett (le chercheur en sécurité, pas le producteur TV).

Pwquality, de son côté, utilise le dictionnaire fourni par la bibliothèque cracklib. Ce dictionnaire est par défaut assez modeste (pour des raisons de licence), mais un dictionnaire plus conséquent peut être choisi lors de la compilation de la bibliothèque.

Pour l’instant, scorepw ne permet pas d’utiliser autre chose que les dictionnaires ci-dessus, qui sont directement inclus dans les bibliothèques. Une des premières pistes d’amélioration du programme serait de permettre à l’utilisateur de spécifier le ou les dictionnaires de son choix.

Mots de passe non-ASCII

La présence de caractères non-ASCII dans le mot de passe provoque parfois des résultats qui laissent pour le moins à désirer.

Signalons déjà un gros bug dans Zxcvbn-CPP, qui se retrouve tout simplement bloqué dans ce qui semble être une boucle infinie dès qu’on lui demande d’analyser un mot de passe non-ASCII ! Chose amusante, le bug ne se produit que si la bibliothèque est compilé en mode debug, la fonction fautive n’étant appelée que dans un assert. Je vais essayer d’isoler plus précisément le bug avant de le remonter au développeur de Zxcvbn-CPP.

Zxcvbn-C n’a pas ce problème, mais en revanche la présence d’un seul caractère non-ASCII suffit à lui faire croire que le mot de passe est très robuste :

$ scorepw -f -e zxcvbn aeiouy
Score: 25
Entropy: 14.208
Guesses: 18928
Attack times:
  Online throttled attack (100/h) ...........: 7 days
  Online unthrottled attack (10/s) ..........: 31 minutes
  Offline attack with slow hashing (10k/s) ..: one second
  Offline attack with fast hashing (10G/s) ..: less than one second

$ scorepw -f -e zxcvbn aéiouy
Score: 100
Entropy: 42.386
Guesses: 5.74881e+12
Attack times:
  Online throttled attack (100/h) ...........: centuries
  Online unthrottled attack (10/s) ..........: centuries
  Offline attack with slow hashing (10k/s) ..: 18 years
  Offline attack with fast hashing (10G/s) ..: 9 minutes

Show me the code

Voilà, si vous êtes intéressés :

  • # Correct horse battery staple

    Posté par  (site web personnel) . Évalué à 6.

    Comme mot de passe, je sais que le correct horse battery staple est un exemple de bon mot de passe (avant qu'il soit publié). Maintenant, je me demande ce qu'il en est pour quelque chose de bien plus court mais finalement très similaire : ✔️🐎🔋📌

    • [^] # Re: Correct horse battery staple

      Posté par  (Mastodon) . Évalué à 2.

      Je profite qu'on ressorte cette référence pour demander : c'est quoi le nb de bits d'entropie dont il parle ? J'ai compris ça revient au nombre de possibilités (228 à 1000/s, on tombe bien sur 3j), mais je ne comprends pas comment il arrive à 28 bits avec son exemple.

      1 bit pour l'éventuelle majuscule, oui je vois. Mais 16 bits pour les 9 lettres, j'ai plus de mal à comprendre…

      En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

      • [^] # Re: Correct horse battery staple

        Posté par  (site web personnel) . Évalué à 4.

        Mais 16 bits pour les 9 lettres, j'ai plus de mal à comprendre…

        Il s’agit de 16 bits pour un mot (ici troubadour) choisi dans une liste comprenant entre autres des mots peu communs (« uncommon (non-gibberish) base word »), contrairement au cas du correcthorsebatterystaple qui ne comprend que des mots choisis dans une liste de mots plus courants (une liste forcément moins longue qu’une liste comprenant des mots courants et des mots moins courants).

        Par exemple, le dictionnaire dont je parlais dans le journal constitué à partir des mots de la Wikipédia anglophone comprend exactement 100 000 mots, donc le choix d’un mot dans cette liste apporte ~16.6 bits d’entropie, soit à peu près ce qu’a retenu Randall.

        • [^] # Re: Correct horse battery staple

          Posté par  (Mastodon) . Évalué à 3.

          Ah mais oui, c'est pour des mots du dico, et pas des lettres aléatoires. Merci :)

          En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

        • [^] # Re: Correct horse battery staple

          Posté par  . Évalué à 2.

          Si je comprends tout à fait le calcul, je me pose tout de même une question.

          Quand on se sert de cette valeur pour définir la force d'un mot de passe, on parle de la résistance au brute force : il faut trouver une combinaison parmi 2 puissance l'entropie. Mais est-ce que l'attaquant va tenter de brute forcer par dictionnaire ?

          Si l'attaquant fait l'hypothèse que tu tire des mots du dictionnaire anglais, il a bien 216 combinaisons à tester. Mais comment peut-il s'assurer de cette hypothèse ? J'imagine bien plus des attaquants lancer une attaque sur les caractères (quelle portion d'unicode ?) et sur des dictionnaires anglais + ta langue. Ça donne un nombre de combinaison à tester (et donc une puissance de calcul à consommer) largement supérieure.

          D'ailleurs si tu prends l'habitude de choisir 3 à 5 mots et que tu intercale quelques caractères quelque part entre 2 mots, tu augmente encore l'entropie.

          Bref est-ce que ce ne serait pas une estimation faible de l'entropie ?

          • [^] # Re: Correct horse battery staple

            Posté par  (site web personnel) . Évalué à 5.

            Bref est-ce que ce ne serait pas une estimation faible de l'entropie ?

            Si. En négligeant l’entropie structurelle ou de configuration (l’entropie provenant de la manière dont le mot de passe est construit : est-ce que c’est un mot choisi dans le dictionnaire ? Deux mots choisis dans le dictionnaire ? Un mot du dictionnaire suivi de deux chiffres ? Un mot du dictionnaire renversé suivi d’une date suivi d’un motif de six lettres sur un clavier QWERTY ? etc.), on sous-estime nécessairement l’entropie totale du mot de passe.

            Je cite Daniel Wheeler (principal auteur de la Zxcvbn originelle) à ce sujet :

            I’m OK [with disregarding configuration entropy] for tree reasons:

            • It’s difficult to formulate a sound model for structural entropy; statistically, I don’t happen to know what structures people choose most, so I’d rather do the safe thing and underestimate.

            • For a complex structure, the sum of the pieces alone is often sufficient to give an “excellent” rating. For exemple, even knowing the word-word-word-word structure of correcthorsebatterystaple, an attacker would need to spend centuries cracking it.

            • Most people don’t have complex password structures. Disregarding structure only underestimates by a few bits in the common case.

          • [^] # Re: Correct horse battery staple

            Posté par  . Évalué à 1.

            Si l'attaquant fait l'hypothèse que tu tire des mots du dictionnaire anglais, il a bien 216 combinaisons à tester. Mais comment peut-il s'assurer de cette hypothèse ?

            En sécurité on se place dans le pire des cas.
            Le pire des cas est : l'attaquant sait comment est construit le mot de passe.

            En fait le vrai pire des cas est : l'attaquant connaît le mot de passe. Là forcément on se fiche pas mal de l'entropie :-)

      • [^] # Re: Correct horse battery staple

        Posté par  (site web personnel) . Évalué à 5.

        Peut être que la page de ExplainXKCD peut répondre à ta question :)

    • [^] # Re: Correct horse battery staple

      Posté par  (site web personnel) . Évalué à 6.

      Maintenant, je me demande ce qu'il en est pour quelque chose de bien plus court mais finalement très similaire : ✔️🐎🔋📌

      Alors, je te déteste (cordialement, hein), parce que tu mets précisément le doigt sur une situation où scorepw ne va servir à rien…

      Comme je le mentionne en fin de journal, scorepw (ou plus exactement, les bibliothèques dont il dépend, notamment Zxcvbn-C) fait plus ou moins n’importe quoi en présence de caractères non-ASCII. C’est valable pour les caractères accentués, c’est a fortiori valable pour des caractères de ce genre.

      $ scorepw -af ✔️🐎🔋📌
      Estimator: Zxcvbn
      Score: 100
      Entropy: 119.589
      Guesses: 1e+36
      Attack times:
        Online throttled attack (100/h) ...........: centuries
        Online unthrottled attack (10/s) ..........: centuries
        Offline attack with slow hashing (10k/s) ..: centuries
        Offline attack with fast hashing (10G/s) ..: centuries
      
      Estimator: Zxcvbn-CPP
      Score: 100
      Entropy: 59.795
      Guesses: 1e+18
      Attack times:
        Online throttled attack (100/h) ...........: centuries
        Online unthrottled attack (10/s) ..........: centuries
        Offline attack with slow hashing (10k/s) ..: centuries
        Offline attack with fast hashing (10G/s) ..: 3 years
      
      Estimator: Pwquality
      Score: 100

      À mon avis, tous ces résultats surestiment largement le « mot » que tu donnes.

      C’est particulièrement vrai pour Zxcvbn-C, qui ne connaissant pas UTF-8 traite en fait ✔️🐎🔋📌 comme un mot de 18 caractères dont les valeurs s’étalent sur toute la plage de 0 à 255 (d’où une estimation d’entropie qui crève le plafond mais à laquelle je ne me fierai pas).

      Zxcvbn-CPP s’en sort mieux en considérant correctement 4 caractères Unicode au lieu de 18 octets, mais même comme ça l’entropie estimée me semble trop haute.

      En général, quand on estime l’entropie d’un mot de passe, on part du principe que la « structure » du mot de passe (comment il est formé) est connue de l’attaquant. Par exemple, quand Randall estime que correcthorsebatterystaple a environ 44 bits d’entropie, c’est en supposant que l’attaquant sait que le mot de passe est formé de quatre mots courants choisis au hasard.

      Une estimation correcte de ✔️🐎🔋📌 qui suit le même principe devrait à mon avis assumer que l’attaquant sait que le mot de passe est formé non pas de quatre caractères Unicode arbitraires (choisis dans la totalité d’Unicode), mais de quatre « symboles » provenant d’une plage restreinte d’Unicode (par exemple la plage des « Mscellaneous SYmbols », de U+1F300 à U+1F5FF).

      C’est peut-être d’ailleurs ce que fait l’implémentation CoffeeScript de Zxcvbn, parce qu’elle considère ce mot de passe très moyen (à juste titre selon moi).

      • [^] # Saisie

        Posté par  (site web personnel) . Évalué à 4.

        À part si tu utilises un outil dédié pour stocker tes mots de passe et les copier/coller, tu fais comment pour saisir ✔️🐎🔋📌 au clavier (ou pire sur un téléphone) ?

        Python 3 - Apprendre à programmer dans l'écosystème Python → https://www.dunod.com/EAN/9782100809141

        • [^] # Re: Saisie

          Posté par  (site web personnel) . Évalué à 2.

          C’est plutôt à Xinfe qu’il faut poser la question, mais pour ma part et en supposant que je suis sur ma machine :

          • si je voulais seulement accéder à un petit nombre de caractères de ce genre : les rendre accessible via la touche Compose ;
          • si je voulais accéder à la plage Unicode complète : utiliser SCIM.

          Sur un téléphone, aucune idée.

        • [^] # Re: Saisie

          Posté par  . Évalué à 5.

          ou pire sur un téléphone

          Sur un téléphone, c'est encore plus facile. Tu tappe cheval et le clavier te propose l'emoji associé.

          « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

          • [^] # Re: Saisie

            Posté par  . Évalué à 5.

            La gueule des SMS entre un sexologue et son client…

      • [^] # Re: Correct horse battery staple

        Posté par  . Évalué à 1.

        Vu que l'implémentation en CoffeeScript est différente, est-il possible de s'en servir va scorepw ?
        Je sais que c'est pas évident… Foutre du JS dans un programme C, quel dommage ;)

        Mais ça va finir par arriver si d'autres bibliothèques d'évaluation de la qualité des mots de passe arrivent.

        • [^] # Re: Correct horse battery staple

          Posté par  (site web personnel) . Évalué à 2.

          Embarquer un moteur JS dans scorepw pour pouvoir utiliser l’implémentation originale ?

          Euh, on va dire que ce n’est pas au programme pour l’instant. Après si quelqu’un est motivé, j’accepte les patchs !

      • [^] # Re: Correct horse battery staple

        Posté par  . Évalué à 2.

        quatre « symboles » provenant d’une plage restreinte d’Unicode

        Tu peux pousser le raisonnement aussi loin que tu veux, ça ne peut pas marcher à l'infini. Par exemple, dans "agFtdP", quel est la plage raisonnable? 6 caractères minuscules ou majuscules? 4 minuscules et 2 majuscules? Deux majuscules en position 3 et 6? 6 lettres entre A et T? 6 lettres à choisir dans l'ensemble {adFgPt}? Évidemment, c'est plus dur d'estimer le caractère de "surprise" d'un mot de pase inhabituel (est-ce que les attaques par dictionnaire essayent des trucs comme XxXxXx?)

  • # Mais pourquoi scorepw ?

    Posté par  . Évalué à 2.

    Félicitations pour le travail que tu as accompli.

    Par contre, mais pourquoi avoir choisi le nom "scorepw" ?

    La commande déjà existante pwscore suit la même convention que pwquality. Avoir choisi pwscore ajoute de la confusion, comme pour les commandes useradd et adduser.

    Il me semble qu'il y a bien d'autres alternatives pertinentes:
    - password-score
    - password-score-cli (le -cli étant pertinent étant donné que tu l'as créé exprès pour être un outil en ligne de commande)
    - password-check
    - password-checker
    - password-quality-checker
    - pwck (même convention que fsck)
    - universal-password-score
    - password-strength-meter (terme utilisé sur la page de ton projet)
    - …

    Et il me semble qu'un utilitaire dont le retour soit user-friendly devrait avoir un nom explicite, non abbrégé, sans ambiguïté avec d'autres commandes, et respectant le plus de conventions possible…

    • [^] # Re: Mais pourquoi scorepw ?

      Posté par  (site web personnel) . Évalué à 6.

      Je ne prétends pas que le nom retenu soit le meilleur, mais il n’est pas possible de contenter tout le monde.

      Par exemple, si j’avais choisi un des noms que tu proposes, on m’aurait peut-être fait la même remarque que la dernière fois que j’ai présenté un outil dont le nom comportait un tiret (à savoir, ce n’est pas pratique, c’est à éviter).

      Du coup je ferais la même réponse que la dernière fois : si c’est vraiment important, change le nom du binaire pour ce que tu veux avec l’option --program-transform-name lors de la configuration.

      Pour ce qui est du nom du projet lui-même (pas le binaire), j’ai pris scorepw pour la simple raison qu’une recherche Google ne rapportait aucun autre projet similairement nommé (contrairement à des alternatives comme « password checker » ou assimilés).

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.