Version imprimable du sujet

Cliquez ici pour voir ce sujet dans son format original

Forum osCommerce-fr _ Installation - fonctionnement _ migration de base et mot de passe des clients

Écrit par : Kawaii77 7 Jun 2018, 19:51

Bonjour,

Je change complètement mon site mais je veux récupérer mes bases dont customers.
Je voudrais pouvoir vérifier le mot de passe chiffré par Osc mais ça fait deux jours que j'essaie de comprendre le code, de faire des tests, impossible de reproduire la function tep_validate_password.
Comment faire pour avoir un simple bout de code qui me permette de comparer le mot de passe saisi et celui de la base de données ?

Écrit par : Bonbec 7 Jun 2018, 20:46

Bonjour,
Pour récupérer les bases, rien de mieux que PhpMyAdmin qui est disponible chez la majorité des hébergeurs.
Pour les mots de passe, il n'y a, en principe, aucun problème pour passer d'une version d'OsCommerce à une autre. Donc je ne vois pas l'utilité de faire la comparaison.

Écrit par : Kawaii77 8 Jun 2018, 08:16

Les bases sont récupérées, ce n'est pas le problème.
Je ne change pas de version d'OsCommerce, je change complètement de structure.
J'ai donc besoin de vérifier le mot de passe existant pour ensuite modifier la base et utiliser mon propre chiffrement.

Quelqu'un aurait un bout de code à me proposer ?
J'en ai testé plusieurs, aucun ne fonctionne.
md5('mot de passe saisi') ne fonctionne pas, il y a un sel que je ne trouve/comprends pas.
crypt non plus.

Écrit par : Kawaii77 9 Jun 2018, 07:57

Personne ne sait comment est codé le chiffrement des mots de passe de table customers ?

Écrit par : Bonbec 10 Jun 2018, 14:05

Re,

Tu as quelle version d'OsCommerce ? 2.3 c'est vague ... on en est à la 2.3.4.1
Pour la version bootstrap communautaire (2.3.4 BS) par exemple, c'est dans includes/classes/passwordhash.php que cela se passe.

Mais je ne comprend toujours aps pourquoi savoir cela, la compatibilité des mots de passe est assurée dans toutes les versions d'OsCommerce ...

Écrit par : Kawaii77 11 Jun 2018, 14:50

Pour la version, où est-ce que je peux la lire ?

Je ne fais pas évoluer OsCommerce, je le quitte, je change complètement de gestion tout en gardant ma table customer, d'où mon besoin de vérifier le mot de passe selon OsCommerce quand le compte client aura été créé sur Osc (sur le site actuel qui va disparaitre) et de le chiffrer selon le nouveau site à la première connexion sur le nouveau site avec un chiffrement password_hash car je pourrais alors être en php 5.5.

J'ai donc juste besoin de vérifier le mot de passe pour éviter de demander à tous les clients de créer un nouveau mot de passe et risquer de le perdre pendant l'achat.

Écrit par : Bonbec 11 Jun 2018, 15:23

Citation (Kawaii77 @ 11 Jun 2018, 14:50) *
Pour la version, où est-ce que je peux la lire ?

Dans ton administration / Outils / Version

Citation (Kawaii77 @ 11 Jun 2018, 14:50) *
Je ne fais pas évoluer OsCommerce

Il existe une version d'OsCommerce qui est responsive, c'est à dire qu'on peut voir le site nickel quelque soit le support : téléphone, tablette, Pc etc ...
Voilà un lien pour une démo : http://template.me.uk/234bs3/index.php

Je suis en train de refaire mon site avec cette version.

Cela te permettrait de ne pas avoir de problèmes avec tes mots de passe.

Écrit par : Kawaii77 12 Jun 2018, 05:27

Pour la version, il semble que j'ai enlevé cette information de l'admin, mais dans le code d'origine j'ai trouvé "osCommerce Online Merchant v2.2 RC1".

Le responsive est en effet une des raisons pour laquelle je quitte Oscommerce, + le https + mes problèmes insurmontables pour les sessions + l'évolution de Php + ... +...
Je ne connaissais pas cette version responsive, dommage mais comme je n'ai cherché à faire évoluer les versions à cause de toutes les adaptations.

Je change donc pour un code que je connais et que je peux modifier plus facilement qu'Oscommerce qui passe par 10 fichiers et 15 fonctions pour sortir une variable. J'en ai marre de jouer le Petit Poucet dès que je veux changer quelque chose.

Mon problème de mot de passe reste donc entier et la fonction qui m'intéresse c'est tep_validate_password.

Si ça peut aider j'ai ce code dans password_funcs.php :

Code
// This function validates a plain text password with a
// salted or phpass password
   function tep_validate_password($plain, $encrypted) {
     if (tep_not_null($plain) && tep_not_null($encrypted)) {
       if (tep_password_type($encrypted) == 'salt') {
         return tep_validate_old_password($plain, $encrypted);
       }

       if (!class_exists('PasswordHash')) {
         include(DIR_WS_CLASSES . 'passwordhash.php');
       }

       $hasher = new PasswordHash(10, true);

       return $hasher->CheckPassword($plain, $encrypted);
     }

     return false;
   }

////
// This function validates a plain text password with a
// salted password
   function tep_validate_old_password($plain, $encrypted) {
     if (tep_not_null($plain) && tep_not_null($encrypted)) {
// split apart the hash / salt
       $stack = explode(':', $encrypted);

       if (sizeof($stack) != 2) return false;

       if (md5($stack[1] . $plain) == $stack[0]) {
         return true;
       }
     }

     return false;
   }

////
// This function encrypts a phpass password from a plaintext
// password.
   function tep_encrypt_password($plain) {
     if (!class_exists('PasswordHash')) {
       include(DIR_WS_CLASSES . 'passwordhash.php');
     }

     $hasher = new PasswordHash(10, true);

     return $hasher->HashPassword($plain);
   }

////
// This function encrypts a salted password from a plaintext
// password.
   function tep_encrypt_old_password($plain) {
     $password = '';

     for ($i=0; $i<10; $i++) {
       $password .= tep_rand();
     }

     $salt = substr(md5($password), 0, 2);

     $password = md5($salt . $plain) . ':' . $salt;

     return $password;
   }

////
// This function returns the type of the encrpyted password
// (phpass or salt)
   function tep_password_type($encrypted) {
     if (preg_match('/^[A-Z0-9]{32}\:[A-Z0-9]{2}$/i', $encrypted) === 1) {
       return 'salt';
     }

     return 'phpass';
   }


Et dans la passwordhash.php j'ai :
Code
class PasswordHash {
     var $itoa64;
     var $iteration_count_log2;
     var $portable_hashes;
     var $random_state;

     function PasswordHash($iteration_count_log2, $portable_hashes)
     {
         $this->itoa64 = './2346789ABCDEFGHJKLMNPQRSTUVWXYZ';

         if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
             $iteration_count_log2 = 8;
         $this->iteration_count_log2 = $iteration_count_log2;

         $this->portable_hashes = $portable_hashes;

         $this->random_state = microtime();
         if (function_exists('getmypid'))
             $this->random_state .= getmypid();
     }

     function get_random_bytes($count)
     {
         $output = '';
         if (@is_readable('/dev/urandom') &&
             ($fh = @fopen('/dev/urandom', 'rb'))) {
             $output = fread($fh, $count);
             fclose($fh);
         }

         if (strlen($output) < $count) {
             $output = '';
             for ($i = 0; $i < $count; $i += 16) {
                 $this->random_state =
                     md5(microtime() . $this->random_state);
                 $output .=
                     pack('H*', md5($this->random_state));
             }
             $output = substr($output, 0, $count);
         }

         return $output;
     }

     function encode64($input, $count)
     {
         $output = '';
         $i = 0;
         do {
             $value = ord($input[$i++]);
             $output .= $this->itoa64[$value & 0x3f];
             if ($i < $count)
                 $value |= ord($input[$i]) << 8;
             $output .= $this->itoa64[($value >> 6) & 0x3f];
             if ($i++ >= $count)
                 break;
             if ($i < $count)
                 $value |= ord($input[$i]) << 16;
             $output .= $this->itoa64[($value >> 12) & 0x3f];
             if ($i++ >= $count)
                 break;
             $output .= $this->itoa64[($value >> 18) & 0x3f];
         } while ($i < $count);

         return $output;
     }

     function gensalt_private($input)
     {
         $output = '$P ;
         $output .= $this->itoa64[min($this->iteration_count_log2 +
             ((PHP_VERSION >= '5') ? 5 : 3), 30)];
         $output .= $this->encode64($input, 6);

         return $output;
     }

     function crypt_private($password, $setting)
     {
         $output = '*0';
         if (substr($setting, 0, 2) == $output)
             $output = '*1';

         $id = substr($setting, 0, 3);
         # We use "$P$", phpBB3 uses "$H$" for the same thing
         if ($id != '$P   && $id != '$H  )
             return $output;

         $count_log2 = strpos($this->itoa64, $setting[3]);
         if ($count_log2 < 7 || $count_log2 > 30)
             return $output;

         $count = 1 << $count_log2;

         $salt = substr($setting, 4, 8);
         if (strlen($salt) != 8)
             return $output;

         # We're kind of forced to use MD5 here since it's the only
         # cryptographic primitive available in all versions of PHP
         # currently in use.  To implement our own low-level crypto
         # in PHP would result in much worse performance and
         # consequently in lower iteration counts and hashes that are
         # quicker to crack (by non-PHP code).
         if (PHP_VERSION >= '5') {
             $hash = md5($salt . $password, TRUE);
             do {
                 $hash = md5($hash . $password, TRUE);
             } while (--$count);
         } else {
             $hash = pack('H*', md5($salt . $password));
             do {
                 $hash = pack('H*', md5($hash . $password));
             } while (--$count);
         }

         $output = substr($setting, 0, 12);
         $output .= $this->encode64($hash, 16);

         return $output;
     }

     function gensalt_extended($input)
     {
         $count_log2 = min($this->iteration_count_log2 + 8, 24);
         # This should be odd to not reveal weak DES keys, and the
         # maximum valid value is (2**24 - 1) which is odd anyway.
         $count = (1 << $count_log2) - 1;

         $output = '_';
         $output .= $this->itoa64[$count & 0x3f];
         $output .= $this->itoa64[($count >> 6) & 0x3f];
         $output .= $this->itoa64[($count >> 12) & 0x3f];
         $output .= $this->itoa64[($count >> 18) & 0x3f];

         $output .= $this->encode64($input, 3);

         return $output;
     }

     function gensalt_blowfish($input)
     {
         # This one needs to use a different order of characters and a
         # different encoding scheme from the one in encode64() above.
         # We care because the last character in our encoded string will
         # only represent 2 bits.  While two known implementations of
         # bcrypt will happily accept and correct a salt string which
         # has the 4 unused bits set to non-zero, we do not want to take
         # chances and we also do not want to waste an additional byte
         # of entropy.
         $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

         $output = '$2a ;
         $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
         $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
         $output .= ' ;

         $i = 0;
         do {
             $c1 = ord($input[$i++]);
             $output .= $itoa64[$c1 >> 2];
             $c1 = ($c1 & 0x03) << 4;
             if ($i >= 16) {
                 $output .= $itoa64[$c1];
                 break;
             }

             $c2 = ord($input[$i++]);
             $c1 |= $c2 >> 4;
             $output .= $itoa64[$c1];
             $c1 = ($c2 & 0x0f) << 2;

             $c2 = ord($input[$i++]);
             $c1 |= $c2 >> 6;
             $output .= $itoa64[$c1];
             $output .= $itoa64[$c2 & 0x3f];
         } while (1);

         return $output;
     }

     function HashPassword($password)
     {
         $random = '';

         if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
             $random = $this->get_random_bytes(16);
             $hash =
                 crypt($password, $this->gensalt_blowfish($random));
             if (strlen($hash) == 60)
                 return $hash;
         }

         if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
             if (strlen($random) < 3)
                 $random = $this->get_random_bytes(3);
             $hash =
                 crypt($password, $this->gensalt_extended($random));
             if (strlen($hash) == 20)
                 return $hash;
         }

         if (strlen($random) < 6)
             $random = $this->get_random_bytes(6);
         $hash =
             $this->crypt_private($password,
             $this->gensalt_private($random));
         if (strlen($hash) == 34)
             return $hash;

         # Returning '*' on error is safe here, but would _not_ be safe
         # in a crypt(3)-like function used _both_ for generating new
         # hashes and for validating passwords against existing hashes.
         return '*';
     }

     function CheckPassword($password, $stored_hash)
     {
         $hash = $this->crypt_private($password, $stored_hash);
         if ($hash[0] == '*')
             $hash = crypt($password, $stored_hash);

         return $hash == $stored_hash;
     }
}
class PasswordHash {
     var $itoa64;
     var $iteration_count_log2;
     var $portable_hashes;
     var $random_state;

     function PasswordHash($iteration_count_log2, $portable_hashes)
     {
         $this->itoa64 = './2346789ABCDEFGHJKLMNPQRSTUVWXYZ';

         if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
             $iteration_count_log2 = 8;
         $this->iteration_count_log2 = $iteration_count_log2;

         $this->portable_hashes = $portable_hashes;

         $this->random_state = microtime();
         if (function_exists('getmypid'))
             $this->random_state .= getmypid();
     }

     function get_random_bytes($count)
     {
         $output = '';
         if (@is_readable('/dev/urandom') &&
             ($fh = @fopen('/dev/urandom', 'rb'))) {
             $output = fread($fh, $count);
             fclose($fh);
         }

         if (strlen($output) < $count) {
             $output = '';
             for ($i = 0; $i < $count; $i += 16) {
                 $this->random_state =
                     md5(microtime() . $this->random_state);
                 $output .=
                     pack('H*', md5($this->random_state));
             }
             $output = substr($output, 0, $count);
         }

         return $output;
     }

     function encode64($input, $count)
     {
         $output = '';
         $i = 0;
         do {
             $value = ord($input[$i++]);
             $output .= $this->itoa64[$value & 0x3f];
             if ($i < $count)
                 $value |= ord($input[$i]) << 8;
             $output .= $this->itoa64[($value >> 6) & 0x3f];
             if ($i++ >= $count)
                 break;
             if ($i < $count)
                 $value |= ord($input[$i]) << 16;
             $output .= $this->itoa64[($value >> 12) & 0x3f];
             if ($i++ >= $count)
                 break;
             $output .= $this->itoa64[($value >> 18) & 0x3f];
         } while ($i < $count);

         return $output;
     }

     function gensalt_private($input)
     {
         $output = '$P ;
         $output .= $this->itoa64[min($this->iteration_count_log2 +
             ((PHP_VERSION >= '5') ? 5 : 3), 30)];
         $output .= $this->encode64($input, 6);

         return $output;
     }

     function crypt_private($password, $setting)
     {
         $output = '*0';
         if (substr($setting, 0, 2) == $output)
             $output = '*1';

         $id = substr($setting, 0, 3);
         # We use "$P$", phpBB3 uses "$H$" for the same thing
         if ($id != '$P   && $id != '$H  )
             return $output;

         $count_log2 = strpos($this->itoa64, $setting[3]);
         if ($count_log2 < 7 || $count_log2 > 30)
             return $output;

         $count = 1 << $count_log2;

         $salt = substr($setting, 4, 8);
         if (strlen($salt) != 8)
             return $output;

         # We're kind of forced to use MD5 here since it's the only
         # cryptographic primitive available in all versions of PHP
         # currently in use.  To implement our own low-level crypto
         # in PHP would result in much worse performance and
         # consequently in lower iteration counts and hashes that are
         # quicker to crack (by non-PHP code).
         if (PHP_VERSION >= '5') {
             $hash = md5($salt . $password, TRUE);
             do {
                 $hash = md5($hash . $password, TRUE);
             } while (--$count);
         } else {
             $hash = pack('H*', md5($salt . $password));
             do {
                 $hash = pack('H*', md5($hash . $password));
             } while (--$count);
         }

         $output = substr($setting, 0, 12);
         $output .= $this->encode64($hash, 16);

         return $output;
     }

     function gensalt_extended($input)
     {
         $count_log2 = min($this->iteration_count_log2 + 8, 24);
         # This should be odd to not reveal weak DES keys, and the
         # maximum valid value is (2**24 - 1) which is odd anyway.
         $count = (1 << $count_log2) - 1;

         $output = '_';
         $output .= $this->itoa64[$count & 0x3f];
         $output .= $this->itoa64[($count >> 6) & 0x3f];
         $output .= $this->itoa64[($count >> 12) & 0x3f];
         $output .= $this->itoa64[($count >> 18) & 0x3f];

         $output .= $this->encode64($input, 3);

         return $output;
     }

     function gensalt_blowfish($input)
     {
         # This one needs to use a different order of characters and a
         # different encoding scheme from the one in encode64() above.
         # We care because the last character in our encoded string will
         # only represent 2 bits.  While two known implementations of
         # bcrypt will happily accept and correct a salt string which
         # has the 4 unused bits set to non-zero, we do not want to take
         # chances and we also do not want to waste an additional byte
         # of entropy.
         $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

         $output = '$2a ;
         $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
         $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
         $output .= ' ;

         $i = 0;
         do {
             $c1 = ord($input[$i++]);
             $output .= $itoa64[$c1 >> 2];
             $c1 = ($c1 & 0x03) << 4;
             if ($i >= 16) {
                 $output .= $itoa64[$c1];
                 break;
             }

             $c2 = ord($input[$i++]);
             $c1 |= $c2 >> 4;
             $output .= $itoa64[$c1];
             $c1 = ($c2 & 0x0f) << 2;

             $c2 = ord($input[$i++]);
             $c1 |= $c2 >> 6;
             $output .= $itoa64[$c1];
             $output .= $itoa64[$c2 & 0x3f];
         } while (1);

         return $output;
     }

     function HashPassword($password)
     {
         $random = '';

         if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
             $random = $this->get_random_bytes(16);
             $hash =
                 crypt($password, $this->gensalt_blowfish($random));
             if (strlen($hash) == 60)
                 return $hash;
         }

         if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
             if (strlen($random) < 3)
                 $random = $this->get_random_bytes(3);
             $hash =
                 crypt($password, $this->gensalt_extended($random));
             if (strlen($hash) == 20)
                 return $hash;
         }

         if (strlen($random) < 6)
             $random = $this->get_random_bytes(6);
         $hash =
             $this->crypt_private($password,
             $this->gensalt_private($random));
         if (strlen($hash) == 34)
             return $hash;

         # Returning '*' on error is safe here, but would _not_ be safe
         # in a crypt(3)-like function used _both_ for generating new
         # hashes and for validating passwords against existing hashes.
         return '*';
     }

     function CheckPassword($password, $stored_hash)
     {
         $hash = $this->crypt_private($password, $stored_hash);
         if ($hash[0] == '*')
             $hash = crypt($password, $stored_hash);

         return $hash == $stored_hash;
     }
}

Écrit par : Bonbec 12 Jun 2018, 10:48

Re,
Voilà le lien pour la version responsive qui fonctionne avec php 7 inclus :
https://github.com/gburton/Responsive-osCommerce

Pour le reste, c'est hors de mes compétences techniques, désolé.
Si tu passes à un système concurrent comme je crois le comprendre, pose la question sur leur forum, le cas s'est peut-être déjà présenté.

Écrit par : Kawaii77 12 Jun 2018, 12:45

Merci Bonbec d'avoir été le seul à me répondre.

Je n'utiliserais pas la version responsive proposée, je n'ai pas envie de tout revoir.
Je ne vais pas non plus à la concurrence, pas de cms, donc pas de passerelle possible.
Je pars sur une copie d'un autre site maison qui tourne bien depuis longtemps, j'ai juste à adapter les tables et les requêtes.
Et juste à vérifier ce mot de passe.

Tant pis, ça confirme que je fais bien de quitter OsCommerce.

Écrit par : Havock 14 Jun 2018, 07:56

Bonjour Kawaii77 , bonjour Bonbec,

C'est vrai qu'en dehors de Bonbec et de quelques anciens qui passent de temps en temps, l'oscommerce Français est dans le coma.

Citation (Kawaii77 @ 8 Jun 2018, 08:16) *
J'ai donc besoin de vérifier le mot de passe existant pour ensuite modifier la base et utiliser mon propre chiffrement.



Citation (Kawaii77 @ 11 Jun 2018, 14:50) *
je change complètement de gestion tout en gardant ma table customer, d'où mon besoin de vérifier le mot de passe selon OsCommerce quand le compte client aura été créé sur Osc (sur le site actuel qui va disparaitre) et de le chiffrer selon le nouveau site à la première connexion sur le nouveau site avec un chiffrement password_hash car je pourrais alors être en php 5.5.
J'ai donc juste besoin de vérifier le mot de passe pour éviter de demander à tous les clients de créer un nouveau mot de passe et risquer de le perdre pendant l'achat.


Je n'ai pas bien saisi si ta question porte sur la façon de procéder ou juste sur la partie cryptage ?


Écrit par : Rusti 15 Jun 2018, 09:54

Bonjour Kawaii77
Si je me souviens bien c'est un hashage à sens unique (crypt) sur osommerce donc indéchiffrable.

Petite solution qui n'est surement pas la meilleur mais bon :

Tu pourrais ajouter un champ INT à ta table customers pour vérifier si le clients est c'est déjà connecter sur ton nouveau site.
Si c'est la première fois, alors tu créé une fonction qui vas vérifier que le mot de passe est bon avec crypt. Si le password est bon alors tu chiffre le mot de passe avec password_hash et tu change la valeur du nouveau champ INT pour ne plus faire la vérification lors de la connexion.

Propulsé par Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)