[RESOLU] php 7 et fonction password_hash

Eléphanteau du PHP | 29 Messages

26 nov. 2019, 16:59

Bonjour le forum,

On a un petit souci et la bible php pour la fonction password_hash ne nous semble pas assez claire.

Notre accès à l'espace membre passe par un PW haché par sha1, nous voulons avoir une meilleure sécurité et passer à password_hash.

Nous avons réussi à généré les PW avec password_hash (c'est fait indirectement via un fichier txt).

Mais il y a un problème dans le code du fichier d'accès.

Voici notre code précédent qui marche pour le test de validité du PW
$passe1=sha1($_POST["password"]);

Et le nouveau qui ne marche pas...

$passe1=password_hash(PASSWORD_DEFAULT)($password);

On a aussi essayé le code en ajoutant un $Post dans la ligne ci-dessus

Merci de votre aide!

A+

Seb

Eléphant du PHP | 164 Messages

27 nov. 2019, 00:11

Bonsoir,

D'après la doc c'est plutot
$pass = password_hash($password, PASSWORD_DEFAULT)

La doc : https://www.php.net/manual/fr/function. ... d-hash.php
Cordialement
Naroth

Eléphanteau du PHP | 29 Messages

27 nov. 2019, 18:34

Bonjour Naroth,

Merci pour cette réaction rapide.
Malheureusement il doit y avoir autre chose.

Tu dis que cela devrait être cela (adapté)
$passe1= password_hash($password, PASSWORD_DEFAULT);

Sur localhost pas de message d'erreur.
Mais si on essaie sur Internet avec bon ID et PW haché (reste du code avec sha1 inchangé),
la page de départ revient et on n'accède pas à l'espace membre.

On a essayé aussi pour prendre en compte davantage notre code avec sha1
$passe1= password_hash($_POST["password"], PASSWORD_DEFAULT);
mais là avec local host on a une erreur:
Notice: Undefined index: password in D:\_xxx\zzzz.php on line 25 qui correspond à cette ligne de code
Et si on essaie sur Internet avec bon ID et PW haché,
la page de départ revient aussi et on n'accède pas à l'espace membre.

Vois-tu un souci?
Sinon faut-il que l'on mette l'ensemble du code?

Merci de ton aide!

Eléphant du PHP | 164 Messages

27 nov. 2019, 18:42

mais là avec local host on a une erreur:
Notice: Undefined index: password in D:\_xxx\zzzz.php on line 25 qui correspond à cette ligne de code
Je dirais que ton mot de passe n'est pas dans le $_POST

Si tu fais
var_dump($_POST);
Est-ce que tu vois ton mot de passe ?
Cordialement
Naroth

Eléphanteau du PHP | 29 Messages

28 nov. 2019, 18:38

bonjour Naroth,

merci de ton aide!

je pense que tu as raison car avec le test, j'ai en local
array (size=0)
empty
( ! ) Notice: Undefined index: password in D:\_xxxxxxxxxxxxxx.php on line 26
et la ligne 26 est bien:
$passe1= password_hash($_POST["password"], PASSWORD_DEFAULT);

d'un autre côté comme nos ID/PW/date se trouvent ailleurs (et pas dans une table de base de données) il me semble que c'est normal.

bon, malgré l'erreur, j'ai continué le test et j'ai rempli ID et PW en local, alors il revient à la page de départ comme avant, et en plus il ajoute une erreur...
array (size=4)
'ID' => string 'testtest' (length=8)
'x' => string '10' (length=2)
'y' => string '10' (length=2)
'password' => string 'moimeme0' (length=8)
peut-être cela t'aide???

sinon, comme tu es bien plus expert que nous, je te propose de te mettre le code ci-après
tu verras par rapport à la situation actuelle avec sha1 et qui marche en routine, nous n'avons changé qu'une ligne comme je l'avais indiqué...
et donc je suis sec (peut-être que notre code qui marche avec sha1 est incompatible avec password_hash ???)

au vu de notre code qu'en penses-tu? Sinon on restera en sha1!

Merci

<?php
session_start();

//Affichage des erreurs PHP
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);


//récupération propre des variables AVANT leur utilisation:
$ID = !empty($_POST["ID"]) ? $_POST["ID"] : NULL;
$password = !empty($_POST["password"]) ? $_POST["password"] : NULL;

$redirect = "test1.php";
$members_area = "espacemembre/acces.php";
$error = "echec.php";

// Si le formulaire a été envoyé ...les codes sont-ils fournis ?
if(!empty($_POST) && (!$ID || !$password) ) {
//header('Location: $error');
die("Vous devez remplir login et password.");
} else {
var_dump($_POST);
$passe1= password_hash($_POST["password"], PASSWORD_DEFAULT);
//$passe1=sha1($_POST["password"]);
$lignes=file("resa/membrespro.txt");
$membre=0;
$regex="#$ID\t$passe1#";
foreach ($lignes as $lgn) {
if(preg_match($regex,$lgn, $tab)) {
$champ = preg_split('#\t#',$lgn);
$date = !empty($champ) && count($champ)>2 ? $champ[2] : false;

if($date!== false) {
$now = new Datetime();
$now = $now->format('Y-m-d');
$next = new DateTime($date);
if( $now < $date ) {//si la date enregistrée est plus récente que la date actuelle
$membre = 1;
$id_mem = !empty($tab[1]) ? $tab[1] : NULL;
}
}
}// fin if(preg_match)
}//fin foreach

if ($membre==1) {
// identifier comme membre
$_SESSION["MEMBRE"]="oui";
$_SESSION["login"]=$ID;
$_SESSION["passe"]=$passe1;
// sauver les infos de connexion, code non copié
header("Location: $members_area");
//exit("connexion OK");
} else {
include "$error";
//header("Location: $error");
//exit;

}//fin else

?>

A+, et merci encore!

Seb

Eléphant du PHP | 164 Messages

30 nov. 2019, 15:59

Bonjour,

Alors je viens de lire la documentation de password_hash plus en détail voici pourquoi te renvoie toujours une erreur :

La fonction password_hash ajoute automatiquement un "salt" à ton mot de passe (Il rajoute automatiquement des caractères à la fin de ton mot de passe pour faire simple) pour des raisons de sécurité

Par exemple si tu fais
$password = "mon mot de passe";
$passHASH = password_hash( $password, PASSWORD_DEFAULT);
echo $passHASH;
Si tu l’exécute plusieurs fois tu n'aura jamais la même chaîne de caractères affichée. Tu ne peux donc pas la vérifier aussi simplement qu'en utilisant la fonction sha1.

Pour que ça marche il faut utiliser la fonction password_verify

Ex :
$password = "mon mot de passe";

$passHASH = password_hash( $password, PASSWORD_DEFAULT);
$passwordValid = password_verify( $password, $passHASH );

var_dump($passwordValid); //  True  
Cordialement
Naroth

Eléphanteau du PHP | 29 Messages

04 déc. 2019, 17:47

Bonjour Naroth,

Et merci de ton aide.

Nous avions soupçonné par hasard le souci avec password_hash car comme nous avions eu peur de nous mélanger les pinceaux et nous avions refait un cryptage par hash (via le net et un fichier txt) et oh surprise on s'est aperçu que les PW hashés avaient changé!!!

Nous ne sommes pas à l'aise avec les variables PHP à définir ou pas, même avec l'aide de bouquins php.
Il vaut mieux le dire franchement!
Aussi avec sha1 nous n'avions pas défini la variable $password (cela apparait quand tu as ajouté le test d'erreur), mais comme cela marchait (on accédait à l'espace membres) cela ne nous a pas inquiétés.

Maintenant avec password_hash cela ne marche toujours pas avec notre adaptation de ton code (vraiment désolé), cad qu'on revient à la page de départ et on n’accède pas à l'espace membres).

Je résume:

avec sha1
$passe1=sha1($_POST["password"]);

avec password_hash (ton code)

$password = "mon mot de passe";
$passHASH = password_hash($password, PASSWORD_DEFAULT);
$passwordValid = password_verify($password, $passHASH);
var_dump($passwordValid); // True

avec password_hash (notre code, -mal!- adapté)
$password = "my password";
var_dump($_POST);
$passe1= password_hash($_POST["password"], PASSWORD_DEFAULT);
$passwordValid = password_verify($password, $passe1);
var_dump($passwordValid); // True

on obtient:

array (size=4)
'ID' => string 'testtest12345' (length=13)
'x' => string '26' (length=2)
'y' => string '6' (length=1)
'password' => string 'testtest678' (length=11)

boolean false

Voilà, on patauge pas mal!
Même après avoir relu : https://www.php.net/manual/fr/language. ... basics.php

A+,

Seb

Eléphant du PHP | 164 Messages

04 déc. 2019, 17:59

Bonsoir,

Alors mon exemple n'a pas du être assez clair

password_hash prend un mot de passe et en génère une chaine de caractère (qu'on va appelé hash)
password_verify prend un mot de passe et un hash et vérifie que le mot de passe est bien celui ayant permit de générer le hash

Autrement dit :
$password1 = "my password";
$password2 = "testtest678";

// génération des hashs
$passHash1 = password_hash( $password1, PASSWORD_DEFAULT);
$passHash2 = password_hash( $password2, PASSWORD_DEFAULT);

// Vérification des hashs

// $password1 et $passHash1
$isValid = password_verify( $password1, $passHash1);
var_dump( $isValid  ); //True - $password1 est bien le mot de passe ayant permis de générer $passHash1

// $password1 et $passHash2
$isValid = password_verify( $password1, $passHash2);
var_dump( $isValid  ); //False - $password1 n'est pas le mot de passe ayant permis de générer $passHash2

// $password2 et $passHash1
$isValid = password_verify( $password2, $passHash1);
var_dump( $isValid  ); //False -  $password2 n'est pas le mot de passe ayant permis de générer $passHash1

// $password2 et $passHash2
$isValid = password_verify( $password2, $passHash2);
var_dump( $isValid  ); //True -  $password2 est bien le mot de passe ayant permis de générer $passHash1
Cordialement
Naroth

Eléphanteau du PHP | 29 Messages

07 déc. 2019, 16:30

Bonjour Naroth,

Merci de la décomposition du code dans ta réponse précédente...
Mais c'est bien moi (et pas toi) qui ne comprend pas comment, à partir de ton exemple pour un cas -my password-, je dois l'adapter à notre code pour le contrôle, ensuite, de la validité de ID/PW/date des nombreux membres, listés dans un fichier txt.

Donc je me reprend

nous avions en sha1
$nom1=$_POST["ID"];
$passe1=sha1($_POST["password"])

je transpose (mal?) pour password_hash en
$nom1=$_POST["ID"];
$passe1= password_hash($_POST["password"], PASSWORD_DEFAULT);
$passwordValid = password_verify($password, $passe1);

ensuite le code est inchangé pour vérifier la validité de ID/PW/date...

$lignes=file("fichieravecIDtabPWhashtabdate.txt");
$membre=0;
$regex="#$nom1\t$passe1#";
foreach ($lignes as $lgn)
{

if(preg_match($regex,$lgn, $tab))
{
$champ = preg_split('#\t#',$lgn);
$date = $champ[2];

quand je teste, il n'accepte pas le PW haché avec password_hash et me vire sur la page d'erreur, alors que quand j'utilise le PW haché avec sha1 tout baigne (y compris sur Internet)

donc j'en conclus que ma compréhension de la transposition des variables, que tu as expliquées pour un cas, n'est pas la bonne avec notre fichier txt.

Est-ce que c'est çà?

Bon je ne me décourage pas et je me demande si ce n'est pas dans la suite du code valide pour sha1 qu'il y aurait un problème...

Donc je modifie la ligne ci-dessus

$regex="#$nom1\t$passe1#";

en:

$regex="#$nom1\t$passwordValid#";

Et là un bon ID/PW me fait rentrer dans l'espace membres, et, un mauvais ID et bon PW me vire vers error... mais mais fausse joie:

quand je tape un bon ID, un faux PW je rentre tout de même dans l'espace membres, donc c'est pas bon...

Je suis bien dans le forum débutant donc c'est bien moi qui ait faux, pas notre code avec sha1 fait par un tiers il y a au moins 10 ans!

A+ et merci de ta patience et de ton aide,

Mammouth du PHP | 1645 Messages

09 déc. 2019, 16:36

Ta logique n'est pas bonne

C'est dans ta boucle qu'il te faut utiliser password_verify

A l'interieur de la boucle il faut que tu cherche uniquement le login et puis vérifier le password.
$lignes=file("fichieravecIDtabPWhashtabdate.txt");
$membre=0;
$regex="#$nom1#";
foreach ($lignes as $lgn)
{

if(preg_match($regex,$lgn, $tab))
{
$champ = preg_split('#\t#',$lgn);
if (!pawsword_verify($champ[1],$passe1)) continue;//Si le mot de passe n'est pas vérifié, on passe à la ligne suivante en cas de double login sinon un break marche aussi
$date = $champ[2];
...
Je fait une supposition sur le format de ton fichier fichieravecIDtabPWhashtabdate.txt mais au vu du code fourni elle doit être juste.
Spols
pour les fan de rubik's cube ou pour les curieux ==> le portail francophone de rubik's cube

Eléphanteau du PHP | 29 Messages

10 déc. 2019, 16:44

Bonjour Spols,

Je comprend mieux et cela me semble logique (même si je n'y aurais pas pensé).
Merci!
J'ai comparé les 2 codes (le nôtre ancien en sha1 et le tien).
En dehors du code nouveau
if (!pawsword_verify($champ[1],$passe1)) continue;

il y a une autre différence au niveau de la variable regex...
nous
$regex="#$nom1\t$passe1#";
toi
$regex="#$nom1#";

mais dans les 2 cas en testant le code sur wamp localhost et sur Internet, j'ai la même erreur:
Fatal error: Call to undefined function pawsword_verify() in D:\test.php on line 59

et la ligne 59 est:
if (!pawsword_verify($champ[1],$passe1)) continue;

je ne vois pas d'erreur pourtant.
Sauf si il y a un souci avec $champ[1]... mais non car il y a champ[2]... sauf si cela aurait dû être champ[2] puis champ[3]????

Le fichier txt est bien du type:
Spols tab ilfaitbeau tab 2019-12-31
Bof333 tab ilpleut tab 2019-12-31


Bon pour être clair voici la partie du code concerné

$nom1=$_POST["ID"];
//$passe1=sha1($_POST["password"]); //ancien code bon avec sha1
$passe1= password_hash($_POST["password"], PASSWORD_DEFAULT); //cryptage en password_hash

// les codes sont-ils vides ?
if (($nom1=="") or ($passe1==""))
{
header("Location: $error");
}
else
{

// verification des codes
$lignes=file("fichieravecIDtabPWhashtabdate.txt");

$membre=0;
//$regex="#$nom1\t$passe1#"; //ancien code bon avec sha1
$regex="#$nom1#";
foreach ($lignes as $lgn)
{
if(preg_match($regex, $lgn, $tab))
{
$champ = preg_split('#\t#',$lgn);
if (!pawsword_verify($champ[1],$passe1)) continue;//Si le mot de passe n'est pas vérifié, on passe à la ligne suivante en cas de double login sinon un break marche aussi
$date = $champ[2];

En tout cas avec ce message d'erreur j'ai l'impression que l'on approche du but.
Merci encore!

A+

Seb

Eléphant du PHP | 164 Messages

10 déc. 2019, 22:57

L'erreur est assez précise : Fatal error: Call to undefined function pawsword_verify() in D:\test.php on line 59
La fonction s'appelle password_verify et non pawsword_verify
Cordialement
Naroth

Mammouth du PHP | 1645 Messages

11 déc. 2019, 09:32

Hello,

Oui j'ai du tapé trop vite et mis un w à la place d'un s.

les 2 modifications ont bien été identifié.
au niveau de la regex, il s'agit de chercher uiquement sur le login et plus sur la paire login/pass
car avec l'utilisation de password_hash il n'est plus possible de connaitre le hash
Du coup aprés une vérification du login, il faut vérifier le mot de passe avec password_verify et si il est pas bon sortir/continuer la boucle.

j'ai mis un continue; qui fait que la boucle passe à la ligne suivante. donc si il existe plusieurs lignes avec le même login mais un mot de passe différent, la boucle trouvera la bonne ligne pour se connecter.
si ce cas de figure ne peux pas arriver, remplacer le continue par un break fera en sorte de sortir de la boucle. il pourrait y avoir un très léger gain de performance dépendant de la longueur de la liste.
Spols
pour les fan de rubik's cube ou pour les curieux ==> le portail francophone de rubik's cube

Eléphanteau du PHP | 29 Messages

11 déc. 2019, 17:54

Bonjour Spols,

Oh, j'étais tellement tendu sur le problème de code que je n'ai pas vu la coquille (j'aurais dû passer le code à mes collègues et peut-être auraient ils vu le souci!).
Bon... ma faute... mais hélas cela ne suffit pas.
Avec la correction il n'y a plus aucun message d'erreur.
J'ai testé en ligne avec 3 bons ID/PW/Date, à chaque fois j'atterris sur ma page d'erreur, que ce soit en localhost ou sur Internet.
J'ai aussi testé 1 bon ID et un mauvais PW et 1 mauvais ID et un bon PW et à chaque fois j'atterris aussi sur ma page d'erreur.

Pourtant le code avec sha1 continue à bien fonctionner sur Internet comme d'hab, donc cela vient bien du remplacement de sha1 par password_hash!

Je ne sais pas si cela te dis quelque chose???

Est-ce dû au fait que nous passons par un intermédiaire (fichier txt) et que nous hashons les PW (et avec ce procédé et password_hash le fichier généré est chaque fois différent, alors que avec sha1, il est toujours pareil, bien sûr si la liste avant hashage ne change pas).

Le fichier qui permet de générer les PW hashés via Internet est, je le rappelle, le suivant (le code pour sha1 est désactivé):
<?php

if(file_exists('listemembres.txt'))
{
    $nom_fichier = 'listemembres.txt';
    $fichier = file($nom_fichier);

    $new_fichier = fopen('listemembres.encrypted.txt','w+');

    foreach($fichier as $ligne)
    {
        $tab = preg_split('#\t#',$ligne);
        fwrite($new_fichier, $tab[0]."\t".password_hash($tab[1],PASSWORD_DEFAULT)."\t".$tab[2]);
        //fwrite($new_fichier, $tab[0]."\t".sha1($tab[1])."\t".$tab[2]);
    }
    fclose($new_fichier);
    unlink('listemembres.txt');
}
J'imagine qu'en tant qu'expert, ce micmac doit te titiller les neurones!

Bon, toujours merci.. eh bien A+, j'espère!

Seb (PS, je suis nul en rubikscube! et merci à Naroth aussi!)
Modifié en dernier par Ryle le 12 déc. 2019, 12:46, modifié 1 fois.
Raison : Lisibilité : ajout des balises [php]

Mammouth du PHP | 1645 Messages

11 déc. 2019, 19:22

tu dois avoir les mot de passe en clair pour créer le nouveau fichier.
là il me semble que tu part des mot de passe hashé en sha1 du coup ca peut pas marcher.
Spols
pour les fan de rubik's cube ou pour les curieux ==> le portail francophone de rubik's cube