Comment importer des passwords hachés d’une base SQL vers un LDAP
Comment convertir des hashs MD5-SQL vers des MD5-LDAP, et vice-versa ?
Cette problématique est régulièrement rencontrée dès lors qu’une entreprise ou qu’un client s’engage dans un process IAM. L’idée est de mettre en place un référentiel unique, type LDAP/AD, comprenant de manière centralisée tous les comptes utilisateurs (internes / externes / prestataires) afin de les gérer à un seul et unique endroit.
Les avantages de cette gestion centralisée sont multiples :
- Facilité des workflow et process pour les départs, les arrivées, les mutations
- Application d’une politique de mot de passe centralisée
- Centralisation des crédentiels
- Intégration plus simple d’une solution d’IAM, de SSO, d’authentification-forte, de fédération, etc.
- Facilité des revues de comptes, de la gestion des comptes à privilèges, d’analyse et SoD.
Seulement, pour disposer d’un référentiel autoritaire et centralisé renfermant tous les comptes utilisateurs, il faut rapatrier et consolider ces informations en provenance de multiples référentiels.
Il n’est pas rare d’observer une entreprise-cliente qui démarre un projet IAM de zéro, et possède une multitude d’annuaires LDAP de technologies différentes (OpenLDAP, 398DS, SunDS, OpenDS, ADAM/ADLDS, ActiveDirectory, etc.). En parallèle, de nombreuses applications utilisées par les employés de cette même entreprise (internes, externes, prestataires) utilisent des bases de données SQL type MySQL, OracleDB, SQL Server, etc.
Une des tâches en amont d’un projet IAM est donc de consolider ces objets, ces identités, ces comptes, ces groupes, ces droits dans un référentiel LDAP unique.
Ce qui nous amène à nous poser la question de la synchronisation et de l’import des mots de passe, toujours problématique.
Les mots de passe sont très rarement “en clair” dans les annuaires ou les bases de données. Malheur à ceux les conservant sans les hacher : c’est une très mauvaise pratique. Un password est généralement haché avant d’être stocké. Le hachage consiste à générer une empreinte unique (sous réserve de collision) associée au mot de passe initial. C’est cette empreinte qui est stockée, ainsi le mot de passe initial n’est jamais révélé. A partir de l’empreinte, il est impossible (mathématiquement parlant) de retrouver le mot de passe en clair originel, ce sont des fonctions à sens unique. Le hachage est donc un mécanisme de sécurité pour le stockage des mots de passe à imposer en toutes circonstances.
Plusieurs algorithmes existent et produisent des empreintes de différentes tailles avec des consommations en ressources différentes. Communément on cite les algorithmes suivants pour ce qui est du hachage de mot de passe :
- MD4 : obsolète
- MD5 : obsolète
- SHA1 : en voie d’obsolescence / obsolète
- SHA 256 / 384 / 512 : nouvelles normes / standard
A ces algorithmes peuvent s’ajouter des mécanismes additionnels pour renforcer l’algorithme de hachage :
- Le salage (salt) : ajout d’un aléa permettant d’augmenter la taille du mot de passe initial et d’en complexifier sa casse. Le salt doit être conservé en clair en parallèle de l’empreinte. Il permet de contrecarrer les attaques par rainbow-table (exemple SSHA, SMD5, BCRYPT). Les empreintes d’un même mot de passe sont donc toutes différentes puisque le salt varie à chaque fois.
- Le bouclage (looping) : pourquoi hacher une unique fois un mot de passe en quelques ms voire µs alors que hacher en boucle un mot de passe et ses empreintes permet d’augmenter le temps de cassage?
- Par exemple : hash = md5(“password”) se calcule disons en 1ms (temps arbitraire)
- hash = “password”; for(i=0;i<1000;<i++) hash = md5(hash);, le mot de passe est haché en boucle 1000 fois en (1ms x 1000) soit 1s
- Si un assaillant tente une attaque brute-force sur l’empreinte finale, chaque test de brute-force sera réalisé en 1s plutôt qu’en 1ms, et donc rallongera considérablement le temps de cryptanalyse renforçant ainsi la confidentialité du mot de passe.
Passons à un cas pratique : imaginez une entreprise qui a centralisé tout ses annuaires LDAP de technologies hétérogènes en un seul et unique annuaire. Seulement, il reste des comptes d’utilisateurs non-importés dans cet annuaire unique et qui sont séquestrés dans une base de données SQL. Au regard du grand nombre de ces utilisateurs (plusieurs centaines par exemple), il est impensable pour l’entreprise de forcer tout ses utilisateurs à réinitialiser leur mot de passe afin que le nouveau mot de passe soit provisionné dans l’annuaire autoritaire.
Peut-on importer des mots de passe hachés d'une base SQL vers un annuaire LDAP, et ce sans avoir à forcer les utilisateurs à retaper / changer ce mot de passe ni en réalisant de la cryptanalyse (cracking de mot de passe) ?
D’ordre général, oui, c’est tout à fait possible. Tout dépend des algorithmes de hachage en place. L’exemple qui suit se base sur l’algorithme MD5.
Dans une base de données SQL (type MySQL), les hashs des mots de passe des utilisateurs peuvent être stockés en MD5, soit une chaîne hexadécimale de 32 caractères de long :
- md5(“password”) = “5f4dcc3b5aa765d61d8327deb882cf99”
Dans un LDAP, le hachage du même mot de passe dans le même algorithme MD5 donne :
- md5LDAP(“password”) = “{MD5}X03MO1qnZdYdgyfeuILPmQ==”
- ou encore en full-base64 : e01ENX1YMDNNTzFxblpkWWRneWZldUlMUG1RPT0K
C’est le même mot de passe “password”, le même algorithme MD5 sans utilisation de salt ni de bouclage. Pourtant les formats des empreintes résultantes diffèrent.
Ce n’est qu’une histoire de conversion !
Comment convertir un MD5 sous sa forme hexadécimale standard (5f4dcc3b5aa765d61d8327deb882cf99) vers l’équivalent compatible LDAP “{MD5}X03MO1qnZdYdgyfeuILPmQ==” ?
Pour réaliser cette conversion, voici les grandes étapes :
- On décode la chaîne de 32 caractères hexadécimale, ce qui donne une chaîne brute composée de caractères non-ASCII
- On encode en base64 cette chaîne non-ASCII pour la rendre affichable : X03MO1qnZdYdgyfeuILPmQ==
- On préfixe la chaîne en base64 par l’algorithme entre accolades (c’est via ce préfixe qu’un annuaire LDAP sait l’algorithme employé) : {MD5}X03MO1qnZdYdgyfeuILPmQ==
- Éventuellement, on ré-encode le tout (préfixe compris) en base64 pour faciliter un import dans l’annuaire LDAP via un LDIF : e01ENX1YMDNNTzFxblpkWWRneWZldUlMUG1RPT0K
Script permettant de réaliser toutes ces actions :
Exécution :
A présent, il est aisé d’extraire tous les couples login/passwordMD5 d’une base de données SQL, convertir tout ces passwordMD5 vers le format MD5-LDAP, et réinjecter via un LDIF les comptes dans l’annuaire.
Tout ceci rapidement, sans cryptanalyse, sans visualiser les mots de passe en clair, et sans changement d’algorithme.
Les annuaires LDAP supportent plusieurs type d’algorithme de hachage en fonction des préfixes disponibles :
- CRYPT : obsolète
- MD5 : obsolète
- SMD5 : secure MD5 avec bouclage et salage
- SHA : SHA1 standard
- SSHA : secure SHA1 avec bouclage et salage
- SHA256 / 384 / 512
Noter que : une conversion de format d’un hash, sans cryptanalyse, ne peut se faire que d’un algorithme de hachage vers le même algorithme de hachage (MD5 vers MD5LDAP ou SHA1 vers SHA1LDAP). La conversion inverse MD5LDAP vers MD5 peut se faire aussi aisément.
A l’heure d’aujourd’hui, privilégier l’utilisation des algorithmes de hachage SHA256 lorsque possible, voire même SSHA256 (avec bouclage et salage) pour les annuaires LDAP. En base de données et pour les applications web, n’hésitez pas à vous orienter vers le BCRYPT.
Si vous souhaitez harmoniser et renforcer tous vos mots de passe dans l’annuaire vers un algorithme de hachage robuste, il convient de déployer des modules de politique de mot de passe. Exemple pour OpenLDAP avec l’overlay “ppolicy”. Via cet overlay, dès qu’un utilisateur change son mot de passe, celui-ci est automatiquement haché avant d’être stocké via un algorithme sûr (SSHA).
Pour toutes questions d’ordre technique sur la conversion de format de hachage, d’import/export SQL/LDAP, de configuration et mise en place de politique de mot de passe, n’hésitez pas à nous contacter.