IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PHP & Base de données Discussion :

password_verify : quelle sécurité?


Sujet :

PHP & Base de données

  1. #1
    Membre actif Avatar de tribaleur
    Profil pro
    Développeur informatique
    Inscrit en
    Mai 2006
    Messages
    401
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2006
    Messages : 401
    Points : 237
    Points
    237
    Par défaut password_verify : quelle sécurité?
    Bonjour à tous,

    Je me renseigne sur l'encodage des passwords pour mes différentes applications web et je me rends compte que PHP intègre ça nativement dans son framework. Cool .
    En effet, on encode facilement avec password_hash() et on vérifie si le mot de passe saisi correspond bien au hash qu'on a en base de données avec password_verify(). Facile!


    La fonction password_hash() retourne une valeur hashée contenant toutes les informations nécessaires (encodage+salt) à password_verify(). Cette dernière peut à partir de là définir quel est le salt et en l'utilisant de nouveau comparer le hash du mdp.
    Ce que je ne comprend pas c'est comment fait cette fonction password_verify() pour déterminer quel est le salt à chaque fois. Sachant quelle y arrive, est-ce que finalement password_hash() est si bien sécurisé que ça?

    Je ne traite pas de données cruciales. Ni pour des millions d'utilisateurs à travers le monde. Mais j'aime bien comprendre et je n'ai rien trouvé dans la docs officielle.
    Et je me dis que si password_verify() peut retrouver le salt à partir de la chaine hashée, alors un hacker aussi.

    Est-ce que par hasard vous pourriez me dire à quel moment il y a un truc que je n'ai pas compris?

    D'avance merci.
    Rien n'est rien!!! ... Tout est quelque chose!!!

    Petits liens utiles :
    -Chaine de connexion : http://www.connectionstrings.com/
    -ADO et ADO.net : Tuto ADO et ADO.net

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    J'étais en formation Web, et je me suis posé la même question

    Ce que je pense, c'est que la fonction password_hash travaille comme cela :

    entrée, un mot de passe -> encodage/ empreinte (hash) (1) -> découpage du résultat pour ajouter le salage -> [éventuellement re-"encodage/ empreinte" du résultat salé (2)] -> résultat final (3)

    En gros, le salage doit être rajouté après coup, parce que la fonction password_verify doit pouvoir reconstituer (1) (et donc supprimer le salage) afin de faire la comparaison entre les 2 encodages/ empreintes : celle existante et celle que l'on demande de tester .

    L'étape (2) ne semble pas être possible , ou alors c'est une opération symétrique (avec des XOR par exemple)


    Il faudrait vérifier si dans le résultat final (3), on retrouve ou pas l'encodage/ empreinte (1) en morceau

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Au cas où ça vous aurait échappé...

    À aucun moment, password_verify n'utilise ni ne reconstitue le mot de passe EN CLAIR.

    Or c'est lui qui est "intéressant"...

  4. #4
    Membre actif Avatar de tribaleur
    Profil pro
    Développeur informatique
    Inscrit en
    Mai 2006
    Messages
    401
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2006
    Messages : 401
    Points : 237
    Points
    237
    Par défaut
    Bonjour à tous les deux,

    @Foetus : en effet, c'est cette deuxième étape qui m'interroge dans password_verify(). Je ne vois pas comment ça peut-être fait de manière sécurisé.

    @Jreaux62 : password_verify() n'as a aucun moment besoin du mot de passe en clair, je suis d'accord. Mais il a besoin de retrouver le hash du mot de pass sans le salt. Ce qui revient au final à connaitre "facilement" le mot de passe (en tous cas pour les mots de passe peu sécurisés) avec un site du genre md5Online. Ou pour le moins à perdre l'utilité du salt.
    Rien n'est rien!!! ... Tout est quelque chose!!!

    Petits liens utiles :
    -Chaine de connexion : http://www.connectionstrings.com/
    -ADO et ADO.net : Tuto ADO et ADO.net

  5. #5
    Membre expert
    Avatar de Spartacusply
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mai 2011
    Messages
    1 723
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2011
    Messages : 1 723
    Points : 3 274
    Points
    3 274
    Par défaut
    Déjà password_hash et password_verify n'y sont absolument pour rien dans la force ou la faiblesse du cryptage des mots de passe. Ce ne sont rien d'autres que des alias pour faire du hashage et de la vérification de mot de passe en une seule fonction au lieu de faire plusieurs opérations.

    Ce qui est important c'est l'algorithme de cryptage utilisé qui se trouve être Blowfish par défaut actuellement.

    Mais il a besoin de retrouver le hash du mot de pass sans le salt.
    Non ! Blowfish retrouve bien le hash AVEC le salt.

    Ce que je ne comprend pas c'est comment fait cette fonction password_verify() pour déterminer quel est le salt à chaque fois.
    Mais elle ne le calcul pas Le salt n'a pas vocation à être secret, celui-ci sert "juste" à rendre obsolète toute table de correspondance entre un mot de passe et son hash. Le salt est stocké juste à côté du mot de passe dans la chaîne de résultat généré par password_hash.

    Sachant quelle y arrive, est-ce que finalement password_hash() est si bien sécurisé que ça?
    Oui elle l'est car la force de blowfish (et de tout algorithme de hashage en général) réside dans la durée nécessaire de calcul du hash à partir du mot de passe en clair, et il s'avère que cette durée est largement supérieure à MD5 ou SHA1 par exemple. Cela empêche toute tentative de hack via force brut car celle-ci dévient rapidement beaucoup trop longue à partir du moment ou le mot de passe est suffisamment compliqué.
    Un message utile vous a aidé ? N'oubliez pas le

    www.simplifions.fr - Simplifier vos comptes entre amis !

  6. #6
    Membre actif Avatar de tribaleur
    Profil pro
    Développeur informatique
    Inscrit en
    Mai 2006
    Messages
    401
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2006
    Messages : 401
    Points : 237
    Points
    237
    Par défaut
    Citation Envoyé par Spartacusply Voir le message
    Mais elle ne le calcul pas Le salt n'a pas vocation à être secret, celui-ci sert "juste" à rendre obsolète toute table de correspondance entre un mot de passe et son hash. Le salt est stocké juste à côté du mot de passe dans la chaîne de résultat généré par password_hash.
    A mon sens le Salt doit rester secret non?
    Sinon il est facile en l'enlevant de définir quel est le hash du mot de passe de départ. Et donc par la suite de pouvoir utiliser une table de correspondance non?

    J'ai l'impression de ne pas comprendre quelque chose. Pour moi voici ce que fait "en gros" password_hash().
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    $mdp = 'CeciEstUnMdpCompliqué!';
    $salt = 'x15sz4y5;,45t';
     
    $hash1 = encodeAvecBlowFish ($hash1 + $salt); // disons que ça retourne "aaaa"
    Dans un cas comme ci-dessous, on ne peut clairement pas retrouver le salt. Et il faudrait avoir dans une table de comparaison la chaine : aaaa = 'CeciEstUnMdpCompliqué!x15sz4y5;,45t'. Compliqué donc de retrouver le mot de passe.

    D'après ce que vous dites je comprend que ça fonctionnerai plutôt comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    $mdp = 'CeciEstUnMdpCompliqué!';
    $salt = 'x15sz4y5;,45t';
     
    $hash1 = encodeAvecBlowFish ($mdp); // disons que ça retourne "aaaa"
    $hash2 = encodeAvecBlowFish ($salt); // disons que ça retourne "bbbb"
    $hash3 = $hash1 + $hash2; // retournerai donc "aaaabbbb"
    Mais du coup je ne vois pas comment savoir quel $salt a été utilisé si il change à chaque génération de hash (sauf si il fait toujours la même longueur).
    Et si jamais il a une longueur fixe et qu'on peut déduire que "bbbb" est le salt, alors on sait que aaaa est le hash du mdp.

    On a donc "plus qu'à" trouver une table de correspondance avec aaaa = 'CeciEstUnMdpCompliqué!'. Et surtout je vois du coup pas l'utilité du salt.

    Je suis désolé j'ai l'impression de tourné en rond

    En tous cas merci à tous pour vos réponses.
    Rien n'est rien!!! ... Tout est quelque chose!!!

    Petits liens utiles :
    -Chaine de connexion : http://www.connectionstrings.com/
    -ADO et ADO.net : Tuto ADO et ADO.net

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Je comprends que dalle mais je tiens une idée :

    L'empreinte de l'algo bcrypt a cette tronche : $2a$12$8vxYfAWCXe0Hm4gNX8nzwuqWNukOkcMJ1a9G2tD71ipotEZ9f80Vu
    Et :
    1. $2a$ -> c'est un identifiant algo
    2. 12 -> c'est le "cost", c'est le nombre de fois que l'algo va "hasher"
    3. 8vxYfAWCXe0Hm4gNX8nzwu -> c'est le sel ("salt")
    4. qWNukOkcMJ1a9G2tD71ipotEZ9f80Vu -> c'est notre empreinte


    Petite précision : l'algo bcrypt a besoin du sel ("salt") pour travailler. D'ailleurs la documentation PHP l'explique bien et par défaut un sel est généré pour nous, avec un "cost" de 10 (*)

    Avec tout cela, c'est sécurisé parce que
    1. l'algo bcrypt est lent parce qu'il "hashe" plusieurs. Donc il ralentit le processus de comparaison.
    2. Le sel ("salt") n'a pas besoin d'être secret parce qu'il est différent pour chaque empreinte. Et apparemment ceci est le summum de la sécurité parce que cela oblige les vilains hackers à décoder 1 empreinte à la fois.



    * ->
    PASSWORD_BCRYPT - Utilisation de l'algorithme CRYPT_BLOWFISH pour créer la clé de hachage. Ceci va créer une clé de hachage standard crypt() utilisant l'identifiant "$2y$". Le résultat sera toujours une chaîne de 60 caractères, ou FALSE si une erreur survient.

    Options supportées :

    salt - pour fournir manuellement un salt à utiliser lors du hachage du mot de passe. Notez que cette option empêchera la génération automatique.

    Si omis, un salt aléatoire sera généré par la fonction password_hash() pour chaque mot de passe haché. C'est le mode de fonctionnement prévu.

    cost - détermine le coût algorithmique qui doit être utilisé. Des exemples de ces valeurs peuvent être trouvés sur la page de la documentation de la fonction crypt().

    Si omis, la valeur par défaut 10 sera utilisée. C'est un bon compromis, mais vous pourriez vouloir l'augmenter suivant votre architecture.

  8. #8
    Modérateur
    Avatar de sabotage
    Homme Profil pro
    Inscrit en
    Juillet 2005
    Messages
    29 208
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juillet 2005
    Messages : 29 208
    Points : 44 155
    Points
    44 155
    Par défaut
    Le salt n'a pas besoin d'être secret, il vise à rendre inutile des tables de hachage.
    Même si la personne malveillante vise un utilisateur en particulier, il va devoir générer une table de hachage entière avec ce sel, ce qui va être long.
    N'oubliez pas de consulter les FAQ PHP et les cours et tutoriels PHP

  9. #9
    Membre actif Avatar de tribaleur
    Profil pro
    Développeur informatique
    Inscrit en
    Mai 2006
    Messages
    401
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2006
    Messages : 401
    Points : 237
    Points
    237
    Par défaut
    Bon ok j'ai mis du temps à comprendre mais ça y est je pense avoir trouvé.

    En prenant les données (merci @Foetus) ci-dessous et en partant du principe que le mdp saisi est 'test' :
    password_hash() va retourné le résultat suivant (uniquement dans notre exemple) : $2a$12$8vxYfAWCXe0Hm4gNX8nzwuqWNukOkcMJ1a9G2tD71ipotEZ9f80Vu
    Ici on a :
    $2a$ -> c'est un identifiant algo (défini dans le cas présent l'encodage BlowFish)
    12 -> c'est le "cost", c'est le nombre de fois que l'algo va "hasher" la concaténation salt+mdp
    8vxYfAWCXe0Hm4gNX8nzwu -> c'est le salt en clair!
    qWNukOkcMJ1a9G2tD71ipotEZ9f80Vu -> c'est le hash obtenue par l'encodage BlowFish pour la chaine de caractère salt+mdp

    Salt + mdp = 8vxYfAWCXe0Hm4gNX8nzwutest (dans l'exemple actuel)

    8vxYfAWCXe0Hm4gNX8nzwutest hashé avec blowFiwh va retourner : qWNukOkcMJ1a9G2tD71ipotEZ9f80Vu (on appel ça l'empreinte apparemment).

    Du coup ici password_verify() va vérifier que 'test' + 8vxYfAWCXe0Hm4gNX8nzwu encoder avec BlowFish avec un cost de 12 = qWNukOkcMJ1a9G2tD71ipotEZ9f80Vu

    Ce qui est sécurisé car en effet, si on veut faire retrouver le mot de passe il faudra ici faire une table de hashage uniquement pour le salt : 8vxYfAWCXe0Hm4gNX8nzwu.

    Ce que je n'avais pas compris en faite c'était que l'empreinte comportait le salt aussi. Et surtout que le salt retourné dans le résultat password_hash() était en clair.

    Merci à tous pour votre aide!

    Rien n'est rien!!! ... Tout est quelque chose!!!

    Petits liens utiles :
    -Chaine de connexion : http://www.connectionstrings.com/
    -ADO et ADO.net : Tuto ADO et ADO.net

  10. #10
    Membre expert
    Avatar de Spartacusply
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mai 2011
    Messages
    1 723
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2011
    Messages : 1 723
    Points : 3 274
    Points
    3 274
    Par défaut
    @tribaleur

    Je pense que foetus a répondu à ce que tu ne comprends pas. Le résultat de la fonction password_hash génère un hash via l'algo blowfish mais ne renvoie pas que ça : elle y ajoute l'algo, le cout et le fameux salt (comme l'a expliqué foetus) avant de retourner son résultat.

    La fonction de vérification se sert de ce hash là pour recréer le hash du mot de passe passé en clair en paramètre.

    L'algo blowfish est donc sécurisé car :

    - Comme dis par foetus, l'utilisation d'un salt est obligatoire (qui possède une taille minimum qui plus est) sans quoi l'algo ne peut pas fonctionner alors qu'évidemment avec md5 rien ne t'empêche de ne pas en utiliser, et donc te laisser vulnérable aux tables de correspondance.
    - Il est lent (ce qui n'est pas le cas de MD5/SHA1 qui au contraire sont prévus pour être le plus rapide possible) et peut-être ralenti à la demande en indiquant un "coût" plus fort. En gros, blowfish possède une boucle à l'intérieur de son algo qui modifie le hash calculé. Comme on peut régler le nombre de tour, il suffit simplement de faire plus de tour pour que le temps de calcul soit plus long et donc augmenter la sécurité du hachage produit.


    EDIT : ben voilà
    Un message utile vous a aidé ? N'oubliez pas le

    www.simplifions.fr - Simplifier vos comptes entre amis !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 61
    Dernier message: 29/12/2016, 12h58
  2. Quelle sécurité pour sites qui demandent connexion Gmail ?
    Par Wymeswold dans le forum Sécurité
    Réponses: 3
    Dernier message: 21/06/2011, 19h54
  3. Quelle sécurité ? Puis-je utiliser SSL ?
    Par kimausoleil dans le forum Sécurité
    Réponses: 2
    Dernier message: 26/05/2011, 17h06
  4. Réponses: 2
    Dernier message: 30/05/2006, 11h55
  5. Réponses: 4
    Dernier message: 13/05/2006, 09h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo