Parlons ici des algorithmes de chiffrement (de hashage, mais pas de “cryptage” !) et WordPress.
MD5 au début
Remontons directement aux débuts de WordPress où le chiffrement et la comparaison des mots de passe étaient fait avec du MD5, pour “Message Digest 5”, créé en 1992 pour remplacer MD4 créé en 1990 et vulnérable dès 1991, lui même créé pour remplacer MD2 qui n’a été retiré qu’en 2011 car n’est même pas si vulnérable puisqu’en 2014 il était encore utilisé dans les infrastructures à clés publiques dans le cadre de certificats générés avec MD2 et RSA. Incroyable ça non ?
Voici la fonction user_pass_ok()
de WordPress à ses débuts, asseyez-vous, ça fait peur :

user pass ok
Une comparaison avec un simple double égal, avec du simple MD5. À l’époque, il n’y avait pas de problème de sécurité dans le sens où les ordinateurs n’étaient pas assez puissants et Internet pas aussi rapide pour balancer autant de requêtes pour trouver une collision entre 2 hashes.
Une collision c’est justement quand il arrive que 2 chaînes totalement différentes aient le même hash, on peut même parler de Type Juggling pour aller encore plus loin dans les collisions.
Voyez ici un exemple de Type Juggling démontrant que 2 MD5 différents : https://3v4l.org/bf8Ao
Il sont bel et bien considérés identiques avec ==
, mais pas avec ===
. Le soucis du ==
est que cela ne compare pas le type de données, donc on a bien 0e462097431906509019562988736854
qui vaut la même chose que 0e830400451993494058024219903391
puisque ce sont tous les 2 de minuscules chiffres trèèèès proche de 0, regardez bien, on parle de 0 puissance (symbole “e”) euh puissance un nombre imprononçable, donc zéro des 2 cotés.
MD5 est rapide à chiffrer, très rapide, encore plus de nos jours avec la puissance des ordinateurs, c’est donc un algorithme ultra performant, voilà, vous le voyez venir ? Allez je le dis : un algo de chiffrage de mot de passes ne doit PAS être performant, car il permet alors de Brute Forcer plus rapidement des milliers voire millions de tentatives.
De plus, WordPress n’utilisait même pas de clé de salage (salt), donc une chaine donne toujours le même résultat. L’astuce de faire une boucle de 100 fois le MD5 pour le “mélanger” encore plus est inefficace de nos jours, 1 fois ou 100 fois, c’est aussi rapide : https://3v4l.org/GAYkv
Le saviez-vous : Quand un compte est inséré en base de données, le mot de passe sélectionné pour lui est chiffré avec le sel de vos clés de sécurité, celles qui sont habituellement dans le wp-config.php ou parfois en base de données aussi sauf si vous utilisez SecuPress, dans ce cas elles ne sont plus lisibles humainement car générées via un mu-plugin.
Mais si vous ajoutez un compte directement en base de données, vous ne pouvez PAS savoir comment le chiffrer car il vous manque cette info. C’est là où WordPress est trèèès gentil (jusqu’en 6.8), vous pouvez lui donner le hash MD5 du mot de passe choisi et l’insérer en tant que mot de passe pour ce compte. Lors de sa première connexion, ce mot de passe MD5 de 32 caractères de long sera alors hashé par le core et mis à jour de façon transparente pour ce compte.
Bien ? Je ne pense pas car c’est justement comme cela que font certains malwares qui insèrent des comptes admin dans les sites, un simple hash comme d8578edf8458ce06fbc5bb76a58c5ca4
et hop ce compte peut se connecter. Niveau sécurité on peut dire que ce n’est pas tip top.
C’est pourquoi depuis SecuPress 2.3 ce genre d’insertion est détectée par le plugin et ce compte bloqué, impossible pour lui de faire la moindre action. Mais nous reparlerons dans un autre article de la façon dont WordPress est trop gentil avec les faux comptes…
Puis vient SHA
Celui qui ne miaule pas, ce SHA là est bien plus puissant que le MD5, créé en 2005 il prend une clé de salage en paramètre pour le renforcer, les collisions sont très difficiles à aller chercher, Google a réussi à en trouver en faisant tourner des super-ordinateurs pendant des années, disant à la fois “attention il y en a” et à la fois “mais vu la galère qu’on a eu, ça va encore tenir bon un moment”.
Plusieurs versions de SHA ont été utilisées, depuis SHA-1 jusque SHA-512, cela reste encore très répandu aujourd’hui et toujours robuste, mais rapide.
C’est là où BCRYPT arrive en jeu.
BCRYPT a été créé en 1999, basé sur Blowfish (chiffrement par blocs) pour l’améliorer en Eksblowfish (EKS pour Expensive Key Schedule). Vous devriez déjà avoir compris si vous avez lu le début de cet article. Le but est justement que le chiffrement soit couteux et donc lent. Notre but avec BCRYPT étant de protéger mieux, il faut donc que l’algo soit moins performant car ici on joue avec des mots de passe.
MD5 versus SHA versus BCRYPT
Il sont donc tous les 3 des algorithmes de chiffrement mais ont un usage bien différent.
Là où MD5 est très bon pour chiffrer des clés, des IDs, des IP, créer des valeurs de token rapidement, bref, là où la sécurité et les données sensibles sont absents, mais il n’est pas recommandé pour générer des mots de passe ou “transformer” des données sensibles (coucou gravatar).
SHA est aussi bon dans le chiffrement, sans collisions simples, salage possible, mais en solo ne sert pas à chiffrer des mots de passe. SHA-256 est à utiliser et non SHA-1 bien entendu.
BCRYPT est fait pour ça, cet algo génère même ses propres clés de salage et peut via un paramètre ralentir son execution afin d’être de moins en moins performant. Tout ça en étant resistant contre les attaques par tables arc-en-ciel (Rainbow Tables) et donc le Brute Force.
Il n’est plus recommandé d’utiliser MD5 car trop performant, BCRYPT incluant désormais un “facteur de coût”, prenons un exemple : https://3v4l.org/0b6V8
On a ici 0.05 secondes pour chiffrer un mot de passe (peu importe la longueur de cette chaîne) contre le minuscule 0,00000596 en MD5 de tout à l’heure. On est donc déjà de l’ordre de 400 fois plus lent avec le facteur de coût (cost) par défaut qui est de 10 (12 depuis PHP 8.4). Cela signifie que BCRYPT va faire 2^10 itérations de chiffrement soit 1024 fois. MD5 serait encore à 0,00596 si on le faisait 1000 fois…
De plus, je rappelle que BCRYPT a sa propre clé de salage, le résultat est donc différent à chaque fois ! Voilà pourquoi l’interface de 3v4l vous montre le résultat selon la version de PHP, car chaque itération est différente. Ce qui est donc plus sécurisé et plus lent.
Avec d’autres exemples d’autres coût de facteur, 11 (2028 itérations), 12 (4096), 15 (32768) qui est le maximum il est simple de deviner ce qui va se passer, puisque le coût est un facteur de 2, les temps sont doublés à chaque fois qu’on ajoute 1 au facteur. On aura donc environ 0.1 pour 11, 0.2 pour 12, 0,4 pour 13, 0,8 pour 14 et 1,7 seconde pour générer UN SEUL HASH BCRYPT pour un coût de 15.
Je vous laisse calculer le temps qu’il faut faire 1 million de tentative en Brute Force ? Allez je vous le donne 5,96 secondes en MD5, et presque 20 jours avec BCRYPT (si on est en local sinon ajoutez la latence de la connexion Internet entre vous et le site/la base de données si aucun des 2 n’a de protection !).
L’article pourrait s’arrêter là, je viens de démontrer que réaliser du Brute Force sur BCRYPT est trèèèès compliqué tant que nos ordinateurs n’ont pas de processeurs quantiques, là, ça deviendra de nouveau facile.
Oui mais…
Ha, il y a un mais. Mais si c’est plus lent, est-ce un soucis ? Cela ne devrait pas nous déranger de passer 1,7 seconde de plus lors de notre connexion à un site/service car nous ne le faisons que très peu de fois dans la journée, et que pour des raisons de sécurité, nous le ferions. D’ailleurs avec les captchas, les OTP, le smartphone etc, nous passons déjà plus de 2 secondes à nous connecter non ?
Ok mais la différence est ailleurs, quand on s’est connecté une fois sur un site WordPress, on a un cookie qui va contenir un hash qui sera comparé lors de notre prochaine visite.
Mais une visite ça signifie ouvrir plusieurs threads PHP, chacun validant la connexion (si il n’y en a pas, 0 sec) ce qui peut vite grimper. Une requête AJAX en mode connecté ? Lente. Une requête à la REST API ? Lente. etc
Avec un algorithme rapide comme MD5 ou SHA, ça va tellement vite qu’on oublie même que le cookie et comparé à chaque fois, plusieurs fois par page.
Mais avec un BCRYPT à 1,7 seconde (paramètre par défaut) pour chaque comparaison, le temps de chargement d’une page peut grimper.
Il faut donc déjà savoir quel coût on veut entre 4 et 15, sachant que 10 est le défaut et n’est déjà plus recommandé, twelve is the new ten.
On peut utiliser ce snipper sur notre serveur pour décider de la valeur de ce facteur, voici le code, n’oubliez pas, il faut le lancer sur SON site pour avoir la valeur de SON serveur : https://3v4l.org/6CeZO vous comprenez maintenant que toutes les valeurs que j’ai citées dans cet article ne dépendent donc que du site 3v4l et peuvent varier chez vous, chez votre hébergeur.
Le code fourni indique un coût de 350ms acceptable, vous pouvez augmenter ou réduire selon votre politique de sécurité mis en place.
Dernier point, il a été créé en 1999 alors que PBKDF2 a été créé en 2017, pourquoi on utilise pas ce dernier !? Car trop performant de nouveau… BCRYPT a justement fait ses preuves depuis 1999 et résiste très bien à plus de 25 ans d’attaques, c’est bon bel et bien un bon choix encore de nos jours.
Pour information la valeur par défaut du coût est de 10, il n’est pas recommandé de baisser en dessous pour des raisons évidentes de sécurité, pour augmenter cette valeur dans WP 6.8 il faudra alors utiliser ce filtre :
$options = apply_filters( 'wp_hash_password_options', array(), $algorithm );
Et passer le paramètre cost
ayant pour valeur un entier compris entre 10 et 15 (en vérité, 4 et 31 mais ne soyez ni fou ni folle).
Oui mais encore…
Autre soucis qui existe déjà dans le monde de WordPress mais on a rien dit. Il s’agit des auteurs et autrices de plugins qui ont besoin de générer des hash et utilisent alors wp_hash_password au lieu de wp_hash. Jusqu’à ce jour tout était rapide, désormais cela peut ajouter une lenteur, et selon le nombre de boucles, il suffit de 20 itérations (création, vérification) pour perdre 1 seconde de load par page…
Il va falloir y penser quand votre site sera plus lent en 6.8, il va falloir rééduquer les devs !
Intégration à WordPress
Pourtant, BCRYPT va être intégré à WordPress 6.8 suite à ce ticket datant du 20 juin 2012 et ces commits du 17 février 2025 : https://core.trac.wordpress.org/ticket/21022 & https://core.trac.wordpress.org/changeset/59828
Résumé de la situation rapidement : soucis de rétrocompatibilité avec les anciennes versions de PHP toujours utilisées, soucis avec les applications passwords, souci avec la rest api, débat pour savoir si vraiment BCRYPT c’est mieux que X ou Y autre algo.
Enfin l’idée serait plutôt d’utiliser plusieurs algo de chiffrement selon le contexte, ce qui est bien plus logique. Voyez ce pull: https://github.com/johnbillion/wordpress-develop/pull/7.
Il est donc très probable de voir arriver BCRYPT dans WordPress 6.8, tout comme il est possible que ça soit repoussé à une prochaine version dans l’attente de ne plus supporter les versions de PHP qui ne supportent pas BCRYPT totalement, ou si le choix des algos n’est pas encore arrêté.
Cet article sera mis à jour quand tout cela sera posé. Mais en attendant, vous en savez un peu plus sur BCRYPT et le chiffrement des mots de passe dans WordPress !