[RESOLU] Protection formulaires.

Eléphant du PHP | 290 Messages

29 oct. 2014, 13:51

Bonjour,

J'ai un formulaire pour entrer sur des pages à accès réservé.
On y rentre avec un nom d'utilisateur, un mot de passe et un test captcha questions-réponses.

J'aurais quelques questions d'ordre général à vous poser quant aux questions de protection/sécurité.

1) Est-il préférable d'écrire du code de sécurité non seulement lorsqu'on propose à un utilisateur d'envoyer ses données vers le SGBD,
mais aussi lorsqu'on récupère des données du SGBD pour demander au navigateur d'afficher ces dernières sur une page web.
Je pose cette question car je ne comprends pas pourquoi sur le forum tous les programmeurs semblent garder comme habitude
de nettoyer des données qui viennent du SGBD.
En effet, ces données se trouvant dans le SGBD devraient à priori avoir été nettoyées antérieurement, juste après la saisie d'un utilisateur dans le but
de les envoyer vers le SGBD. Donc elles devraient à priori être déjà nettoyées.
Deuxième raison pour laquelle je pose cette question, j'ai du mal à imaginer un SGBD qui contiendrait du code malveillant "à l'état statique"
dans une bdd en train d'attendre d'être récupéré sur une table pour créer des problèmes sur le site.

2) On parle souvent de md5. Ca me permet à moi de faire afficher des points noirs sur mon site à l'endroit dédié à une entrée de mot de passe.
Mais dois-je utiliser md5 que pour ça, ou aussi pour remplacer les données par des points noirs dans ma bdd sur phpmyadmin.
J'ai l'impression qu'il faut l'utiliser pour les deux quand je lis ce qui se passe sur le forum.
Mais s'il faut l'utiliser pour les deux, alors moi non plus je ne peux plus lire ce que les utilisateurs ont rentré dans le SGBD,
et ma seule manière de le lire est alors de ressortir ces données sur une page web ou elles seront affichées pour moi seulement,
et si cela est bien ce qu'il faut faire qu'est-ce qui me dis que cette page est plus sécurisée que ma table dans phpmyadmin
(sans parler du fait que cette manière de contourner le problème me semble assez sophistiquée, ... mais réalisable).

3)Avec md5, mon captcha questions-réponses et mes codes de nettoyage pour chaque interaction avec le SGBD
est-ce qu'à votre avis mon site est bien sécurisé?
Me conseilleriez-vous d'ajouter le SHA-256 et le grain de sable?
Pour info, je ne sais pas du tout de quoi il s'agit quand on parle de SHA-256 et de grain de sable.

ViPHP
xTG
ViPHP | 7331 Messages

29 oct. 2014, 14:48

1) Traiter trop profondément les données en entrée est souvent très lourd.
Il est donc de notoriété d'enregistrer dans la table la donnée après un minimum de contrôle mais faire en sorte qu'elle ne puisse agir inopportunément.
On échappe donc les données à l'enregistrement pour éviter les injections SQL.
Puis pour chaque affichage on utilise des fonctions telles que htmlspecialchars pour éviter les failles XSS.
C'est en cela qu'on dit qu'un SGBD peut contenir du code malveillant statique. Il ne pourra être exécuté, juste affiché.

2) Le MD5 ne permet en aucune façon d'afficher des points noirs, c'est le type d'input password qui permet cela.
Le md5 est un hash qui est déconseillé car il existe de nombreuses rainbow table qui permette d'approximer le mot hashé.
Le but est avant tout de ne pas avoir connaissance de la donnée, seul l'utilisateur la connait.
Pour cela on utilise un hash (plus puissant que md5, tu as SHA-256 par exemple) et on stocke uniquement ce hash.
Et on ne fait par la suite que des comparaisons de hash.

Après si ton but est d'avoir une base de données avec laquelle un hackeur ne peut rien faire il faut crypter les données.
Sauf que la clé de cryptage sera sur ton serveur (dans ton code PHP) qui est en général le même serveur que pour la base de données, l'intérêt est donc assez nul.

3) Le MD5 est devenu dépassé à notre ère (à cause des rainbow table), il est préférable d'utiliser SHA-256.
Pour l'utiliser : crypt

Eléphant du PHP | 290 Messages

29 oct. 2014, 17:58

Merci xTG,

Je vais déjà m'occuper du 1).
Si je peux te poser quelques petites questions à ce propos, pour voir si j'ai bien compris.
Le code de nettoyage à l'entrée du formulaire sert à éviter les injections SQL.
On utilise très souvent mysqli_real_escape_string
Plus de chevrons interprétés, pareil pour les apostrophes simples et double, l'antislash,...

Le code de nettoyage à la sortie lui est différent: il sert à éviter l'interprétation de caractères
qui prennent un sens particulier côté client tel que du javascript.
Il s'agit donc de code malveillant qui a pu être introduit dans une bdd car ne prend pas de sens particulier en SQL,
mais qui par contre prend un sens en javascript.
Donc htmlspecialchars ou htmlentities permettent de traiter dans le code source
avant l'affichage les entités SGML comme é ou  
ce qui est différent de ce que fait mysqli_real_escape_string qui lui se préoccupe des injections SQL.
Est que j'ai bien compris?
Je crois que non en fait 8-|
car... on utilise parfois dans le code d'un champs de formulaire htmlentities
htmlentities est donc utilisé à la fois pour une entrée comme pour une sortie.
Et ça pour moi c'est pas logique: le code de nettoyage à l'entrée doit se préoccuper des interprétations langage côté serveur ou/et SGBD,
le code à la sortie doit s'occuper des interprétations langage côté client.
Le code à nettoyer n'est donc pas de même nature à l'entrée comme à la sortie.
Alors pourquoi on peut utiliser htmlentities pour une entrée comme pour une sortie?
Pour dire ça autrement, pourquoi nettoyer exactement la même chose à l'entrée comme à la sortie,
puisque ce qui est potentiellement dangereux à la sortie est ce qui n'a pas pu être nettoyé à l'entrée?

ynx
Mammouth du PHP | 586 Messages

30 oct. 2014, 10:29

Salut,

Tu as bien compris, on nettoie les données en fonction de leurs destinations :
- pour enregistrer les données en bdd -> on nettoie les injections sql (mysqli_real_escape_string ou PDO::prepare/PDO::quote)
- pour afficher sur une page web -> on nettoie les injections xss (htmlentities)
- etc...

Cela permet de gérer tous types de caractères sans soucis.

on utilise parfois dans le code d'un champs de formulaire htmlentities
En fait, on utilise htmlentities pour afficher la valeur d'un champ de formulaire : c'est normal puisqu'on affiche une donnée dans un document html.
Mais la valeur récupérée en php correspond bien au rendu de celle-ci dans le champ. Pour exemple :
<?php
var_dump($_GET['toto']);
?>
<form method="get">
    <input type="text" name="toto" value="<?php echo htmlentities($_GET['toto'], ENT_QUOTES, 'UTF-8'); ?>" />
</form>
Si je saisie la valeur '<div>' dans ce champs, voici ce que j'ai en retour :
- var_dump affiche la valeur '<div>'
- htmlentities affiche la valeur '<div>' dans le champ (entités html)

Si je valide de nouveau ce formulaire, la valeur récupérée en php est bien '<div>' sans entités html. Dans cet exemple htmlentities nous sert donc à nettoyer uniquement l'affichage (la sortie).

Eléphant du PHP | 290 Messages

31 oct. 2014, 13:01

Salut ynx,

Merci pour tes explications qui sont très intéressantes :D
Jusqu'à l'exemple, ça va parfaitement.

A partir de l'exemple, je commence à mélanger le code source et l'affichage à l'écran.
Pour moi, si dans ton exemple en tant qu'utilisateur je rentre la valeur <div> alors effectivement
var_dump affiche <div>.
Quant à htmlentities ce dernier convertit la valeur <div> en <div> et la valeur convertie <div>
devient code source et avec l'interpétation du navigateur <div> est affiché <div> à l'écran,
au final on voit donc la même chose à l'écran que pour le var_dump.

Qu'est-ce que je ne comprends pas?

ViPHP
xTG
ViPHP | 7331 Messages

31 oct. 2014, 13:54

Si ton var_dump affiche <div> c'est que la valeur est déjà traitée avec un htmlentities. ;)
var_dump va afficher la valeur qu'on lui passe. Le navigateur va tenter de l'interpréter.
<div> sera interprété. <div> ne le sera pas.

Eléphant du PHP | 290 Messages

31 oct. 2014, 15:20

Où là là je ne suis pas sûr de comprendre.

Plusieurs points posent difficulté:

1) En gros, est-ce que déjà ça c'est TOUT juste:

mysqli_real_ecape_string nettoie le code pour éviter les injections SQL.
Il met un antislash comme caractère d'échappement derrière certains
caractères comme l'apostrophe, le guillemet ou l'antislash.
Il sert lors de l'envoi de données vers une bdd. Il sert à éviter que des données malicieuses créent du désordre dans la bdd.

htmlentities lui nettoie le code pour éviter des injections xss, et principalement des injections javascript.
Il remplace certains caractères par des entités. Exemple: il remplace l'apostrophe par &8217;
Il sert lors de l'affichage sur l'écran. Il sert à éviter que le navigateur interpète du code malveillant affichant des choses indésirables à l'écran contre notre gré.

2)Ynx dit à propos de htmlentities que htmlentities sert à nettoyer contre les injection xss (ça j'ai bien compris maintenant), mais il dit aussi
on utilise htmlentities pour afficher la valeur d'un champ de formulaire
Il sert donc aux deux? Si oui, quelle est sa principale fonction parmi les deux? Et pourquoi est-ce logique qu'il serve aux deux?

3) Dans son exemple, ynx dit
htmlentities affiche la valeur '<div>' dans le champ (entités html)
Ca veut dire que c'est <div> qui apparaît à l'écran?

4) Toujours dans son exemple, ynx parle de valider à nouveau le formulaire.
Pourquoi est-ce que la première fois où on valide le formulaire et la deuxième c'est pas pareil?

5) xTG tu dis
Si ton var_dump affiche <div> c'est que la valeur est déjà traitée avec un htmlentities.
Pourtant, quand l'utilisateur tape <div> alors htmlentities transforme ça en <div> (c'est <div> qu'on a alors dans le code source, c'est juste?)
et le navigateur pour moi doit interpéter <div> puisque le SGML est à mon avis interpété par le navigateur pour afficher <div>.
Mais tu dis que non.
Et tu dis que <div> est interprété. Ca non plus je ne comprends pas. Il est interpété comment et pourquoi?

Désolé pour toutes ces questions mais je n'arrive pas encore à bien comprendre.

ynx
Mammouth du PHP | 586 Messages

31 oct. 2014, 16:06

Le point 1 est juste, tu as bien compris.

on utilise htmlentities pour afficher la valeur d'un champ de formulaire
Il sert donc aux deux? Non, le but de ce htmlentities est uniquement de convertir les entités html à l'affichage (en sortie), c'est logique puisque l'on est dans un document html. Mais ce htmlentities ne filtre pas ce qui est envoyé à la soumission du formulaire.

C'est justement ce que je précise à la suite : htmlentities affiche la valeur '<div>' dans le champ, les entités html sont correctement comprises par le navigateur et c'est donc la valeur '<div>' qui apparait à l'écran pour l'utilisateur.
Lorsque le formulaire est envoyé, php récupère la valeur '<div>' et non pas '<div>', htmlentities n'a donc servi que pour l'affichage.

La différence entre la première et la deuxième validation du formulaire est que sur la première j'ai moi-même saisie la valeur '<div>' dans le champ alors pour le deuxième c'est php qui a repris la valeur que j'avais saisie et qui affiche également '<div>' (avec des entités html via le htmlentities). Tout ça pour dire que dans les deux cas (via des entités html ou en saisie directe) la valeur récupérée par php est bien '<div>', et que donc html n'a bien servi que pour l'affichage dans cet exemple.

Je t'invite à tester le code de mon précédent message si tout n'est pas encore claire.

ViPHP
xTG
ViPHP | 7331 Messages

31 oct. 2014, 17:06

5)
Pourtant, quand l'utilisateur tape <div> alors htmlentities transforme ça en <div> (c'est <div> qu'on a alors dans le code source, c'est juste?)
Oui.
et le navigateur pour moi doit interpéter <div> puisque le SGML est à mon avis interpété par le navigateur pour afficher <div>.
Mais tu dis que non.
Le navigateur n'interprète dans cette chaîne de caractère aucun code HTML, il ne fait que de l'affichage de texte (je ne considère pas le changement de < à < dans l'affichage comme une interprétation mais juste comme une correspondance).
Et tu dis que <div> est interprétée. Ca non plus je ne comprends pas. Il est interpété comment et pourquoi?
Toute balise HTML est interprété par ton navigateur pour générer un certain rendu d'affichage.

Est-ce plus clair ? :)

Eléphant du PHP | 290 Messages

31 oct. 2014, 17:45

1) Pour ce faire, je mets ce code dans une nouvelle page que j'appelle test.php:
<?php
var_dump($_GET['toto']);
?>
<form method="get">
    <input type="text" name="toto" value="<?php echo htmlentities($_GET['toto'], ENT_QUOTES, 'UTF-8'); ?>" />
    <input type="submit" />
</form>
J'obtiens
Notice: Undefined index: toto in C:\xampp\htdocs\mon_site\test.php on line 2
NULL
et dans le champs de saisie:
<br /><b>Notice</b>: Undefined index: toto in <b>C:\xampp\htdocs\htdocs\mon_site\test.php</b> on line <b>5</b><br />

2) Je crois que je ne comprends pas bien ce que tu appelles affichage.
Est-ce que tu peux préciser ce que tu entends par là dans ton dernier message:
le but de ce htmlentities est uniquement de convertir les entités html à l'affichage (en sortie)
htmlentities affiche la valeur '<div>' dans le champ
htmlentities n'a donc servi que pour l'affichage
J'ai toujours pensé que tu parles de l'affiche du code client sur l'écran de l'utilisateur une fois que ce dernier est interprété par le navigateur. C'est bien ça?

Si la réponse est oui, dans ce cas quand tu dis
htmlentities affiche la valeur '<div>' dans le champ
l'utilisateur ne va
pourtant pas voir <div> à l'écran, si?
Tu entends bien par champs le champs de saisie que l'utilisateur voit à l'écran?

ynx
Mammouth du PHP | 586 Messages

31 oct. 2014, 18:04

1) Je n'ai pas traité les Notice php sur mon exemple. Il faut saisir une valeur dans le champ, sinon tu peux utiliser cette exemple :
<?php
if (!empty($_GET['toto'])) {
	var_dump($_GET['toto']);
}
?>
<form method="get">
    <input type="text" name="toto" value="<?php echo !empty($_GET['toto']) ? htmlentities($_GET['toto'], ENT_QUOTES, 'UTF-8') : ''; ?>" />
    <input type="submit" />
</form>
2) Oui mon utilisation du terme affichage peut amener des ambiguïtés.
Pour compléter :
- le but de ce htmlentities est uniquement de convertir les entités html à l'affichage (en sortie) : il ne sert qu'à éviter les injections xss
- htmlentities affiche la valeur '<div>' dans le champ : pour être précis, htmlentities retourne la valeur '<div>' dans le champ (dans le code source). Dans le navigateur, ces entités html corresponde à l'affichage de '<div>'.
- htmlentities n'a donc servi que pour l'affichage : je répète qu'il ne sert qu'à éviter les injections xss

Eléphant du PHP | 290 Messages

31 oct. 2014, 18:15

Merci pour tout tout dernier message xTG.

J'ai maintenant une question importante à te poser car c'est ce qui me tourne dans la tête depuis déjà un bon bout de temps.

htmlentities transforme <div> en <div> et <div> est alors écrit dans le code source.
Du code source à l'affichage sur l'écran de l'ordinateur de l'utilisateur, comment ça se passe pour <div> alors?

Le navigateur va effectuer une correspondance pour < et ensuite facile, il va afficher tel quel les lettres div et enfin
il va effectuer une correspondance pour >

Qu'est-ce que c'est que ces correspondances et comment ça fonctionne?
C'est exactement le cheminement inverse qu'exécute htmlentities lorsqu'il remplace certains caractères par des entités.
Mais ce cheminenement inverse qui consiste à remplacer les entités dans le code source par des caractères UTF-8 pour l'affichage
ce n'est pas la fonction htmlentities qui l'exécute, et ce n'est pas non plus le navigateur.
Alors qui est-ce qui se charge de cette tâche? La "correspondance" ne peut pas s'exécuter toute seule!
(sinon, comment savoir qu'il y a correspondance)

Et si je comprends bien c'est le code source qui est vulérable. Une injection xss peut créer des désordres que lorsqu'elle atteind le code source.

ViPHP
xTG
ViPHP | 7331 Messages

31 oct. 2014, 19:36

Ces correspondances proviennent d'une table prédéfinie.
C'est comme la table ASCII, chaque numéro de 0 à 255 représente un caractère.
Mais ce cheminenement inverse qui consiste à remplacer les entités dans le code source par des caractères UTF-8 pour l'affichage
ce n'est pas la fonction htmlentities qui l'exécute, et ce n'est pas non plus le navigateur.
Non c'est le navigateur qui fait le boulot.
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 ';'.
Une injection xss peut créer des désordres que lorsqu'elle atteind le code source.
Tout à fait, si tu utilises htmlentities() peut importe que tu affiches du code source malicieux ou non il ne sera pas exécuté.
Il est souvent plus simple de faire en sorte de ne pas l'exécuter par cette technique plutôt que de faire des filtres très couteux à exécuter et à maintenir lors de la phase de vérification avant insertion dans la BDD.

Eléphant du PHP | 290 Messages

31 oct. 2014, 23:31

Donc pour résumé, on peut dire que htmlentities dans une instruction echo converti certains caractères en entités SGML
pour protéger le site au niveau du code source et pour le réaffichage sur l'écran des données saisies le navigateur s'occupe à lui tout seul des correspondances à faire grâce à une table ASCII?

Si la réponse est oui alors j'ai tout compris.

ViPHP
xTG
ViPHP | 7331 Messages

31 oct. 2014, 23:47

Je ne saurais te confirmer que les &...; sont des entités SGML. Et j'ai pas franchement envie d'éplucher la norme pour trouver l'information. :twisted:

Par contre le rôle du navigateur c'est :
1) récupérer la réponse du serveur qui est une suite de '0' et de '1' (tout est question de bits en informatique)
2) interpréter ce contenu dont une portion (parce que dans la réponse il y a aussi des entêtes, là je me concentre sur le contenu de la page) est une suite de caractères ASCII
3) Et à partir de cette suite de caractères il recherche des motifs collant à des entités HTML (balises, ect).

"<div>" est un motif. "<" en est un autre.
Ce qui fait que "<div>" n'est pas un motif mais le mot "div" entouré de deux motifs.
Ce ne sera donc pas interprété de la même façon que "<div>" par le navigateur.