[RESOLU] Protection formulaires.

Eléphant du PHP | 290 Messages

10 nov. 2014, 15:00

Bonjour AB,

Je te remercie pour la méthodologie :D
C'est ce qui me manquait le plus!
D'ailleurs, j'ai lu et appris tout ton tuto, suite à quoi j'ai résolu mon problème avec extract :D

J'ai d'autres problèmes avec ma session et mon formulaire,
mais je vais d'abord opter pour faire des tutos dessus et faire des révisions.

Même si vous me donniez la solution de mon prochain problème, suite à ça je suis sûr
que j'aurais plein d'autres problèmes pour lequels je chercherais des solutions sans grand résultat,
pendant x heures.

Je change don de fusil d'épaule et vous donne des nouvelles un peu plus tard :)

Eléphant du PHP | 290 Messages

11 nov. 2014, 17:41

Bonjour,

J'ai encore pu réglé un problème :D
Ca va beaucoup mieux :D

J'ai encore un problème de réaffichage de valeurs mais le problème est très identifié :D
Je me permets de vous poser une question très précise, sans qu'il y ait besoin de connaitre
l'historique de ce message pour me répondre (juste de vos connaissances, ce qui est en fait énorme :D ).

Dans une session j'ai un formulaire.
Je veux que lorsque l'utilisateur le valide en oubliant de remplir un ou plusieurs champs,
une boîte de dialogue modale javascript le renvoit sur le formulaire en indiquant qu'il manque un ou plusieurs champs,
et que lorsqu'il revient sur le formulaire celui-ci est pré-rempli avec ce qu'il avait déjà rempli la première fois.
Mon problème: suite à la redirection js qui par ailleurs fonctionne parfaitement, le formulaire est vierge/effacé.
La source du problème est identifiée:
sur mon fichier de traitement de formulaire, juste avant le code de la boîte modale
les variables _POST['champs1'], $_POST['champs2'], $_POST['champs3'], ... sont définies et sont
bien remplies avec les valeurs passées par l'utilisateur.
Sur le formulaire (de retour suite à la redirection), elles n'existent plus (donc je ne risque pas de les réafficher).
Elles ont disparu entre la page de traitement de formulaire et celle du formulaire.
Il est écrit dans le tuto de Le PHP Facile (qui par ailleurs est un excellent tuto):
toutes les variables enregistrées au cours de notre session, seront accessibles dans les pages de notre session.
La disparition des données a lieu même si j'essaye de remplacer la boîte de dialogue modale js par un header en php
(je sais qu'un header n'empêche pas des variables de passer d'une page à l'autre).

J'en arrive donc à me demander si dans une session il est impossible de faire passer des variables dans une certaine
page à une page qui la précède.
Savez-vous quelque chose là-dessus? (c'est ma question)

ViPHP
AB
ViPHP | 5818 Messages

12 nov. 2014, 06:17

Si tu as des pertes de session d'une page à l'autre, c'est que tu n'a pas déclaré session_start() avant de définir ou de récupérer tes variables de session (ou alors tu les efface par inadvertance dans ton code).

Sur le principe pour conserver les données après retour du formulaire
<?php
session_start();
if(isset($_POST['envoyer']))
{
//traitement du formulaire ... 
//...

// et enregistrement des variables post en session
$_SESSION['nom'] = $_POST['nom'];
}
?>
...html
<input type = "text" name ="nom" value="<?= isset($_SESSION['nom']) ? $_SESSION['nom'] : null; ?>" />

Eléphant du PHP | 290 Messages

12 nov. 2014, 13:08

Merci AB!
J'ai trouvé le problème grâce à ton aide :D

Dans ma page de traitement de formulaire j'ai rajouté une ligne:
$_SESSION['ma_variable']=$_POST['ma_variable'];

et dans mon formulaire j'ai changé mes tableaux intégrés ainsi:
=>avant (dans mes attributs value)
<?php if(isset($_POST['ma_variable'])) { echo htmlentities($_POST['ma_variable'], ENT_QUOTES, 'UTF-8');}; ?>
=>après (dans mes attributs value)
<?php if(isset($_SESSION['ma_variable'])) { echo htmlentities($_SESSION['ma_variable'], ENT_QUOTES, 'UTF-8');}; ?>
Le tableau $_POST me permet de faire passer les variables de ma page de formulaire à ma page de traitement de formulaire.
Mais apparemment il ne me permet pas l'inverse.
Par contre le tableau $_SESSION lui permet apparemment de faire passer n'importe quelle variable
de n'importe quelle page de la session sur n'importe quelle autre page de la même session.
Mais je n'ai pas trouvé jusque là de tuto qui me parle de ce point avec autant de concision.

La dernière chose qui me reste à faire est la programmation d'un hashage avec des grains de sable,
mais je pense pouvoir m'en sortir.
Par rapport au code que tu m'as donné là-dessus, je préfère dans une session
éviter de déplacer de page en page le mot de passe, hashé ou non.
C'est-à-dire déplacer uniquement l'identifiant et le nom d'utilisateur de l'utilisateur.
Que j'y arrive ou non, je vous donnerai des nouvelles et je mettrai le message en RESOLU
quand ce sera le cas.

ViPHP
AB
ViPHP | 5818 Messages

12 nov. 2014, 17:12

Salut,

Tu peux utiliser htmlspecialchars à la place de htmlentities. C'est suffisant pour la protection des données d'affichage et cela t'évitera d'avoir besoin de spécifier l'encodage utf_8.
<?php if(isset($_SESSION['ma_variable'])) echo htmlspecialchars($_SESSION['ma_variable']); ?>
Par rapport au code que tu m'as donné là-dessus, je préfère dans une session
éviter de déplacer de page en page le mot de passe, hashé ou non.
C'est-à-dire déplacer uniquement l'identifiant et le nom d'utilisateur de l'utilisateur.
Dans les tutos ou codes que je t'ai donné, à aucun moment le mot de passe n'est enregistré dans une variable de session...

Eléphant du PHP | 290 Messages

12 nov. 2014, 18:08

Salut,

Merci.
En fait, j'ai vu dans ton code
$_SESSION["sel"]
et j'ai donc pensé que tu souhaitais retrouver ta variable où tu voulais sur la session.
Mais ce message sur le salage je n'avais pas encore travaillé dessus à ce moment-là.

J'y reviendrai si je n'arrive pas à faire mon programme avec des tutos sur le salage que j'avais vu avant ton premier
message et que je voudrais tester.

ViPHP
AB
ViPHP | 5818 Messages

12 nov. 2014, 23:06

Le sel c'est une variable "aléatoire" unique qui est passée dans le formulaire et concaténée au mot de passe en javascript puis hashée (toujours en javascript) avant d'être envoyée vers le serveur dans le post. A réception on compare avec la même routine en php. Ainsi le post ne contient pas le mot de passe mais le hash(sel+mdp). Cela complique la tâche des éventuels pirates qui ne peuvent pas se servir de dictionnaire de hash (si le mdp était passé simplement hashé mais sans sel) mais doivent refaire une nouvelle table de correspondance en tenant compte du sel ce qui demande une très grosse puissance de calcul (et du temps).

Mais dans l'absolu même avec un sel c'est pas impossible à "décoder" en quelques quelques jours (voir moins) avec du travail collaboratif (plusieurs centaines ou milliers d'ordinateurs qui font chacun une partie du travail). Si bien qu'on préfère quand c'est possible une connexion ssl où tout le message est crypté.
Mais bon on peut commencer par le script salé qui sera compatible avec une connexion ordinaire puis garder le même script si on passe en ssl, ce qui fait une double protection.

Eléphant du PHP | 290 Messages

13 nov. 2014, 00:26

Salut,

Je vais en fait d'abord regarder en détail ton code sur le salage et me renseigner sur les ssl que je ne connais pas,
ça à l'air très intéressant et j'ai le sentiment que ça va pas mal, voire beaucoup alimenter ma réflexion!

ViPHP
AB
ViPHP | 5818 Messages

13 nov. 2014, 19:57

Bah c'est assez simple puisque c'est suivant ton hébergement que tu peux avoir accès au ssl ou pas. C'est donc au moment de choisir ton hébergement qu'il faut faire attention à cette option.
Au niveau de ton code cela ne change rien. Juste savoir que tu auras des adresses en https://... à la place des http://..., et en cas de certificat ssl commun (par exemple le ssl gratuit des hébergements mutualisés OVH entrées de gamme) il est possible que ton nom de domaine ne soit pas inclus dans l'url. Pour dire qu'au niveau des adresses/liens internes de ton site il est largement préférable d'utiliser des adresses relatives si tu veux qu'elles fonctionnent dans tous les cas de figure.

Eléphant du PHP | 290 Messages

14 nov. 2014, 09:50

Merci pour l'info :D

Le ssl est donc le fameux https://
Et à priori je pourrais y avoir accès en demandant à mon hébergeur.

Je croyais que c'était des programmeurs de très haut niveau qui créaient des pages en https://
sûrement avec l'utilisation de langages hyper complexes comme Java ou C++
qu'ils maîtrisent sur le bout des doigts.

Très bon à savoir :D
Mais dans l'absolu même avec un sel c'est pas impossible à "décoder" en quelques quelques jours (voir moins) avec du travail collaboratif (plusieurs centaines ou milliers d'ordinateurs qui font chacun une partie du travail).
C'est la grosse artillerie lourde!!
Mais à ce point-là, ces gros pirates n'ont-ils pas intérêt à attaquer des sites bien plus gros que le mien qui, lui, de pas sa taille et son contenu ne leur apportera strictement rien?
=> si ce n'est le plaisir de m'enquiquiner, mais je pense qu'à ce stade les pirates cherchent à gagner de l'argent avec de la vente de base de données.

A propos de ces milliers d'ordinateurs dont tu parles, ils ne peuvent rien faire contre le https:// ?

ViPHP
AB
ViPHP | 5818 Messages

14 nov. 2014, 22:57

Et à priori je pourrais y avoir accès en demandant à mon hébergeur.
Non, pas à priori, car tous les hébergeurs ne proposent pas cette prestation et les conditions peuvent varier suivant les hébergeurs (certains peuvent proposer des certificats communs gratuits, d'autres pas, les prix pour un certificat individuel peuvent varier etc).
C'est la grosse artillerie lourde!!
Mais à ce point-là, ces gros pirates n'ont-ils pas intérêt à attaquer des sites bien plus gros que le mien qui, lui, de pas sa taille et son contenu ne leur apportera strictement rien?
Oui tu as tout à fait raison. Et donc pour des forums ou espaces d'administration de petits sites on peut se contenter d'une connexion http standard sans trop de soucis. Certains mêmes se contentent d'un hash sans sel mais là c'est plus dangereux car cela laisse la possibilité d'utiliser un dictionnaire déjà constitué. Enfin dans tous les cas la sécurité commence par avoir un mot de passe suffisamment long. Pour un espace administrateur on peut imposer un minimum de 10 caractères par exemple (surtout si la connexion n'est pas cryptée avec ssl).
A propos de ces milliers d'ordinateurs dont tu parles, ils ne peuvent rien faire contre le https:// ?
Non ce n'est pas le même principe. Sans la clé de décodage on ne peut pas en récréer une qui fonctionnera (du moins c'est l'objectif). A ma connaissance ceux qui pour l'instant ont réussi à pirater des liaisons ssl, ont piratés les fournisseurs de certificats. Dans cette hypothèse - quand même rarissime car le minimum que l'on demande pour l'accréditation de ces fournisseurs est de fournir des services très hautement sécurisés - on peut se dire que le hash avec grain de sable est une double protection, au cas où...

Ensuite et pour finir, le dernier point faible est l'appareil du visiteur. S'il est infecté par un keylogger, une personne malveillante pourra éventuellement récupérer ses frappes au clavier (entre autre quand il rempli son formulaire...). Pour ces raisons on voit souvent des authentifications par click sur un clavier virtuel dont l'organisation des touches change à chaque fois (au cas ou le keylogger enregistre aussi la position des click). On ne fait généralement cela que pour les banques car l'authentification est plus pénible pour l'utilisateur et pour que le piratage soit réussi cela suppose une négligence du poste de l'utilisateur qui auparavant doit s'être fait infecté par un virus.

Eléphant du PHP | 290 Messages

15 nov. 2014, 00:01

Donc pour moi proposer un mot de passe d'au moins 10 caractères et qui sera sablé avec des sables différents pour chaque utilisateur c'est déjà bien.

ViPHP
AB
ViPHP | 5818 Messages

15 nov. 2014, 00:41

Oui, juste une précision : le grain de sable envoyé dans le formulaire doit être différent à chaque envoi du formulaire (ce qui est le cas dans mon exemple plus haut). Sinon, sans même pouvoir connaître le mot de passe, on pourrait néanmoins s'authentifier en renvoyant simplement le contenu du post. Si donc tu as un sel fixe pour chaque visiteur pour sauvegarde en bdd par exemple, il n'est pas suffisant à lui seul pour assurer l'unicité de la connexion.
Donc avec un simple hash du mot de passe en bdd, le javascript doit renseigner le formulaire avec quelque chose comme :

Code : Tout sélectionner

hash(sel_unique_formulaire.hash(mot_de_passe))

et avec hash + sel en bdd :

Code : Tout sélectionner

hash(sel_unique_formulaire.hash(mot_de_passe.sel_unique_visiteur))
Et dans tous les cas javascript doit bien évidemment supprimer le contenu du champ "mot_de_passe" du formulaire avant l'envoi vers le serveur sinon tout cela ne sert à rien :wink:

EDIT : la seconde hypothèse suppose de devoir faire une requête ajax pour connaître le sel du visiteur en bdd en fonction de son login

Eléphant du PHP | 290 Messages

17 nov. 2014, 15:57

Salut,

J'ai mis un peu de temps avant de répondre car je suis encore tombé sur un problème.
Je pensais résoudre la chose en 2 minutes et voilà une semaine que je lis et relis des tutos sur différents sites,
que je regarde des livres et des définitions sur internet en vue de la résolution du problème mais rien à faire,
je n'y arrive vraiment pas malgré tous mes efforts :(

C'est à propos du réaffichage de cases à cocher sur un formulaire.
Même en essayant de réadapter le code du tuto de Cyrano sur php France je n'y arrive pas.

Je vais créer un message par rapport à mon problème.

En attendant, je vais lire attentivement ton message et travailler en parallèle sur mon hash.

Eléphant du PHP | 290 Messages

24 nov. 2014, 20:49

Bonjour,

Je reviens à mes moutons mais ton dernier message AB c'est difficile et j'ai besoin de te poser quelques questions de compréhension.
le grain de sable envoyé dans le formulaire doit être différent à chaque envoi du formulaire (ce qui est le cas dans mon exemple plus haut). Sinon, sans même pouvoir connaître le mot de passe, on pourrait néanmoins s'authentifier en renvoyant simplement le contenu du post.
Là où j'ai du mal à suivre, c'est quand tu parles du contenu du post dans le cas de l'utilisation d'un grain de sel fixe par utilisateur.
1. Il s'agit du hashage de la concaténation d'un grain de sel fixe avec un mot de passe que l'on a en bdd, n'est-ce pas?
2. C'est-à-dire que si l'on considère la concaténation d'un grain de sel fixe avec un mot de passe comme un simple mot de passe
un peu plus compliqué que d'ordinaire, une rainbow table suffit à décrypter l'ensemble, c'est bien ça?
Mais si quelqu'un arrive à ce stade, et qu'il envoi la valeur de la concaténation du mot de passe + grain de sable décrypté via le formulaire,
cet ensemble sera à nouveau concaténé au grain de sable avant d'être crypté, et à cause de cette deuxième concaténation au grain de sable,
et à cause de ça seulement, la valeur cryptée produite différera de la valeur hashée qui se trouve en bdd.
3. Tu veux dire que cette personne pourrait trouver le moyen de contourner cette deuxième concaténation au grain de sable?

En plus il y a un truc que je ne comprends pas.
Si on crée une concaténation automatique entre un mot de passe posté et un grain de sel aléatoire,
comment l'utilisateur pourrait-il être identifié comme ayant saisi le bon mot de passe?
L'ensemble hashage de mot de passe + grain de sable aléatoire en bdd ne sera jamais, sauf cas rarissime, égal
à hashage mot de passe posté + grain de sable aléatoire car le grain de sable aléatoire d'aujourd'hui et celui d'hier étant
différents, les deux valeurs hashées le seront aussi. Je ne vois donc pas comment l'utilisateur peut être reconnu
avec un grain de sable aléatoire.

Quant à
Et dans tous les cas javascript doit bien évidemment supprimer le contenu du champ "mot_de_passe" du formulaire avant l'envoi vers le serveur sinon tout cela ne sert à rien
Alors là je patauge :|
Il est bien question d'envoyer le hashage du mot de passe + grain de sel vers la bdd et pour cela l'utilisateur doit bien rentrer son mot de passe.
Ce mot de passe est juste en mémoire vive et sur l'ordinateur de l'utilisateur seulement.
4. Pourquoi ai-je besoin de javascript?
=> à propos il a l'air très compliqué le code javascript que tu m'a montré!!
Je te remercie pour tout, c'est juste que c'est un peu costaud :) !!
Mais je tiens bon :D

5. Puis-je poser une cinquième question (toujours en relation avec le message, mais avec le début du message)?
Ca commence à faire quelques questions mais ça m'aiderait vraiment beaucoup :D
C'est à propos de htmlentities (début de ce message).
Pour éviter de créer des failles xss, j'ai mis des htmlentities lors que j'ai des sorties navigateur.
A un endroit dédié à du texte, j'ai donc remplacé:
<textarea rows="4" cols="100" name="$ma_variable" maxlength="2000"><?php echo $ma_variable; ?></textarea>
par:
<textarea rows="4" cols="100" name="$ma_variable" maxlength="2000"><?php echo htmlentities($ma_variable, ENT_QUOTES, 'UTF-8'); ?></textarea>
Mail il apparaît un problème: les entités HTML apparaissent à l'écran, par exemple le é devient &eacute; et c'est la fonction qui crée ce changement.
Si j'enlève htmlentities j'ai bien alors é au lieu de &eacute; mais je veux éviter les failles xss.
C'est donc le navigateur qui ne fait plus le travail d'interpétation si je suis la logique de xTG:
Il reçoit des octets, qu'il convertie avec une table ASCII en caractère puis il interprète ces caractères avec la définition de la syntaxe HTML.
Et cette syntaxe prévoit les "entities HTML" qui commencent par '&' et qui se terminent par ';'.
Pourquoi "ne bosse t'il plus?"
Je me retrouve donc avec du code source en sortie qui n'est pas converti par une table ASCII