Page 1 sur 2

check de formulaires via php

Posté : 18 août 2015, 11:50
par donkeykick
Bonjour,

Je voulais connaître les bonnes pratiques en matière de contrôle de formulaire via php.

La première étape est de faire ces contrôles via jquery mais comment blinder côté php.

Pouvez-vous me dire svp ?

D'avance merci.

do_ok

Re: check de formulaires via php

Posté : 18 août 2015, 14:10
par xTG
Cela reste assez basique pour le contenu, il faut vérifier que la valeur que tu reçois respectes :
- le type attendu (exemple : une chaîne de caractère au lieu d'un nombre)
- la plage de valeur attendue (exemple : [0..16] attendu alors que tu reçois 32)

Et si tu travailles avec une base de données il faut protéger les variables contre les injections.
Tu peux pour cela utiliser les requêtes préparées ou bien les fonctions de protection propre à chaque librairie :
MySQL : mysql_real_escape_string
MySQLi : mysqli_real_escape_string
PDO : quote
ect

Après pour la forme tu peux vérifier que les données proviennent bien de ton formulaire et non d'un autre.
En général pour cela on utilise un token dans un champs caché que l'on compare à une variable de session.

Re: check de formulaires via php

Posté : 19 août 2015, 09:51
par donkeykick
slt !

merci XTG.

Je comprends pas trop PDO : quote, c'est quoi ?

D'ailleurs me vient cette question annexe, quand faut-il utiliser les quotes ou les guillemets et quand utiliser print ou echo ?

Re: check de formulaires via php

Posté : 19 août 2015, 09:58
par xTG
PDO::quote c'est la fonction d'échappement pour protéger des injections SQL quand tu utilise la fonction query par exemple.
$res = $db->query('SELECT * FROM `mytable` WHERE id=' . $db->quote($_GET['id']))
Quotes ou guillements ? C'est à ta convenance, cela ne change rien.
La seule différence à laquelle il faut faire attention :
echo "$var"; // affiche le contenu de $var
echo '$var'; // affiche $var en toute lettre
De même pour print et echo, cela ne change pas grand chose.

Re: check de formulaires via php

Posté : 19 août 2015, 10:42
par donkeykick
Ca roxe du poney PHP !!!

le quote de pdo s'applique aussi aux requêtes préparées ? Si je reprends ton exemple :
$res = $db->query('SELECT * FROM `mytable` WHERE id=' . $db->quote($_GET['id']))
ça donne ceci, c'est juste ?
$res = $db->query('SELECT * FROM `mytable` WHERE id=' . $db->quote(:id))
do_ok

Re: check de formulaires via php

Posté : 19 août 2015, 11:20
par xTG
La fonction query n'étant pas une requête préparée ton poney risque pas d'avancer. ;)

Les requêtes préparées protègent déjà les données en entrée, donc pas besoin de cette fonction quote.
Il faut juste ne pas faire ceci :
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < ' . $_POST['calories'] . ' AND colour = ' . $_POST['colour']);
Car sinon requête préparée ou non les injections sont possibles. ;)

Re: check de formulaires via php

Posté : 19 août 2015, 12:35
par donkeykick
:lol:

Dans ton exemple si je fais :
$sth = $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour);

$sth->bindParam(':calories', $_POST["calories"]);
$sth->bindValue(':colour', $_POST["colour"]);
c'est bon ? Rien besoin de rajouter ? J'ai du mal à voir la différence entre le code ci-dessus et si je faisais calories < $_POST["calories"] AND colour = $_POST["colour"]..... J'ai peut être oublié un truc dans le bindParam :-k

do_ok

Re: check de formulaires via php

Posté : 19 août 2015, 13:16
par xTG
La différence c'est que tu passes par prepare qui génère une requête préparée dans laquelle tu ne peux rien injecter hormis des données saines.
Tu peux mettre ce que tu veux dans le bindParam sans risquer d'injection SQL.

Alors que tout ce qui est dans le prepare doit être sain.

Re: check de formulaires via php

Posté : 19 août 2015, 14:18
par Ryle
Bonjour,

Ce n'est pas tant la requête préparée qui est importante, mais le fait de contrôler les données transmises par l'utilisateur.

Dans la logique, la requête préparée ne devrait servir que lorsque tu exécutes plusieurs fois la même requête de façon consécutives avec des valeurs différentes (ex : insertions ou mises à jour en masse, exécution de la requête dans une boucle, ...). Le gain de temps et de ressources est alors notable sur de gros volumes de requêtes.
Lorsque tu utilises PDO, ce dernier va implicitement protéger toutes les valeurs transmises à la requête préparée. C'est pourquoi beaucoup de gens l'utilisent ou recommandes PDO, même pour des requêtes simples qui ne seront exécutées qu'une fois dans le code.

Le contrôle des données transmises et la protection des injections sql évoqué par xTG est primordiale, car sans cela un utilisateur malintentionné pourrait en cherchant un peu, accéder à des données confidentielles de ton site (identifiants, mots de passe, ...).
Pour reprendre l'exemple et la requête donnés plus haut :
'SELECT name, colour, calories FROM fruit WHERE calories < ' . $_POST['calories']
Dans une logique fonctionnelle, $_POST['calories'] devrait contenir un nombre (saisie ou sélectionné dans ton formulaire) et tout fonctionnera bien. Dans la pratique, s'il s'agit d'un champ de saisie libre (mais ça marche avec n'importe quel type de champ si on bricole le html), il suffit à l'utilisateur de rentrer une valeur du type : " 250 UNION SELECT username, password, id FROM users " pour que la requête SQL exécutée devienne
SELECT name, colour, calories FROM fruit WHERE calories < 250
UNION 
SELECT username as name, password as colour, id as calories FROM users
et retourne effectivement tous les éléments inférieurs à 250 ca, mais également la liste des identifiants et des mots de passes de la table users... Et si ça ne marche pas car la table ou la colonne n'existe pas, il suffit de changer le nom de la table et/ou des champs jusqu'à ce que ça fonctionne (et on peut même demander à un robot d'essayer des combinaison jusqu'à trouver les bonnes valeurs :))

En contrôlant que la valeur de $_POST['calories'] est bien un nombre avant de l'envoyer dans ta requête, tu t'épargnes ce genre de problème. De la même manière, avec les chaines de caractères, si tu ne contrôles pas la présence d'apostrophes ou de guillemets, l'utilisateur peut ainsi compléter ta requête et disposer d'un accès à ta base de données et peut être plus :)

Re: check de formulaires via php

Posté : 20 août 2015, 01:20
par donkeykick
Merci pour les astuces ;)

Du coup le fait de faire $sth->bindParam(':calories', $_POST["calories"]); suiffit ou il faut rajouter des contrôles ?

Idem est-ce qu'on faire des injections via l'url en récupérant des variables postées en GET.

Comment se gère la réécriture d'url à ce niveau ? (je sais c'est j'ouvre une parenthèse mais c'est pertinent je pense au vue du sujet)

do_ok

Re: check de formulaires via php

Posté : 20 août 2015, 11:25
par xTG
Il FAUT rajouter des contrôles.
On traite pas une variable sans la contrôler en se disant que la protection SQL suffit.
C'est bête de se retrouver à vouloir stocker un entier qui n'en est pas un.

Re: check de formulaires via php

Posté : 20 août 2015, 12:22
par donkeykick
Ok mais sur cet exemple ça donne quoi ?
$sth->bindParam(':calories', $_POST["calories"]);

Concernant les GET on peut aussi faire de l'injection ?

Re: check de formulaires via php

Posté : 20 août 2015, 13:13
par xTG
On peut faire de l'injection avec n'importe quoi qui provient de l'utilisateur/navigateur.

$_POST['calories'] doit être un entier ou au pire un chiffre.
Tu as la fonction is_number qui peut t'aider à faire ce test, ou bien is_integer si tu veux aller plus loin.

Re: check de formulaires via php

Posté : 20 août 2015, 14:44
par Ryle
Il est tout à fait possible de faire des injections en GET (c'est même d'autant plus facile qu'il suffit juste de modifier l'url de la page), tout comme tu peux le faire en POST, ou en bricolant la valeur d'un cookie. La règle est simple : il ne faut jamais faire confiance à une donnée dont tu ne maîtrises pas la provenance ou le contenu (input utilisateur, site externe, fichier d'import, ...) :)

Comme l'indique xTG, la première chose à contrôler est le type de valeur que tu reçois : si tu attends un nombre, tu ne dois pas te retrouver avec des lettres ou des caractères spéciaux, si tu attends une date, il faut que celle-ci soit valide, si tu attends une valeur sélectionnée dans une liste, il faut que celle-ci soit bien présente dans la liste etc.

Une fois que tu es certain que le type de donnée reçu est le bon, le second contrôle à mettre en place concerne les chaines de caractères soumises par l'utilisateur et que tu enregistres en base pour te prémunir des "injections SQL". Pour cela, les requêtes préparées et le bindParam de PDO fonctionnent bien et gèrent les caractères spéciaux de la chaine reçue (après tu peux aussi utiliser des mysqli_real_escape_string() ou fabriquer un contrôle maison).

Le troisième élément dont il faut se méfier c'est le "cross site scripting" ou "XSS". Cela consiste à envoyer du code html et javascript sur ton site qui va potentiellement l'enregistrer mais qui va surtout afficher celui-ci. Tu peux ainsi te retrouver avec des liens non désiré (ou bien pire avec du javascript) dans une des pages de ton site et permettre d'exécuter un code malicieux chez tout ceux qui ouvriront la page en question sur ton site.

Après il faut aussi se prémunir du spam, des attaques bruteforce, et de plein d'autres choses en fonction de l'attrait et de la confidentialité des données, mais déjà si tu gères les 3 cas ci-dessus, ton site sera bien plus sécurisé que nombre de site sur lesquels tu peux surfer ;)

Re: check de formulaires via php

Posté : 21 août 2015, 09:32
par donkeykick
Waouh ça craint le xss !!!

Typiquement pour protéger en PDO ta variable ça se passe comment ?

Est-ce que vous avez un exemple de code simple d'usage PDO avec des requêtes préparées protégées ?

J'adore ta signature ryle, tellement vrai :lol:

do_ok