Eviter les injections de Sql

    Publicités

Users Who Are Viewing This Thread (Total: 0, Members: 0, Guests: 0)

Mangemoi

..::~~**~**~~::..
V
Ancien staff
Dec 4, 2009
4,086
2
764
That's is the question...
Bonjour !

Je vais, dans le tutorial qui va suivre, vous donner une formation basique sur les attaques SQL, communément appeler Injection SQL. Il est aussi évident que je vais aussi vous montrez comment vous protéger de ce type d'attaque. Vous pouvez voir dans la table des matières le déroulement de l'article. Il est aussi important de savoir que l'injection SQL est plus fréquente dans les scripts ASP ou JSP, à cause de leur configuration par défaut.



Table des matières :

1 . L'injection SQL en gros.

2 . Injection par SELECT / INSERT / UPDATE

3 . Comment se protége

4 . Conclusion / Référence




1. L'injection SQL en gros

Une injection SQL consiste à lire, écrire ou même supprimer des données. À première vue, nous pouvons penser que le plus grave est la suppression mais en fait les 3 sont aussi dangereux les un des autres, car si on peu lire, éventuellement, nous pourrons écrire si nous avons accès aux codes administratifs et encore supprimer.

Premier exemple, un administrateur configure mal un formulaire d'authentification. Quand l'utilisateur envoie les données, la requête SQL devrait ressembler à ça :

SELECT uid FROM members WHERE account='$var_login' AND password='$var_password'

Si nous prenons par exemple le login Terri et le password Monkey nous avons une requête qui ressemblera à :

SELECT uid FROM members WHERE account='Terri' AND password='Monkey'


Mais si le pirate décide de mettre le login : ' OR 1=1 et la même chose dans le password la requête va devenir :

SELECT uid FROM members WHERE account='' OR 1=1 AND password='' OR 1=1


La requête va prendre le premier compte de la liste (UID 1) et va renvoyer TRUE car 1=1. Alors le pirate va être sur le compte sans avoir le mot de passe. Disons que cet exemple est un peu tiré par les cheveux, mais il illustre bien le principe d'une injection SQL. En passant, le nombre de chance que vous trouvez une situation du genre est de 1 sur 1 000 000. Cet exemple est aussi valide si le pirate veut prendre un compte précis. Il suffit de mettre le login désiré et comme mot de passe : ' OR 1=1 ce qui va renvoyer TRUE.



2. Injection par SELECT / INSERT / UPDATE

Voici les 3 principales commandes du SQL. SELECT sert à récolter les données, INSERT sert à insérer des données dans une table existante et UPDATE sert à mettre à jour une ou des données entrées. Je ne vais pas entrer dans les détails des formulations des requêtes SQL car ce n'est pas le but de l'article et je considère que vous connaissez déjà le SQL.



2.1 SELECT

SELECT est le plus utilisé, car il sert à consulter la base de donnée. Il sert par exemple à l'authentification d'un compte ou encore la recherche d'information dans une BD (Base de Données). Le but principal d'une attaque SQL de base est que la requête renvoie vrai même quand c'est faux. Comme l'exemple plus haut il existe plusieurs façons de rendre une requête vraie. Voici une petite liste :

SELECT * FROM table WHERE 1=1
SELECT * FROM table WHERE 'uuu'='uuu'
SELECT * FROM table WHERE 1<>2
SELECT * FROM table WHERE 3>2
SELECT * FROM table WHERE 2<3
SELECT * FROM table WHERE 1
SELECT * FROM table WHERE 1
SELECT * FROM table WHERE 1--1
SELECT * FROM table WHERE ISNULL(NULL)
SELECT * FROM table WHERE ISNULL(COT(0))
SELECT * FROM table WHERE 1 IS NOT NULL
SELECT * FROM table WHERE NULL IS NULL
SELECT * FROM table WHERE 2 BETWEEN 1 AND 3
SELECT * FROM table WHERE 'b' BETWEEN 'a' AND 'c'
SELECT * FROM table WHERE 2 IN (0,1,2)
SELECT * FROM table WHERE CASE WHEN 1>0 THEN 1 END
Référence : Voir chapitre 4

Maintenant, je vais vous montrer une des principaux principes de l'injection SQL, les commentaires. Le caractère # fait que le reste de la requête (après le #) est ignorer par la DB. Les caractères /* et */ mettrons tout ce qu'il y a entre les 2 en commentaire. Par exemple, vous entrez le login : Terri'#

SELECT * FROM membres WHERE account='Terri' # ' AND password='$var_password'


Alors il va prendre le compte Terri en ignorant le mot de passe. C'est encore une injection plutôt rare. J'ai oublié de mentionner que les attaques SQL demande de la patience et de la persévérance mais je ne suis pas ici pour vous montrer comment démolir un site, mais plutôt pour vous protéger en les évitants.

Avec de l'imagination et une bonne connaissance du SQL vous pouvez récupérer le compte et mot de passe de l'administrateur si le site est mal protégé. Mais comme je l'ai dit plus haut ce n'est pas facile du tout au contraire car la plupart des sites sont bien protégés.

Je vais maintenant passer au INSERT et par la suite le UPDATE.



2.2 INSERT

Une requête INSERT est faite pour ajouter des données dans une table existante. Les cas d'injection par INSERT sont plus rares mais il en existe quelques un. Par exemple une requête INSERT peut ressembler à cela :

INSERT INTO membres (login,password,nom,prenom,email,level) VALUES ('$login','$password','$nom','$prenom','$email','$level')

Si le pirate écrit, dans le champ du email, le code suivant : Ce lien n'est pas visible, veuillez vous connecter pour l'afficher. Je m'inscris!', '1'# la requête deviendra :

INSERT INTO membres (login,password,nom,prenom,email,level) VALUES ('Terri','MonPass','Terri','Terri','[email protected]',1'# ','$level')

Alors le pirate aura le level 1 qui peut vouloir dire par exemple : 1=Administrateur, 2= Modérateur et 3=Utilisateur.

Le problème de ce type d'attaque c'est qu'il faut savoir comment est construit la requête SQL. C'est pour cela que ce genre d'attaque est plus présent dans les systèmes pré faits où le code source est public. Mais il existe des méthodes pour réussir à reconstruire la requête SQL, mais ce n'est pas encore le but de l'article.



2.3 UPDATE

Les requêtes UPDATE sont faites pour mettre à jour des données déjà présente dans la DB. Les injections UPDATE sont encore moins présentes que les injections INSERT, mais ça l'existe.

Nous pouvons trouver des requêtes du genre quand il est temps de changer les informations du compte (mot de passe, email, etc..). Alors une requête pourrait ressembler à cela :

UPDATE membres SET password='$var_pass',nom='$var_nom',email='$var_email' WHERE id='$id'

Ici par exemple nous pourrions changer une valeur que nous ne sommes pas supposer changer. Par exemplesi nous inscrivons dans le champ du mot de passe le code suivant : ',level='3 le code deviendrait le suivant.

UPDATE membres SET password='',level='3',nom='$var_nom',email='$var_email' WHERE id='$id'

Alors le pirate deviendrait administrateur du site en question. C'est sur que cet exemple est encore tiré par les cheveux car il est rare qu'un site accepte un compte sans mot de passe. Il serait mieux de prendre le champ nom ou encore d'écrire quelque chose de bidon dans le champ avant de faire l'injection. Je vous laisse imaginer les possibilités.

Je ne voie pas vraiment l'intérêt de s'attarder encore plus sur l?UPDATE car les cas de faille UPDATE sont très rares et encore plus dur à trouver.



3. Comment se protéger

Il est certain de que la protection à 100% contre les injections SQL est quasiment impossible si ce ne l'est pas. Mais je vais quand même vous montrer quelques trucs pour éviter se genre de faille qui peuvent vous faire perdre beaucoup.

Premièrement, le plus important, filtrer les variables dans les formulaires. Moi personnellement j'utilise une fonction PHP qui me permet de savoir si il a un espace ou tous autres caractères spéciaux non désirés. Il est aussi important de préciser que si vous protéger votre formulaire par une fonction JavaScript un pirate va recopier votre formulaire et exploiter en local rien de plus facile, alors à ne pas faire.

Il existe aussi la commende 'htmlentities' qui convertie tous les caractères éligibles en entités HTML. Ce qui empêche les attaques Injection et XSS (Cross Scripting) peut être le sujet d?un autre tutorial.

Mais comme je l'ai dit précédemment, les web masters ne sont pas stupides, ils vont protéger leur site le mieux possible, alors ne vous attendez pas a trouver une faille SQL en 2 temps 3 mouvements.



4. Conclusion / Référence

Pour conclure ce tutorial, il est aussi bon de savoir les autres sortent de failles car si vous n'avez aucune faille SQL il se peu que vous aillez plusieurs failles de types différents. Le pirate ne va pas juste chercher les failles SQL mais va aussi tenter de BruteForcer votre FTP par exemple. Je vous laisse sur cette conclusion, peu rassurante, en vous disant qu?il faut mieux filtrer 2 fois les variables plutôt qu?une.

Référence :

Ce lien n'est pas visible, veuillez vous connecter pour l'afficher. Je m'inscris!
 

killer04

Nouveau membre
Jan 1, 2010
2
0
561
38
On peut pas s'en protéger tous simplement avec un mysql_real_escape_string(htmlspecialchars($variable_en_relation_avec_la_BDD)); ????
 

noname

Membre
Jan 11, 2010
23
0
566
Je crois que si c'était aussi simple, le créateur du texte, bah l'aurait pas créer. Non ?
 

triple15

Membre actif
Dec 17, 2009
214
0
576
L'injection et veuille comme le monde . Les 3/4 du web sont patcher contre c'est attaque . Mais elle reste redoutable quand elle marche surtout quand la " table_ " viser et une "table_User" .

Sinon bon tuto .
 

Connard95

Membre
Aug 7, 2010
12
0
426
32
On peut aussi, bloquer toutes les ' '' ? % qui passe sur l'URL avec un code PHP, mais ça n'arrête pas les injections sql par requête POST.

à+
 

adimea

Membre
Feb 11, 2010
10
0
561
Il est possible de s'en protéger assez facilement en fait...

Déjà, utilisez mysql_query(' XXX '); et non pas mysql_query(" XXX ");
Ensuite, une montagne de fonctions existe afin de ne pas être embêté par des failles SQL.

Imaginons :

Je me connecte avec un compte et un mdp.
Les donnés reçues sont donc :
$_POST['compte'] et $_POST['mdp']

Il suffira de faire
PHP:
$compte = strip_tags(trim(htmlspecialchars($_POST['compte'])));
$mdp = strip_tags(trim(htmlspecialchars($_POST['mdp']))); //(si il n'es pas crypté... >.>)

$correct_ou_pas = mysql_num_rows(mysql_query('SELECT id FROM compte WHERE compte="'. $compte .'" AND mdp = "'. $mdp .'"'));
if($correct_ou_pas == 1)
{
   echo 'Connecté !';
}
else
{
 echo 'Combinaison incorrecte.';
}

Et c'est sans faille.

Adimea.