[RESOLU] Protection formulaires.

Eléphant du PHP | 290 Messages

11 déc. 2014, 12:28

Bonjour,

Merci AB pour ces explications complémentaires :D
Je comprends mieux!!

J'ai réussi sans aide mon programme Ajax qui fonctionne très bien, ce qui est plutôt un miracle :D

Je récupère donc le sable de l'utilisateur une fois que ce dernier (moi dans les phases d'essai),
après avoir rentré son nom d'utilisateur, place le curseur à un autre endroit qu'à l'intérieur du champs du nom d'utilisateur.
Je le récupère via un champs caché.

Je crée dans la foulée un sable aléatoire.
A ce propos j'aurais une question.
Dans ton tuto, tu appelles ce champs $_SESSION["sel"]
J'imagine bien qu'on l'appelle comme on veut mais ce qui m'interpelle
c'est le tableau intégré $_SESSION
N'est-il pas possible par exemple d'appeler mon sel aléatoire
$sel_aleatoire
?
Est-ce obligatoire de passer par un tableau intégré $_SESSION pour la nomination de mon sel?
Ce genre de tableau intégré m'a déjà servi dans un espace de sessions pour récupérer
automatiquement une variable d'un page à l'autre.
Je devine donc un peu pourquoi tu l'utilises mais je dois avouer ne pas maîtriser parfaitement son sens.
Il peut s'utiliser aussi en dehors des session malgré son nom, et sans générer non plus le moindre problème niveau sécurité?

ViPHP
AB
ViPHP | 5818 Messages

11 déc. 2014, 17:36

Le sel est enregistré dans une variable de session pour pouvoir le récupérer après l'envoi du post.

Sinon sur le principe tu reprends le code donné ici sauf qu'il faut modifier la fonction doChallengeResponse(form) et un peu le code php.

Dans la fonction doChallengeResponse(form) avant de créer la variable str qui sera transmise au formulaire, tu fais une requête ajax en envoyant le login pour rapatrier le sel correspondant en bdd (tu devrais vérifier cette étape avant de poursuivre).

Une fois le sel de bdd récupéré il te suffit de construire le hash de la chaine complète avec var str = hash('<?= $_SESSION["sel_aleatoire"] ?>'+hash(mot de passe+sel_bdd)).
La suite est identique, tu envoies "str" dans le formulaire dans le champ "reponse", tu efface la valeur du mot de passe dans le formulaire et tu soumet le formulaire.

Côté php quand tu reçois le formulaire tu fais une requête en fonction du login qui retourne la valeur "hash(mot de passe+sel_bdd)". Et donc tu te sert du sel aléatoire défini et enregistré dans la variable de session pour construire hash($_SESSION["sel_aleatoire"] + hash(mot de passe+sel_bdd)) que tu compare à la valeur de $_POST['reponse'].

Eléphant du PHP | 290 Messages

11 déc. 2014, 19:22

Merci encore pour ton aide :D
Dans la fonction doChallengeResponse(form) avant de créer la variable str qui sera transmise au formulaire, tu fais une requête ajax en envoyant le login pour rapatrier le sel correspondant en bdd (tu devrais vérifier cette étape avant de poursuivre).
C'est vérifié. Mon Ajax fonctionne parfaitement, j'ai le sel utilisateur en bdd rapatrié sur mon fichier avant le code de la fonction doChallengeResponse(form).
Côté php quand tu reçois le formulaire tu fais une requête en fonction du login qui retourne la valeur "hash(mot de passe+sel_bdd)". Et donc tu te sert du sel aléatoire défini et enregistré dans la variable de session pour construire hash($_SESSION["sel_aleatoire"] + hash(mot de passe+sel_bdd)) que tu compare à la valeur de $_POST['reponse'].
Cette partie je ne l'ai pas encore préparé mais ça à l'air très simple.

En revanche, la partie en js à l'air très compliquée, surtout quand le php et le js sont en relation l'un avec l'autre. 8-|
J'ai aussi du mal à adapter cette partie à mon formulaire déjà existant.
Là je dois dire avoir besoin d'aide... :priere:

Déjà, je sépare les fichiers: un fichier pour le formulaire et un autre pour le traitement du formulaire.
J'ai un petit niveau et je préfère donc éviter le 2 en 1.

Je vais poser des questions concises:

1) Par rapport à:
[javascript]
var str = form.utilisateur.value+'<?php echo $_SESSION["sel"]?>'+form.mot_de_passe.value;
[/javascript]
si j'ai un attribut name="visiteur" pour mon input du nom d'utilisateur et
un attribut name="mdpasse" pour mon input du mot de passe
dois-je remplacer le code js de la manière suivante:
[javascript]
var str = form.visiteur.value+'<?php echo $_SESSION["sel"]?>'+form.mdpasse.value;
[/javascript]
?

2) J'ai d'autres champs dans mon formulaire, dont un pour le captcha.
J'ai aussi déjà un bouton submit et un bouton reset.
Est-ce-que je peux supprimer la ligne
[javascript]
form.submit();
[/javascript]
?
Il m'est effectivement plus logique de poster ma variable form.reponse.value
par le bouton dédié à tout mon formulaire.

3) Si dans ma page de formulaire j'écris:
var str = form.login.value+'<?php echo $salt ?>'+form.password.value; //dans ma fonction ou en dehors, ça ne change rien dans les deux cas
<input type="text" name="str"/>
et dans ma page de traitement de formulaire j'écris:
$str=$_POST['str'];
echo $str;
mon echo $str; ne permet aucun affichage.
Je n'arrive pas à envoyer la variable $str dans les tuyaux.
Je ne sais pas si tu peux me dire comment faire si tu sais car je dois dire sécher complètement?

4) A propos de form. quelque chose
on retrouve plusieurs fois form. quelque chose dans la fonction js
exemple:
form.mot_de_passe.value
Suffit-il que la fonction js se trouve entre les balises <form> et </form>
de mon formulaire écrit en html, je le précise, pour que tous
les form.quelque chose soient référé à mon formulaire.

5) L'utilité de mettre le code js dans une fonction ici est de pouvoir retourner false
sinon à part ça on peut s'en passer.
C'est juste?

6) Enfin, si je peux poser une dernière question pour aller au fonds des choses,
je ne comprends pas pourquoi dans le code suivant seule la première variable
est précédée d'un var:
[javascript]
var str = form.utilisateur.value+'<?php echo $_SESSION["sel"]?>'+form.mot_de_passe.value;
form.reponse.value = SHA256(str);
form.mot_de_passe.value = "";
[/javascript]
Je croyais d'abord que toute variable en js était précédée de var.
=> dans ce cas pourquoi pas de var devant les deux autres?
Puis en me documentant un peu il semblerait qu'on ajoute var quand il est question d'une variable globale seulement.
=> dans ce cas pourquoi la première variable est précédée d'un var alors que les trois variables sont toutes dans une fonction?

Si tu peux répondre à ces quelques questions ça m'aiderait énormément :D

ViPHP
AB
ViPHP | 5818 Messages

11 déc. 2014, 21:21

Et oui tu n'as pas suffisamment de bases en javascript pour comprendre le code. Faudrait faire plus de tutos...

"form.utilisateur.value" tout comme "form.mot_de_passe.value" ne sont pas des variables javascript mais les valeurs des champs "utilisateur" et "mot_de_passe" du formulaire. Et suivant les cas on récupère ces valeurs ou on les défini avec "=".

Par ailleurs il FAUT DISSOCIER LES PROBLEMES ! Fais ton authentification complète et quand elle fonctionnera tu incluras le chapta (mais pas avant).

Montres-nous d'abord ta fonction "doChallengeResponse" complète ainsi que la partie html du formulaire : <form.... </form>. Uniquement ces bouts de code et rien d'autre. Simplifies au maximum, comme déjà dit je veux pas voir d'input concernant le chapta dans un premier temps.

Eléphant du PHP | 290 Messages

12 déc. 2014, 11:06

Bonjour,

Je t'ai envoyé un mp.

ViPHP
AB
ViPHP | 5818 Messages

12 déc. 2014, 20:19

Nan :evil:
Les messages doivent pouvoir être compris par tout le monde, c'est l'intérêt d'un forum.

Et au passage ta requête ajax doit être à l'intérieur de la fonction doChallengeResponse(form) et simplement retourner la valeur du sel fixe en fonction du login qui est "form.login.value". Donc oublies ton "...addEventListener('blur'..." puisque tu as déjà la valeur du login et il ne sert à rien de transférer la valeur du sel fixe dans le formulaire.

Eléphant du PHP | 290 Messages

12 déc. 2014, 23:40

Bon, je ne peux pas revoir ça tout de suite.

Mais je voudrais te demander en attendant s'il n'existe pas de tutos qui apprennent
à mettre en relation les différents langages et comment les mettre en relation?
Car j'ai beau apprendre de manière isolée le html, le css, le JavaScript, le php et le sql,
quand il s'agit de mettre du code de l'un dans du code de l'autre (du php dans du js, du js dans du php,
du js dans de l'html,...) les choses sont tout de suite plus dures à appréhender:
je ne peux pas trop improviser comment faire le lien entre les deux langages concernés en fonction
de ce que sont ces deux langages et de la relation qui les unit.

Je crois que ça c'est la plus grosse difficulté que je rencontre.

ViPHP
AB
ViPHP | 5818 Messages

13 déc. 2014, 00:26

Pour insérer une variable php dans du javascript il te suffit de faire un echo. C'est d'ailleurs dans l'exemple du code qu'il faut que tu mette en place et que je t'ai indiqué ici (le <?= est une forme raccourcie de <?php echo).
var str = hash('<?= $_SESSION["sel_aleatoire"] ?>'+hash(mot de passe+sel_bdd));
(donc oublies le "var str = form.login.value+'<?php echo $salt ?>'+form.password.value;" de l'ancien code qui n'utilisait pas de sel de bdd)

Sinon tu avais dit que ta requête ajax retournait correctement le sel bdd en fonction du login... ben alors tu devrais pas être loin de la solution puisque le mot de passe est égal à "form.mot_de_passe.value". Il ne te manque plus rien pour écrire correctement "str".

Souviens-toi juste que le code ci-dessus est là pour le principe, il ne suffit pas de le copier, il faut l'adapter. Il te faut absolument comprendre ce que tu fais. Par exemple la fonction hash se nomme SHA256 dans mon script.

Pendant le développement fais un "alert(str);" après la définition de str pour vérifier si cela ressemble à un résultat attendu (en l'occurrence une chaine alphanumérique de 64 caractères avec le sha 256).

Eléphant du PHP | 290 Messages

13 déc. 2014, 00:52

Merci encore :D

Mais Attends, attends,...
avec les précisions que tu viens de m'apporter et une relecture du long code
que tu m'as montré il y a un certain temps des choses se débloquent dans ma tête.

Il faut que je réfléchisse et que je relise encore.
J'ai moi-aussi l'impression d'arriver au bout de ce que je veux faire!

Je vous redonne des nouvelles :)

Eléphant du PHP | 290 Messages

16 déc. 2014, 17:10

Concernant l'Ajax, j'ai supprimé le gestionnaire d'événement => addEventListener

J'ai mis une feuille js externe avant ma fonction doChallengeResponse, comme ceci:

[javascript]
<script src="programmeAjax.js"></script> <!-- programme Ajax -->
<script language="javascript">
function doChallengeResponse(form) {

var str = form.login.value+'<?php echo $salt ?>'+form.password.value;
form.reponse.value = SHA256(str);
form.password.value = "";

// 64 correspond à la longueur d'un sha 256 (condition à modifier si l'on change d'encodage)
if (form.mot_de_passe.value == '' && form.reponse.value.length == 64)
{
form.submit();
}
else return false;
}
</script>
[/javascript]

J'ai alors adapté mon programme Ajax avec une fonction initialisation
qui s'exécute dès que le programme est lu et une fonction enclenchementAJAX
qui enclenche le programme AJAX via l'événement onbLur comme son nom l'indique:

[javascript]
function initialisation (){
document.getElementById("login").onblur = enclenchementAJAX;
}

function enclenchementAJAX() {
// variable qui récupère l'objet requête
// variable qui récupère la valeur de login saisie avant la perte du focus (événement onblur)

// mon paramètre onreadystatechange pour vérifier le statut et l'état de ma requête,
// suivi de mon innerHTML qui remplacera la valeur entre les div (je n'y ai rien mis, donc rien) dans mon fichier d'authentification par
// la réponse construite dans mon fichier php de réponse du serveur, qui n'est rien de plus que le grain de sable récupéré en bdd
// par le code SQL écrit dans ce même fichier php de réponse du serveur.

// méthde open avec $_POST choisi comme premier paramètre
// méthode setRequestHeader indispensable pour envoyer des données via le tableau $_POST (spécifie le nom de l'entête)
// méthode send avec comme variable à envoyer le login saisi par l'utilisateur
// appel à la fonction construite pour le onreadystatechange => voir troisième double slash
[/javascript]

Tu vois que je mets mon lien externe qui dirige vers la feuille js pour l'AJAX juste avant la fonction doChallengeResponse
et non à l'intérieur.

Est-ce indispensable de la mettre à l'intérieur?
Si oui, tu pourrais m'expliquer pourquoi? Car obligatoire pour pouvoir s'intégrer à la concaténation à la variable str dans la fonction?

Je te montre comment je m'y prends pour mettre cette ligne de code à l'intérieur:
[javascript]
<script language="javascript">
function doChallengeResponse(form) {
</script>
<script src="programmeAjax.js"></script> <!-- programme Ajax -->
<script language="javascript">
var str = form.login.value+'<?php echo $salt ?>'+form.password.value;
form.reponse.value = SHA256(str);
form.password.value = "";

// 64 correspond à la longueur d'un sha 256 (condition à modifier si l'on change d'encodage)
if (form.mot_de_passe.value == '' && form.reponse.value.length == 64)
{
form.submit();
}
else return false;

}
</script>
[/javascript]

Ca me fait écrit beaucoup de balises script.
Mais c'est la manière de coder qui me paraît la plus logique.
C'est juste?

Eléphant du PHP | 290 Messages

16 déc. 2014, 17:22

Je signale à tout lecteur qui peut être intéressé par mon code que dans mon programme Ajax, il maque une ligne
devant ma fonction initialisation:
[javascript]
window.onload = initialisation;

function initialisation (){
...
[/javascript]

window.onload permet d'initialiser la fonction initialisation :wink:

ViPHP
AB
ViPHP | 5818 Messages

16 déc. 2014, 18:45

Salut,

Oula, c'est du grand art ! :mrgreen: :roll: |*()

Je croyais pourtant avoir été clair :
Et au passage ta requête ajax doit être à l'intérieur de la fonction doChallengeResponse(form) et simplement retourner la valeur du sel fixe en fonction du login qui est "form.login.value". Donc oublies ton "...addEventListener('blur'..." puisque tu as déjà la valeur du login et il ne sert à rien de transférer la valeur du sel fixe dans le formulaire.
Et pourquoi ??? veux tu déclencher ta requête ajax sur un comportement onblur pour récupérer le login puisque tu as déjà le login dans la fonction doChallengeResponse et que sa valeur est "form.login.value". Donc suis ce principe :
<script language="javascript">
function doChallengeResponse(form) {

1/ récupération des variables :
var login = form.login.value;
var pass = form.mot_de_passe.value;

2/ Requête ajax :
ICI requête ajax qui envoie login et récupère le sel correspondant en bdd
var sel_bdd = reponse ajax

3/ Construction de la réponse du formulaire
Construction de str avec les variables pass, le sel aléatoire php (<?php echo $salt?>) , et sel_bdd qu'on vient de récupérer. Le tout mis dans le bon ordre et hascher suivant la même procédure qu'en php pour pouvoir comparer avec le hash stocké en bdd.

4/ Transfert de str dans le champ réponse du formulaire

5/ Effacement de la valeur du champ pass du formulaire

6/ Envoi du formulaire
}
</script>

Essaies de mettre ça en oeuvre (et pas d'improvisation).

Eléphant du PHP | 290 Messages

16 déc. 2014, 19:48

Bonjour et merci encore :D

Je suis bien sûr d'accord pour suivre les étapes que tu proposes,
mais il y a quelques points qui sont encore obscurs pour moi:

a)
il ne sert à rien de transférer la valeur du sel fixe dans le formulaire.
C'est pourtant bien ce que tu proposes de faire en 2/:
2/ Requête ajax :
ICI requête ajax qui envoie login et récupère le sel correspondant en bdd
var sel_bdd = reponse ajax
b)
pourquoi ??? veux tu déclencher ta requête ajax sur un comportement onblur pour récupérer le login puisque tu as déjà le login dans la fonction doChallengeResponse et que sa valeur est "form.login.value".
Oui, mais pourquoi est-ce que je l'ai déjà?
Uniquement et simplement parce-que l'utilisateur l'a rentré dans le formulaire.
C'est la seule raison.
Et moi avec l'événement onblur je récupère bien ce même nom d'utilisateur que ce dernier a rentré via le champs de formulaire.
Donc pour moi récupérer le nom d'utilisateur avec l'événement onblur dans mon Ajax ou utiliser l'Ajax de façon différente pour récupérer le nom d'utilisateur
(qui permet d'aller chercher le grain de sel fixe) c'est blanc bonnet ou bonnet blanc.
Pour te dire, en venant de terminer 1/ et 2/ (sans changer mon programme Ajax), je me retrouve avec mes trois variables, dans l'ordre:

var login = form.login.value;
var pass = form.mot_de_passe.value;
et
var sel_bdd => reponse ajax

et ça marche. Mon sel fixe est bel et bien présent en troisième position comme souhaité grâce à mon Ajax.

Donc je ne vois pas où il peut y avoir un soucis.

c)
Construction de str avec les variables pass, le sel aléatoire php (<?php echo $salt?>) , et sel_bdd qu'on vient de récupérer. Le tout mis dans le bon ordre
Pour être plus précis sur le bon ordre, tu veux dire par variables pass, dans l'ordre, var login et var pass?
Ou bien var login, sel aléatoire, var pass et sel fixe?

ViPHP
AB
ViPHP | 5818 Messages

17 déc. 2014, 06:19

Salut,

1/ Non je n'envoie pas le sel fixe (de bdd) dans le formulaire, je m'en sert pour construire la chaine str, c'est à dire le hash qui sera envoyé dans le champ "reponse" du formulaire.

2/ Il ne sert à rien de récupérer le login avant l'envoi du formulaire, donc quand on peut faire simple... En plus tu risque de gros problèmes de synchronisation de ton code en jouant avec deux événements différents. Fais comme je te dis pour que tout se passe bien.

3/ Dans le bon ordre pour construire la chaine str dont je t'ai parlé plusieurs fois

Eléphant du PHP | 290 Messages

17 déc. 2014, 17:32

Bonjour,

Pour 1/ oui, j'avais pas compris que tu entends par transférer envoyer, poster.
2/ Je suppose donc que je garde seulement onload, je n'utilise pas onblur.
3/ Ok

Par rapport à mon niveau, le code que tu m'as montré est très difficile.
Faire tout d'un bloc, je ne vais pas y arriver.
Je n'arrive même pas à soumettre le formulaire.
C'est pour cela que je pense essayer de comprendre chaque chose par étape,
en simplifiant au maximum et en séparant sur deux feuilles ce qui est le formulaire en soit
et ce qui est le traitement du formulaire.

J'écris une page de formulaire nommée page_1.php:

[javascript]
<title>Identification avec mot de passe hashé et grain de sel aléatoire</title>

<script language="javascript">
<!--
function doChallengeResponse(form) {

var str = form.utilisateur.value+form.mot_de_passe.value;
form.reponse.value = SHA256(str);
form.mot_de_passe.value = "";

// 64 correspond à la longueur d'un sha 256 (condition à modifier si l'on change d'encodage)
if (form.mot_de_passe.value == '' && form.reponse.value.length == 64)
{
form.submit();
}
else return false;

}
// -->

</script>

</head>
<body>

<form name="identification" method="post" action="page_2.php">
<p>
Utilisateur:
<input type="text" name="utilisateur" size="32" maxlength="32"><br>
Mot de passe:
<input type="password" name="mot_de_passe" size="32" maxlength="32"><br>

<input onclick="doChallengeResponse(this.form); return false;" type="button" value="identification">
<input type="hidden" name="reponse" value="">
</p>
</form>

</body>
[/javascript]

et une page page_2.php de traitement de formulaire:
<?php
echo "j'ai réussi à attenidre la feuille de traitement de formulaire";
?>
Je n'arrive donc même pas à aller sur la page de traitement de formulaire.

Est-ce que tu pourrais m'aider à comprendre ce qui ne va pas? :priere:
J'ai toujours créé des formulaires avec un input pour le bouton soumettre avec type=submit".
Ajouté à cela la complexité de l'assemblage des deux feuilles de formulaire et traitement de formulaire,
je n'y retrouve plus mes petits.