Page 1 sur 1

mysql_real_escape_string ou \"\"

Posté : 13 févr. 2011, 11:13
par will7991
Bonjour à tous,

Je m'interroge sur une subtilité.

De ce que je lis ça et là, afin d'empecher les injéctions SQL, il faut appliquer mysql_real_escape_string sur toutes les variables saisies par un utilisateur dans un formulaire. Effectivement, si on fait comme ceci, ça craint :

Code : Tout sélectionner

Source : http://www.lephpfacile.com/manuel-php/function.mysql-real-escape-string.php Exemple #2 Un exemple d'attaque par injection SQL 1. <?php 2. // Demande à la base de vérifier si un utilisateur correspond 3. $query = "SELECT * FROM users WHERE user='{$_POST['username']}' AND password='{$_POST['password']}'"; 4. mysql_query($query); 5. 6. // Nous ne vérifions pas $_POST['password'], il peut contenir ce que l'utilisateur veut ! Par exemple : 7. $_POST['username'] = 'aidan'; 8. $_POST['password'] = "' OR ''='"; 9. 10. // Cela signifie que la requête envoyée à MySQL sera : 11. echo $query; 12. ?> La requête envoyée à MySQL : SELECT * FROM users WHERE user='aidan' AND password='' OR ''='' Cela permet à n'importe qui de s'identifier sans mot de passe valide.
Mais ce que je remarque dans quasiement tous les tutos, pour concater une variable PHP dans une chaine, sont utilisées les simples quotes :

Code : Tout sélectionner

$query = "SELECT * FROM users WHERE user='{$_POST['username']}'] AND password='{$_POST['password']}'";
En ce qui me concerne, j'ai toujours utilisé les guillemets échappés par un antislash, en ayant stocké les champs POST dans des variables, sans appliquer mysql_real_escape_string :

Code : Tout sélectionner

$username=$_POST['username']; $password=$_POST['password']; $query = "SELECT * FROM users WHERE user=\"$username\" AND password=\"$password\"";
Mes questions sont simples :
Pourquoi concaténer à l'aide de simples quotes sachant que l'on s'expose ?
Concernant ma méthode : est-ce sécurisé ? Ou dois-je tout de même utiliser mysql_real_escape_string ?

Merci !

Re: mysql_real_escape_string ou \"\"

Posté : 13 févr. 2011, 11:58
par xTG
On peut appliquer le même raisonnement avec les doubles côtes de porc.
Donc utilises les fonctions miracles qu'on te donne. ;)

Re: mysql_real_escape_string ou \"\"

Posté : 13 févr. 2011, 13:55
par moogli
Salut,

Pour etre plus explicite ce n'est pas une question de simple ou double quote. Ce que tu fait, outre utiliser de la memoire pour rien lors de la copie des variable, et exactement la meme chose que concatener $_POST dans la chaine finale ;)

Donc une simple concatenation de $_POST dans la chaine en utilisant mysql_real_escape_string est suffisant et correct ;)

Ensuite la "bonne" demarche serait :
- tester l'existance des index du tableau $_POST correspondant aux inputs du formulaire avec isset / empty
- verifier le contenu des index (strlen etc attention aux "faux amis" de empty qui peuveut preter a confusion)
- creer la requete par concatenation en utilisant mysql_real_escape_string sur TOUTES les infos

Pour la crearion de lanrequete tu peut utiliser les simples ou doubles quotes (sache qu'a la base la syntaxe des chaines sql est delimité par des simples quotes). Tu peut aussi utiliser la syntaxe heredoc si tu estime que cela est plus claire (je le fait sur des requetes assez longue, et pourquoi pas un array_walk avant).

@+

Re: mysql_real_escape_string ou \"\"

Posté : 13 févr. 2011, 21:40
par AB
Mais ce que je remarque dans quasiment tous les tutos, pour concater une variable PHP dans une chaine, sont utilisées les simples quotes :

Code : Tout sélectionner

$query = "SELECT * FROM users WHERE user='{$_POST['username']}'] AND password='{$_POST['password']}'";
Dans ce forum, on s'est mis d'accord (il y a longtemps) pour adopter la syntaxe :
$requeteSQL = "SELECT * FROM table1 WHERE colonne2 = '".mysql_real_escape_string($variable)."'"; 
$variable devant bien entendu être protégé par mysql_real_escape_string puisque selon le manuel :
Cette fonction doit toujours (avec quelques exceptions) être utilisée pour protéger vos données avant d'envoyer la requête à MySQL
Un exemple complet de code utilisant cette syntaxe.

Re: mysql_real_escape_string ou \"\"

Posté : 14 févr. 2011, 01:55
par will7991
salut à tous et merci d'avoir répondu !
les doubles côtes de porc
Miam miam :)
Donc utilises les fonctions miracles qu'on te donne.
Oui effectivement, j'aurais pu faire ça. Mais bon, c'est quand même bien d'utiliser ET de comprendre ce qu'on me file :) C'est un peu comme les sportifs de hauts niveaux qui se piquent, se font chopper ensuite et invoquent "l'insu de leur plein gré" ...
Ce que tu fait, outre utiliser de la memoire pour rien lors de la copie des variable
Exact. Mais j'aurai du préciser que là n'était pas la question.
Cette fonction doit toujours (avec quelques exceptions) être utilisée pour protéger vos données avant d'envoyer la requête à MySQL
Effectivement, si le manuel le dit, je m'incline :D

Bon, il est clair que je vais utiliser mysql_real_escape_string, mais est-ce que quelqu'un peut dire - exemple à l'appui - ce à quoi on s'expose si on n'applique pas mysql_real_escape_string mais qu'on échappe manuellement les quillemets (Je précise bien guillemets (touche 3) et non 2xcotes (touche 4)) :

Code : Tout sélectionner

$query = "SELECT * FROM users WHERE user=\"{$_POST['username']}\" AND password=\"{$_POST['password']}\"";
Guillemets échappés ou cote de porc, même combat face aux injections ?

Merci encore !

Re: mysql_real_escape_string ou \"\"

Posté : 14 févr. 2011, 10:12
par xTG
Logiquement le sgbd n'utilise pas les " pour les champs, donc il risque de les interpréter comme des ' et là l'injection tu la prends sur la figure.
Bref pour te répondre plus simplement, cela risque d'apporter un comportement aléatoire suivant le driver que tu as derrière.
Si ce driver interprète tes " pas de soucis, si par contre il les remplace : bang !

Re: mysql_real_escape_string ou \"\"

Posté : 14 févr. 2011, 10:21
par will7991
Salut !
cela risque d'apporter un comportement aléatoire suivant le driver que tu as derrière.
Effectivement, rien que pour ça, il vaut mieux faire les choses en règle.

Merci à vous tous pour votre aide !

Will

Re: mysql_real_escape_string ou \"\"

Posté : 14 févr. 2011, 10:35
par moogli
en fait ce que tu ne comprend pas c'est la différence entre ta chaine de caractère et le contenu de la variable. Et donc au final l'endroit ou l'erreur va se passer :)

Une chaine de caractère doit être délimiter par des " ou des ' (ça tu le sais déja).
lorsque l'on souhaite utiliser des " ou des ' dans une chaine de caractère il faut échapper celui qui correspond à ce qui sert à "encapsuler" la chaine (ce que tu fait dans ton exemple) donc avec echo 'je l'aime'; (oui c'est la st valentin ^^) tu aura une parse error que tu n'aura pas avec echo 'je l\'aime';

maintenant si je fait
<?php
$x = 'je joue avec les guillements la " et la " voir même ici " ;)'; 
echo "j'inclue le tous dans un echo :  $x | et je peut mettre des truc après si veut !";
?>
la il n'y a aucun problème le texte va s'afficher sans parse error. Pourquoi ? parce que mes chaines sont correctement formée indépendamment des ' ou "

Qu'est ce qu'une faille SQL ?
ben vulgairement parlant c'est un truc qui détourne l'utilisation normale d'une requete, parce que tu l'a laisser faire (sisi le truc ne fait que ce que tu lui dit et si tu lui dit de faire mal il le fera ;)).
exemple
$requete = 'select count(id) from user where login=\'$x\'';
cette requête parait banal, on se dit tiens il veut savoir si le mec existe dans la base. Effectifvement, mais ça c'est penser au petit malin qui rentrera dans le beaux formulaire avec le titre ADMINISTRATION de ton site le pseudo ' or 1=1 limit 1 !

dans ce cas la requête c'est quoi ?
si tu te souvient de ce que j'ai dit la chaine de caractère PHP sera bien formée car le fait qu'il y ait une ' dans la valeur fournie ne le dérange pas puisse que l'on "n'interfère" pas dans les délimiteurs on va donc avoir dans la variable :
select count(id) from user where login='' or 1=1 limit 1 !
/!\ je n'ai pas mis les ' car je te montre le contenu de la variable c'est dire ce qui sera utile les ' n'étant la que pour dire la où commence et où finis la chaine de caractère.

Donc tu peut voir qu'au final ou va envoyer à mysql un requête SQL, elle aussi, syntaxiquement correcte mais on vos la faille de sécurit. Non ?
aller je t'aide
- select count(id) from user : je compte tout les id de la table user
- where login ='' : je compte tout les id de la table user qui ont un champ login vide (attention pas null vide)
- or 1=1 : ou 1=1 O_o ben oui 1 = 1 cette condition est toujours vrai donc au final login='' or 1=1 sera toujours VRAI je valide donc la clause where je compte l'id
- limit 1 : alors astuce, je m'dit le dev est pas trop couillon il à mis ensuite dans son code une vérification du nombre de tuple pour le cas où et il vérifie == 1 et pas >=0 (mais bon la p lus part du temps c'est pas le cas ;) ).

donc je vais toujours sélectionner 1 comme résultat du count.

je vais plus loin si j'ajoute un order by id asc (au pif mais les 3/4 des clefs primaire se nomme id au pire tu aura une erreur sql qui va t'aider à pourrir le site ;)). Avec mon order by je vais selectionner le 1er tuple de la table, si je m'en sert pour une connection se sera le premier utilisateur de la table qui est .......... en général l'administrateur du site (quand tu installe n'importe qu'elle appli c'est la première chose que tu entre) et la c'est le drame, le mec fait ce qu'il veut de ton site =D>

maintenant si tu utilise mysql_real_escape_string tu évite ce problème. Pourquoi ? parce que cette fonction va ajouter un \ devant 'est rendre la requete différente :
select count(id) from user where login='\' or 1=1 limit 1' 
la tu va chercher l'utilisateur qui a pour login ' or 1=1 limit 1 (quote comprise) et ça c'est pas banal :)

pourquoi tous ce paté ?

Pour te montrer qu'il faut différencier les chaines de caractère PHP et SQL et te montre que ce qui est syntaxiquement correct pour l'un ne le sera pas pour l'autre et surtout peut l'être mais induire une faille de sécurité.
Mais aussi te montrer qu'elles sont indépendante et que former une chaine php syntaxiquement correcte n'inclue pas une chaine correcte et sécurisé pour SQL :-)

pourquoi j'utilise des ' et pas des " dans mes requetes ? parce que de mémoire la syntaxe de la ref SQL mais ça ne pose pas de problème à mysql (ça serait le cas avec d'autre comme sqlserver et la ton code n'est pas portable ;)).

pour la formation des chaines php tu peut aussi utiliser la syntaxe pour t'affranchir des ' et " coté php mais il faudra quand même les gérer pour MySQL.

tu peut aussi regardé du coté de l'extension mysqli et l'extension montante [url=http://www.siteduzero.com/tutoriel-3-34 ... x-bdd.html]PDO
(article sur le SdZ).

J'espère que c'était pas trop barbant et que t'a compris ce que j'ai mis :)

@+

Re: mysql_real_escape_string ou \"\"

Posté : 14 févr. 2011, 12:45
par will7991
Salut Moogli,
pourquoi tous ce paté ?
Pas de pb, j'aime le paté

J'espère que c'était pas trop barbant et que t'a compris ce que j'ai mis :)
Non, pas barbant du tout. Très instructif même !
pourquoi j'utilise des ' et pas des " dans mes requetes ? parce que de mémoire la syntaxe de la ref SQL mais ça ne pose pas de problème à mysql (ça serait le cas avec d'autre comme sqlserver et la ton code n'est pas portable ).
(se tape le front avec ça main) Exact ! Voilà pourquoi on utilise des ' !

En tout cas, moogli, merci beaucoup pour cette démonstration !

Re: mysql_real_escape_string ou \"\"

Posté : 14 févr. 2011, 21:49
par AB
Tu devrais te référer un peu plus au manuel, c'est LA BASE mysql_real_escape_string

La doc indique les caractères qui seront protégés et cela ne se limite pas aux quotes et doubles quotes :wink:

Par ailleurs si tu regarde les caractères protégés par mysql_real_escape_string par rapport à fonction addslashes, tu constate que mysql_real_escape_string protège des caractères supplémentaires.

Et la doc de la fonction addslashes mentionne bien "il est fortement recommandé d'utiliser les fonctions de protection spécifiques à chaque base de données".

Cela fait déjà beaucoup de réponses...

Sinon tant qu'à faire les choses bien, pour tes prochains projets utilises plutôt mysqli (très proche de la syntaxe mysql) ou PDO car l'extension mysql n'est plus en développement, voir le tableau en bas de cette page

Re: mysql_real_escape_string ou \"\"

Posté : 14 févr. 2011, 22:23
par will7991
Tu devrais te référer un peu plus au manuel, c'est LA BASE
t'inquiètes, je suis partisan du "lis d'abord, ensuite réfléchis et surtout codes en dernier".

En fait ma question (mal formulée) n'était pas "faut il utiliser ou non la fonction" car la reponse est evidente. mais plutôt "qu'est ce que ça fait dans mon cas"
Ce à quoi moogli a très bien repondu.
Cela fait déjà beaucoup de réponses...
c'est plutôt cool sur un forum, non ?
Sinon tant qu'à faire les choses bien, pour tes prochains projets utilises plutôt mysqli (très proche de la syntaxe mysql) ou PDO car l'extension mysql n'est plus en développement, voir le tableau en bas de cette page
Ça effectivement je n'avais pas du tout suivi et vais grandement suivre ton conseil.

Merci à toi !

Re: mysql_real_escape_string ou \"\"

Posté : 14 févr. 2011, 22:59
par AB
Cela fait déjà beaucoup de réponses...
c'est plutôt cool sur un forum, non ?
Pas de souci, je voulais juste dire que le manuel donne déjà beaucoup de réponses :wink:
... et comme, parlant de mysql_real_escape_string, je te voyais focaliser sur les seuls problèmes de quotes/double quotes, je me disais que tu n'avais pas lu la doc puisque son intérêt dépasse la protection de ces seuls caractères... :)