|
Publicité ' | |||||||||||||||||||||||
|
|
#1 |
|
Membre régulier
![]() |
Salut à tous
Je programme en php et je fais souvent des formulaires qui vont ensuite donner lieu à des requètes sql. Je voudrais donc trouver le moyen pour sécuriser ma base de données contre les injections sql. J'ai déjà cherché un peu partout sur le net, j'ai trouvé plein de petites choses mais au final, ca donne toujours lieu à des polémiques sur les forums et ça ne se termine pas de manière constructive avec une solution. J'ai vu des choses sur magic_quotes_gpc, sur addslashes et stripslashes, sur htmlentities, sur real_escape_string etc ... mais au final, comment je fais pour éviter les injections sql ? En gros, ça me simplifierai la vie de pouvoir mettre 2 fonctions que j'includerai quand j'en aurai besoin : - l'une que j'apellerai pour modifier ma chaîne avant insertion dans la base de données - et l'autre qui me rendrait ma chaîne comme au début après son extraction de la base de données Ou sinon, quels sont les caractères indispensables, sans lesquels on ne peut pas faire d'injection sql ? Peut-être me suffit-il de bannir ce caractère de tous mes formulaires, et de ne pas faire de requète lorsque sa présence est détectée ? Voilà je n'ai jamais hacké de base de données et donc je ne maîtrise pas trop dans ce domaine, si quelqu'un d'expérimenté peut me donner des tuyaux, ce serait vraiment sympa ! Merci ! |
|
|
00
|
|
|
#2 |
![]() ![]() ![]() Inscription : septembre 2002 Messages : 1 591 ![]() |
Toutes les fonctions que tu as citées servent justement à "sécuriser" les données reçues.
En gros: - magic_quotes_gpc est une directive PHP (php.ini) qui est généralement mise à "On", c'est à dire que certains caractères des données reçues seront échappés. Lorsque magic_quotes_gpc est à On, il ne faut plus faire de addlsahes - addslashes permet justement d'échapper les caractères significatifs. - htmlentities & htmlspecialchars permettent de convertir en entité HTML tous les caractères ayant une entité HTML correspondante. De manière générale, j'essaye de m'arranger pour filter systématiquement les données que je reçois. Pour toute injection SQL, il est nécessaire d'introduire des espaces (%20), si les données que tu reçois ne sont pas censées en contenir, tu peux déjà les bannir, ce qui au final limite grandement les possibilités de hacking. Si tu travailles avec mysql, les possibilités de hacking sont moindres étant donné que l'api php ne permet pas d'exécuter des requêtes multiples en un seul appel. Il est à noter que les injections SQL constituent un problème général non inhérent aux applications web. Voilà deux trois trucs. |
|
|
00
|
|
|
#3 | |
|
Membre régulier
![]() |
je ne comprends pas vraiment ce que tu veux dire avec les espaces
Citation:
si je bannis le point virgule de tout ce qui passe dans mes champs input avant de les utiliser pour faire des requètes est-ce que ça suffirait ? (le point virgule on s'en sert rarement sauf peut-être dans un textarea c'est un peu embêtant comme restriction) |
|
|
|
00
|
|
|
#4 |
|
Membre régulier
![]() Inscription : décembre 2004 Messages : 121 ![]() |
le point virgule passe dans phpmyadmin car il separe lui meme les requetes et les excute une par une. Avec mysql il est impossible d'en effectuer plusieures avec une seule comme l'a dit stephane.
Quant aux espaces ce qu'il veut dire c'est que generalement la plupart des champs des formulaires (comme par exemple le champ password ou user) demandent des informations en un seul mot donc sans espaces. Donc tu peux tout de suite faire un filtre : si une entrée contient un espace c'est surement pas le type de valeur qui etait attendu. Ainsi comme les injections necessitent des espaces, cela te permet de les eviter. Mais ce n'est pas une methode infaillible et en plus certaines informations peuvent contenir des espaces sans pour autant representer une menace (sujet de topic par ex). Sinon tu as mysql_escape_string(str) pour filtrer les champs afin d'eviter toute injection. Apres si tu veux eviter les attaques par cross site scripting il faut que tu utilise htmlentities. Donc pour resumer le mieux c'est mysql_escape_string et en plus htmlentities au moment de l'affichage pour eviter les attaques CSS. |
|
|
00
|
|
|
#5 |
|
Membre régulier
![]() |
en fait j'utilise beaucoup les expressions régulières et je limite les caractères à des alphanumériques mais c'est une politique très restrictive j'aime pas ça du tout (et elle ne fonctionne plus sur des textarea)
le problème si j'utilise des trucs comme addslashes, ce qui est inséré dans la bdd sera plus long (avec le slash) et donc un caractère comme l'apostrophe comptera comme 2, c'est embêtant tout ça, surtout quand on a un champ varchar de taille 15 caractères, si on veut entrer des apostrophes on ne pourra plus mettre 15 caractères au total. de plus, si l'ajout de slashs fait que la chaine dépasse 15 caractères elle sera tronquée et insérée en partie seulement j'ai peur que ça cause encore d'autres bugs comme ça. donc supposons que je veuille garder ma politique de restriction (vu que le reste je le comprends mais je ne sais pas m'en servir efficacement) quels sont les caractères, ou les jeux de caractères sans lesquels un hackeur de base de données mysql serait totalement désarmé ? parce que je vois que des exemples d'injection avec un 'OR 1=1' mais pas d'autres sur le net, donc à première vue je suis tenté de croire que si j'interdis les caractères de comparaison = < et > je suis sauvé. bref malgré vos explications je suis complètement perdu là ... faut-il faire une carrière de hackeur avant de pouvoir commencer à programmer des trucs sécurisés ? je vous remercie de la patience dont vous faites preuve face à un perdu ! |
|
|
00
|
|
|
#6 |
|
Membre régulier
![]() |
concrètement vous faites comment ? je peux voir un exemple dans le cas ou je ne veux pas tester la chaîne de caractères avec une expression régulière ?
(une chaîne qui à le droit de contenir n'importe quoi) |
|
|
00
|
|
|
#7 |
|
Membre régulier
![]() |
désolé pour le flood mais j'ai peut-être un élément de réponse
dites-moi si je me trompe : étant donné que des que j'envoie une variable dans une requète je l'entoure de " comme ceci : Code :
mysql_query('INSERT INTO table VALUES("","'.$_POST['var1].'","'.$_POST['var2].'")'); si je fais comme ça y a-t-il encore une faille ? peut-on encore faire une injection sans utiliser les double quotes dans ce cas ? je vais en rêver cette nuit des injections sql ... |
|
|
00
|
|
|
#8 |
|
Membre Expert
![]() ![]() Inscription : janvier 2004 Messages : 1 238 ![]() |
Pour verifier si ton site peut etre victime d'une faille d'injection SQL... il suffit de le tester !
Dans tout tes champs saisissables, tu essayes de mettre la valeur : Si ton code est bon, tu devrait pouvoir entrer cette valeur dans les champs de ta base (car a mon avis, c'est pas en "interdisant" des caracteres qu'on protege un site, c'est en blindant son code pour echapper correctement les caracteres qui posent probleme) Donc, si ton code est bon : * Tu peux entrer cette valeur dans tout les champs (y compris login et password pourquoi pas * partout ou le contenu du champ s'affiche, tu doit voir EXACTEMENT ce que tu as entré, pas de \ en trop ou en moins, pas de caractere HTML interprété (sauf si c'est ce que tu veux, sur un forum par exemple, mais c'est dangeureux, c'est pas de l'injection SQL, mais c'est une autre faille de sécurité - il vaut mieux utiliser du bbcode ou autre) |
|
|
00
|
|
|
#9 |
|
Membre émérite
![]() Inscription : avril 2005 Messages : 988 ![]() |
Je suis d'accord avec Flagnag, on ne peut pas interdire des caractères à l'utilisateur
Mais comment faire pour "échapper" les mots-clés SQL, du genre OR AND ... ? |
|
|
00
|
|
|
#10 |
|
Membre Expert
![]() ![]() Inscription : janvier 2004 Messages : 1 238 ![]() |
Tu n'a que 2 types de valeurs en sql (3 en comptant les dates, mais c'est des chaines de caracteres aussi) :
* Les nombres * Les chaines de caracteres Donc, toute requete ressemble a : ...truc=$var... (pour les nombres) ou ...truc='$var'... (pour les chaines de caracteres) Pour les nombres, tu peux faire un traitement avant en php avec is_numeric() par exemple pour verifier que c'est bien un nombre et qu'il ne contient des betises du genre OR, AND, etc... pour les chaines de carateres, si tu echappe correctement ta variable, la chaine ne sera jamais interpretée, tout les caracteres sont donc utilisables. (ce que j'appelle echapper correctement, c'est faire en sorte que truc='$var' avec $var qui vaut : "a'a" soit transformé en truc='a\'a' qui est une instruction sql valide) Les autres cas d'utilisation de variable dans une requete sont "filtrables" facilement, par exemple pour faire un moteur de recherche sur différents champs, on peut avoir : WHERE $colonne = '$var' On peut en php gerer un tableau contenant la liste des colonnes et verifier que $colonne appartient bien au tableau. |
|
|
00
|
|
|
#11 |
|
Membre émérite
![]() Inscription : avril 2005 Messages : 988 ![]() |
En effet, en echappant bien les caractères on peut éviter les injections.
Je pensais notamment à l'injection OR 1=1 Autre question, si on a truc='$var' Et que $var vaut 'a' "a", en faisant un addslashes(), cela va échapper les quotes et guillemets ? Ce qui n'est pas utile pour les guillemets, dans ce cas là. |
|
|
00
|
|
|
#12 |
|
Membre Expert
![]() ![]() Inscription : janvier 2004 Messages : 1 238 ![]() |
Deja il vaut mieux utiliser :
http://fr3.php.net/fr/mysql_real_escape_string Apres... c'est pas tres important. Si tu echappe " en mettant \", mysql comprendra que \ est un caractere d'echappement et qu'il faut l'enlever, tu n'aura donc pas de \ en trop dans la donnée au final. |
|
|
00
|
|
|
#13 |
|
Membre régulier
![]() Inscription : décembre 2004 Messages : 121 ![]() |
Pour eviter les injections SQL il ne faut pas seulement echaper les apostrophes etc..
Prenons un exemple. Une bete page affiche.php qui prend comme parametre id qui est un nombre le script : <? mysql_query('SELECT * FROM pages WHERE id='.$_GET['id']); ?> Ici comme le champ id est du type INT il n'y a pas besoin de mettre de quote. De meme, il est possible de faire une injection SQL sans quote. Imaginons ce soit un site ou ya phpbb d'installer. Pour avoir le mot de passe/user admin il suffit de faire affiche.php?id=-1 UNION SELECT username, user_password,1,1... FROM phpbb_users (le 1,1,..... c'est si ya plusieurs colonnes. Un UNION doit renvoyer le meme nombre de colonne que la premiere requete). Mais ce n'est qu'un exemple il ya plein d'autre possibilité. Par exemple avec ça on peut aussi passer des chaines de caracteres en les transformants en hexadecimal. exemple sur rapidupload (signalé mais pas corrigé ^^): http://www4.rapidupload.com/dl.php?i...2E706870,1,1,1 Il est possible de recupérer nimporte quel fichier php du site, avec une injection sans quote. Conclusion : Si tu a a traité des champ du type int, il ne faut pas simplement echapper les quotes. Il faut que tu verifie bien que le parametre soit un nombre. par ex : $id=(int)$_GET['id']; |
|
|
00
|
|
|
#14 | |||
|
Membre Expert
![]() ![]() Inscription : janvier 2004 Messages : 1 238 ![]() |
Citation:
Code :
__________________
PHP : Regle n°1 : mysql_query(...), mysql_connect(...) et mysq_select_db(...) doivent EN DEBUG etre suivies de or die(mysql_error()); (mais jamais en production) Regle n°2 : Mieux encore : mysql_query($requete) or die("$requete<br/>".mysql_error()); Regle n°3 : echo '<pre>';var_dump($var);echo '</pre>'; affiche le contenu et le type d'une variable. Publiez vos textes de fantasy et de science-fiction sur http://www.cercledefaeries.com/concours/ |
|||
|
|
00
|
|
|
#15 |
|
Membre régulier
![]() |
merci pour ces réponses !
ok donc si je résume : pour les nombres : on fait un is_numeric($var) ou un is_int($var) selon le cas pour les chaines : on applique mysql_real_escape_string($var) avant d'insérer dans la bdd questions : * si magic_quotes_gpc() est activé (et je crois que c'est le cas chez free, et que je ne peux pas le désactiver) je dois alors appliquer mysql_real_escape_string(stripslashes($var)) avant d'insérer dans la bdd ? * et lorsque j'extrais les données de la base, je dois appliquer quelque chose ou rien du tout ? * si le mec entre dans la bdd un '</table>' par exemple, rien ne sera échappé, et lors de l'affichage si j'utilise un tableau pour afficher les données ça va foutre en l'air ma mise en page ? si oui je contre ça comment ? désolé de poser tant de questions mais dans ce domaine j'ai du mal ! j'ai toujours eu du mal et j'ai toujours ignoré les problèmes de sécurité mais ce coup-ci je dois faire mieux ! |
|
|
00
|
|
|
#16 | |||
|
Membre Expert
![]() ![]() Inscription : janvier 2004 Messages : 1 238 ![]() |
Citation:
tu peux savoir dans ton script si l'option magic_quotes est activée avec get_magic_quotes_gpc() Citation:
Citation:
Il ne faut jamais faire un : echo $var; mais toujours un : echo htmlentitites($var); sauf si bien sur ton but est d'afficher de l'html ;o)
__________________
PHP : Regle n°1 : mysql_query(...), mysql_connect(...) et mysq_select_db(...) doivent EN DEBUG etre suivies de or die(mysql_error()); (mais jamais en production) Regle n°2 : Mieux encore : mysql_query($requete) or die("$requete<br/>".mysql_error()); Regle n°3 : echo '<pre>';var_dump($var);echo '</pre>'; affiche le contenu et le type d'une variable. Publiez vos textes de fantasy et de science-fiction sur http://www.cercledefaeries.com/concours/ |
|||
|
|
00
|
|
|
#17 |
|
Membre régulier
![]() |
ok merci beaucoup !
j'y vois un peu plus clair, je vais donc faire comme ça et si j'ai encore une question je reviendrai ! en attendant, on va considérer que mon problème est résolu, merci encore |
|
|
00
|
|
|
#18 |
![]() ![]() Guillaume RossoliniDirecteur technique Inscription : février 2004 Messages : 13 720 ![]() |
Salut
Puisque c'est le sujet ici, je te recommande le post-it sécurité et ce lien : http://thierrylhomme.developpez.com/php/php_secure/
__________________
Mes articles - Zend Certified Engineer (PHP + Zend Framework) Ressources PHP - Ressources Zend Framework |
|
|
00
|
Copyright © 2000-2012 - www.developpez.com