IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

[Sécurité] Injection SQL


Sujet :

Langage PHP

  1. #1
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut [Sécurité] Injection SQL
    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 !

  2. #2
    Membre expert

    Profil pro
    Inscrit en
    Septembre 2002
    Messages
    1 581
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2002
    Messages : 1 581
    Points : 3 016
    Points
    3 016
    Par défaut
    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.

  3. #3
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    je ne comprends pas vraiment ce que tu veux dire avec les espaces

    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.
    la je vois pas non plus, je viens de tester de faire 2 requètes en même temps dans phpmyadmin, il suffit de les séparer d'un point virgule et ça marche donc à priori ca marcherait tout autant si je fais un insert dans une base, provenant d'un champ input, on pourrait y mettre un point virgule pour finir le insert et mettre derrière la méchante requète genre drop table.



    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)

  4. #4
    Membre habitué

    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 121
    Points : 127
    Points
    127
    Par défaut
    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.

  5. #5
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    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 !

  6. #6
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    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)

  7. #7
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
     mysql_query('INSERT INTO table VALUES("","'.$_POST['var1].'","'.$_POST['var2].'")');
    pour faire une injection sql, le méchant doit fermer les double quotes. donc il me suffit de tester si la chaine contient des doubles quotes " et si oui je les enlève tout simplement avec un string_replace.
    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 ...

  8. #8
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    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 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a'a"a/a\a<b>a</b>a<br>a
    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)

  9. #9
    Membre expérimenté
    Avatar de Linaa
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    987
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 987
    Points : 1 309
    Points
    1 309
    Par défaut
    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
    ...

    ?

  10. #10
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    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.

  11. #11
    Membre expérimenté
    Avatar de Linaa
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    987
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 987
    Points : 1 309
    Points
    1 309
    Par défaut
    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à.

  12. #12
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    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.

  13. #13
    Membre habitué

    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 121
    Points : 127
    Points
    127
    Par défaut
    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'];

  14. #14
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    Citation Envoyé par Fladnag
    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...
    C'est ce que je disais un peu plus haut...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if (!is_numeric($_GET['id'])) {
      log("Tentative de piratage : ".htmlentities($_GET['id']));
      die("Et non mon gars, ca marche pas comme ca !");
    }
    A noter que personnellement je log les erreurs de ce genre sur mon site, et que je vois régulierement des petits malins qui testent des 'or''='... je trouve ça tres marrant ;o) et puis comme ca, je me tiens au courant des nouvelles "methodes" d'injections sql o)

  15. #15
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    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 !

  16. #16
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Points : 1 565
    Points
    1 565
    Par défaut
    Citation Envoyé par Michel_57
    * 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 ?
    Le mieux est d'etre independant de l'hebergeur... comme ca, si tu change d'hebergeur, ou que free change son parametrage, ton script fonctionnera toujours.
    tu peux savoir dans ton script si l'option magic_quotes est activée avec get_magic_quotes_gpc()

    Citation Envoyé par Michel_57
    * et lorsque j'extrais les données de la base, je dois appliquer quelque chose ou rien du tout ?
    en principe rien

    Citation Envoyé par Michel_57
    * 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 ?
    toutes les données doivent, a l'affichage seulement, passer par un htmlentities() ou htmlspecialchars().
    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)

  17. #17
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    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

  18. #18
    Rédacteur

    Avatar de Yogui
    Homme Profil pro
    Directeur technique
    Inscrit en
    Février 2004
    Messages
    13 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yonne (Bourgogne)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Février 2004
    Messages : 13 721
    Points : 29 985
    Points
    29 985
    Par défaut
    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/

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Sécurité - Injection Sql
    Par bouuuh dans le forum Langage
    Réponses: 5
    Dernier message: 22/10/2011, 14h44
  2. [MySQL] Sécurité injection sql
    Par Souri84 dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 26/11/2010, 14h10
  3. [Sécurité] protections php pour XSS, injections SQL, etc
    Par nintendoplayer dans le forum Langage
    Réponses: 1
    Dernier message: 20/03/2008, 08h57
  4. [Sécurité] Injections SQL
    Par sway dans le forum Langage
    Réponses: 5
    Dernier message: 12/05/2007, 11h13
  5. Sécurité - Inject SQL et %
    Par bigsister dans le forum Requêtes
    Réponses: 14
    Dernier message: 01/04/2006, 09h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo