Quelqu'un peut-il expliquer l'injection SQL ? Comment provoque-t-elle des vulnérabilités ? Où se trouve exactement le point où le SQL est injecté ?
Réponses
Trop de publicités?Quelqu'un peut-il expliquer l'injection SQL ?
L'injection SQL se produit lorsque vous interpolez du contenu dans une chaîne de requête SQL, et que le résultat modifie la syntaxe de votre requête d'une manière que vous n'aviez pas prévue.
Ce n'est pas forcément malveillant, ça peut être un accident. Mais une injection SQL accidentelle a plus de chances d'aboutir à une erreur qu'à une vulnérabilité.
Le contenu préjudiciable ne doit pas nécessairement provenir d'un utilisateur, il peut s'agir d'un contenu que votre application obtient de n'importe quelle source, ou même qu'elle génère elle-même dans le code.
Comment cela provoque-t-il des vulnérabilités ?
Elle peut conduire à des vulnérabilités car les attaquants peuvent envoyer à une application des valeurs dont ils savent qu'elles seront interpolées dans une chaîne SQL. En étant très malins, ils peuvent manipuler le résultat des requêtes, lire des données ou même modifier des données qu'ils ne devraient pas être autorisés à faire.
Exemple en PHP :
$password = $_POST['password'];
$id = $_POST['id'];
$sql = "UPDATE Accounts SET PASSWORD = '$password' WHERE account_id = $id";
Supposons maintenant que l'attaquant fixe les paramètres de la requête POST à " password=xyzzy
" et " id=account_id
", ce qui donne le SQL suivant :
UPDATE Accounts SET PASSWORD = 'xyzzy' WHERE account_id = account_id
Bien que je m'attendais $id
pour être un nombre entier, l'attaquant a choisi une chaîne de caractères qui est le nom de la colonne. Bien sûr, maintenant la condition est vraie sur chaque l'attaquant vient donc de définir le mot de passe de l'option chaque compte. L'attaquant peut maintenant se connecter au compte de n'importe qui, y compris les utilisateurs privilégiés.
Où se trouve exactement le point où le SQL est injecté ?
Ce n'est pas le SQL qui est injecté, c'est le contenu qui est interpolé ("injecté") dans une chaîne SQL, ce qui donne un type de requête différent de celui que j'avais prévu. J'ai fait confiance au contenu dynamique sans le vérifier, et j'ai exécuté aveuglément la requête SQL qui en résultait. C'est là que les problèmes commencent.
L'injection SQL est une faille dans le code de l'application, et non généralement dans la base de données ou dans la bibliothèque ou le cadre d'accès à la base de données.
La plupart des cas d'injection SQL peuvent être évités en utilisant des paramètres de requête. Voir Comment prévenir l'injection SQL en PHP ? par exemple.
L'injection SQL se produit lorsque l'utilisateur d'une application est capable d'affecter la signification d'une requête de base de données. Cela se produit souvent lorsque des chaînes arbitraires provenant de l'entrée de l'utilisateur sont concaténées pour créer un SQL qui est transmis à la base de données. Par exemple, imaginons que nous ayons le code suivant (en PHP, mais la même chose est valable pour n'importe quel langage), qui pourrait être utilisé pour gérer la connexion d'un utilisateur.
$sql = "SELECT FROM users WHERE username='".$_GET['username']."' AND password='".$_GET['password']."'";
Le mal est fait lorsque l'utilisateur entre quelque chose comme
administrator'; --
... pour le nom d'utilisateur. Sans un encodage approprié, la requête devient :
SELECT * FROM users WHERE username='administrator'; -- AND password=''
Le problème ici est que le ' dans le nom d'utilisateur ferme le champ du nom d'utilisateur, puis le -- commence un commentaire SQL, ce qui fait que le serveur de base de données ignore le reste de la chaîne. Le résultat net est que l'utilisateur peut maintenant se connecter en tant qu'administrateur sans avoir à connaître le mot de passe. La connexion SQL peut également être utilisée pour exécuter des requêtes UPDATE, DELETE ou DROP et endommager réellement la base de données.
L'injection SQL peut être évitée en utilisant des requêtes paramétrées ou en appliquant les fonctions d'échappement de votre langage/outil (comme mysql_real_escape_string() en PHP).
Une fois que vous aurez compris l'injection SQL, vous comprendrez la blague derrière ce dessin animé .
L'injection SQL, c'est quand des choses qui sont censées être des données sont traitées comme du code SQL sans le vouloir.
Par exemple, si vous faites
mysql_query("SELECT * FROM posts WHERE postid=$postid");
Normalement, cela devrait vous permettre d'obtenir le message avec un id donné, mais supposez que $postid
est défini comme la chaîne de caractères 10; DROP TABLE posts --
tout d'un coup, la requête que vous envoyez est
mysql_query("SELECT * FROM posts WHERE postid=10; DROP TABLE posts --");
C'est un problème, car vous perdriez l'intégralité de votre table des messages à cause d'un utilisateur malveillant - oh là là.
La manière la plus simple d'éviter cela est d'utiliser des instructions préparées, par exemple par le biais de AOP ou MySQLi .
L'exemple équivalent dans PDO serait alors
$statement = $db->prepare('SELECT * FROM posts WHERE postid = :postid');
$statement->bindValue(':postid', $postid);
$statement->execute();
Cela garantit que le système de base de données sait que $postid doit être traité comme une donnée et non comme un code, et qu'il sera donc traité de manière appropriée.
Cette question a reçu de nombreuses réponses sur StackOverflow, mais il s'agit d'un sujet important à connaître pour tout le monde, donc je ne vais pas voter pour fermer cette question.
Voici des liens vers certaines de mes réponses passées sur ce sujet :
- Qu'est-ce que l'injection SQL ?
- Comment protéger cette fonction contre l'injection SQL ?
- Les paramètres sont-ils vraiment suffisants pour empêcher les injections Sql ?
- L'injection SQL est-elle un risque aujourd'hui ?
J'ai également donné une présentation à la conférence MySQL ce mois-ci, et mes diapositives sont en ligne :
Il existe de nombreuses ressources sur le web - il suffit de les chercher sur Google :
http://en.wikipedia.org/wiki/SQL_Injection est un bon point de départ.
- Réponses précédentes
- Plus de réponses