Article original : How Devise keeps your Rails app passwords safe
Par Tiago Alves
Devise est une solution d'authentification incroyable pour Rails avec plus de 40 millions de téléchargements. Cependant, comme il abstrait la plupart des opérations cryptographiques, il n'est pas toujours facile de comprendre ce qui se passe en coulisses.
L'une de ces abstractions culmine dans la persistance d'un encrypted_password directement dans la base de données. J'ai donc toujours été curieux de savoir ce qu'il représente réellement. Voici un exemple :
$2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
Mais que signifie ce charabia ?
Devise utilise Bcrypt pour stocker les informations de manière sécurisée. Sur son site, il est mentionné qu'il utilise l'algorithme de hachage de mot de passe « OpenBSD bcrypt() », vous permettant de stocker facilement un hachage sécurisé des mots de passe de vos utilisateurs. Mais qu'est-ce que ce hachage exactement ? Comment fonctionne-t-il et comment protège-t-il les mots de passe stockés ?
C'est ce que je veux vous montrer aujourd'hui.
Travaillons à rebours — du hachage stocké dans votre base de données au processus de chiffrement et de déchiffrement.
Ce hachage $2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO est en réalité composé de plusieurs éléments :
- Version Bcrypt (
2a) - la version de l'algorithme bcrypt() utilisée pour produire ce hachage (stockée après le premier signe$) - Coût (
11) - le facteur de coût utilisé pour créer le hachage (stocké après le deuxième signe$) - Sel (
$2a$11$yMMbLgN9uY6J3LhorfU9iu) - une chaîne aléatoire qui, combinée à votre mot de passe, le rend unique (29 premiers caractères) - Somme de contrôle (
LAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO) - la partie réelle du hachage duencrypted_passwordstocké (chaîne restante après les 29 caractères)
Explorons les 3 derniers paramètres :
- Lorsque vous utilisez Devise, la valeur Coût est définie par une variable de classe appelée stretches et la valeur par défaut est
11. Elle spécifie le nombre de fois où le mot de passe est haché. (_Dans votre initialiseur devise.rb, vous pouvez configurer cette valeur à un niveau inférieur pour l'environnement de test afin de faire tourner votre suite de tests plus rapidement._) * - Le sel est la chaîne aléatoire utilisée pour combiner avec le mot de passe original. C'est ce qui fait que le même mot de passe a des valeurs différentes lorsqu'il est stocké chiffré. (Voir plus bas pourquoi cela compte et ce que sont les attaques par table arc-en-ciel.) **
- La somme de contrôle est le hachage réel généré du mot de passe après avoir été combiné avec le sel aléatoire.
Lorsque qu'un utilisateur s'inscrit sur votre application, il doit définir un mot de passe. Avant que ce mot de passe ne soit stocké dans la base de données, un sel aléatoire est généré via BCrypt::Engine.generate_salt(cost) en tenant compte du facteur de coût mentionné précédemment. (Note : si la valeur de la variable de classe pepper est définie, elle ajoutera sa valeur au mot de passe avant de le saler.)
Avec ce sel (ex. $2a$11$yMMbLgN9uY6J3LhorfU9iu, qui inclut le facteur de coût), il appellera BCrypt::Engine.hash_secret(password, salt) qui calcule le hachage final à stocker en utilisant le sel généré et le mot de passe choisi par l'utilisateur. Ce hachage final (par exemple, $2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO) sera à son tour stocké dans la colonne encrypted_password de la base de données.
Mais si ce hachage est irréversible et que le sel est généré aléatoirement lors de l'appel à BCrypt::Password.create par BCrypt::Engine.generate_salt(cost), comment peut-il être utilisé pour connecter l'utilisateur ?
C'est là que ces différents composants de hachage sont utiles. Après avoir trouvé l'enregistrement correspondant à l'email fourni par l'utilisateur pour se connecter, le mot de passe chiffré est récupéré et décomposé en différents composants mentionnés ci-dessus (Version Bcrypt, Coût, Sel et Somme de contrôle).
Après cette préparation initiale, voici ce qui se passe ensuite :
- Récupérer le mot de passe saisi (
1234) - Récupérer le sel du mot de passe stocké (
$2a$11$yMMbLgN9uY6J3LhorfU9iu) - Générer le hachage à partir du mot de passe et du sel en utilisant la même version de bcrypt et le même facteur de coût (
BCrypt::Engine.hash_secret("1234", "$2a$11$yMMbLgN9uY6J3LhorfU9iu")) - Vérifier si le hachage stocké est le même que celui calculé à l'étape 3 (
$2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO)
Et c'est ainsi que Devise stocke les mots de passe de manière sécurisée et vous protège contre une série d'attaques, même si votre base de données est compromise.
Contactez-moi sur Twitter @alvesjtiago et faites-moi savoir si vous avez trouvé cet article intéressant ! Merci pour votre lecture.
PS : Je ne suis en aucun cas un expert en sécurité ou en cryptographie, alors n'hésitez pas à me contacter si vous trouvez quelque chose de faux. J'espère qu'en simplifiant certains des concepts, il sera plus facile de comprendre ce qui se passe.
_Merci à @filipepina, @ivobenedito, @jackveiga, @joao_mags et @pedrosmmoreira pour les révisions et suggestions. Cet article est également disponible à l'adresse http://blog.tiagoalves.me/how-does-devise-keep-your-passwords-safe._
Plus d'informations sur certains des sujets.
Facteur de coût
Attaques par table arc-en-ciel