Une injection SQL peut détruire votre base de données.
SQL dans les pages Web
Dans les chapitres précédents, vous avez appris à récupérer (et mise à jour) les données de base de données, en utilisant SQL.
Lorsque SQL est utilisé pour afficher les données sur une page web, il est courant de laisser entrée des utilisateurs web leurs propres valeurs de recherche.
Depuis les instructions SQL sont uniquement du texte, il est facile, avec un petit morceau de code informatique, pour modifier dynamiquement les instructions SQL pour fournir à l'utilisateur avec des données sélectionnées:
Code Serveur
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *
FROM Users WHERE UserId = " + txtUserId;
L'exemple ci-dessus, crée une instruction select en ajoutant une variable (txtUserId) à une chaîne de sélection. La variable est extraite de l'entrée d'utilisateur (demande) à la page.
Le reste de ce chapitre décrit les dangers potentiels de l'utilisation d'entrée de l'utilisateur dans les instructions SQL.
Injection SQL
injection SQL est une technique où les utilisateurs malveillants peuvent injecter des commandes SQL dans une instruction SQL, via la page Web d'entrée.
commandes SQL Injecté peuvent modifier l'instruction SQL et compromettre la sécurité d'une application Web.
SQL Injection Basé sur 1 = 1 est toujours vrai
Regardez l'exemple ci-dessus, une fois de plus.
Disons que l'objectif initial du code était de créer une instruction SQL pour sélectionner un utilisateur avec un identifiant d'utilisateur donné.
S'il n'y a rien pour empêcher un utilisateur d'entrer dans "wrong" entrée, l'utilisateur peut entrer dans un certain "smart" entrée comme ceci:
Identifiant d'utilisateur:
serveur Résultat
SELECT * FROM Users WHERE UserId = 105 or 1=1
Le SQL ci-dessus est valable. Il retournera toutes les lignes des utilisateurs de table, puisque WHERE 1 = 1 est toujours vrai.
Est-ce que l'exemple ci-dessus semblent dangereux? Que faire si la table des utilisateurs contient les noms et mots de passe?
L'instruction SQL ci-dessus est la même que celle-ci:
SELECT UserId, Name, Password
FROM Users WHERE UserId = 105 or 1=1
Un pirate intelligent pourrait avoir accès à tous les noms d'utilisateur et mots de passe dans une base de données en insérant simplement 105 ou 1 = 1 dans la zone de saisie.
SQL Injection Basé sur ""="" est toujours vrai
Voici une construction commune, utilisée pour vérifier la connexion utilisateur à un site web:
Nom d'utilisateur:
Mot de passe:
Code Serveur
uName = getRequestString("UserName");
uPass = getRequestString("UserPass");
sql = "SELECT * FROM Users WHERE Name ='" + uName + "' AND Pass ='" + uPass + "'"
Un pirate intelligent pourrait avoir accès aux noms d'utilisateur et mots de passe dans une base de données en insérant simplement "ou ""=" dans la zone de texte de nom ou mot de passe utilisateur.
Le code sur le serveur va créer une instruction SQL valide comme ceci:
Résultat
SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""
Le résultat SQL est valide. Il retournera toutes les lignes des utilisateurs de table, puisque WHERE "" = "" est toujours vrai.
SQL Injection Basé sur instructions SQL batched
La plupart des bases de données prennent en charge l'instruction SQL batched, séparés par des points-virgules.
Exemple
SELECT * FROM Users; DROP TABLE Suppliers
Le SQL ci-dessus renverra toutes les lignes de la table des utilisateurs, puis supprimer la table appelés Fournisseurs.
Si nous avions le code serveur suivant:
Code Serveur
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *
FROM Users WHERE UserId = " + txtUserId;
Et l'entrée suivante:
Identifiant d'utilisateur:
Le code sur le serveur créerait une instruction SQL valide comme ceci:
Résultat
SELECT * FROM Users WHERE
UserId = 105; DROP TABLE Suppliers
Paramètres de protection
Certains développeurs web utilisent une "blacklist" des mots ou des caractères à rechercher dans l' entrée SQL, pour empêcher des attaques SQL.
Ce n'est pas une très bonne idée. Beaucoup de ces mots (comme supprimer ou drop) et les caractères (comme des points-virgules et les guillemets), sont utilisés dans le langage courant, et devraient être autorisés dans de nombreux types d'entrée.
(En fait, il devrait être parfaitement légal pour entrer une instruction SQL dans un champ de base de données.)
Le seul moyen éprouvé pour protéger un site web à partir attaques par injection SQL, est d'utiliser les paramètres SQL.
SQL paramètres sont des valeurs qui sont ajoutées à une requête SQL au moment de l'exécution, d'une manière contrôlée.
ASP.NET Razor Exemple
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *
FROM Users WHERE UserId = @0";
db.Execute(txtSQL,txtUserId);
Notez que les paramètres sont représentés dans l'instruction SQL par un @ marqueur.
Le moteur SQL vérifie chaque paramètre pour vous assurer qu'il est correct pour sa colonne et sont traités littéralement, et non dans le cadre du SQL à exécuter.
Un autre exemple
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City)
Values(@0,@1,@2)";
db.Execute(txtSQL,txtNam,txtAdd,txtCit);
Vous venez d'apprendre pour éviter l'injection SQL. L'un des sites Web haut vulnérabilités.
Exemples
Les exemples suivants montrent comment construire des requêtes paramétrées dans certains langages web communs.
Instruction SELECT dans ASP.NET:
txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserID);
command.ExecuteReader();
INSERT INTO EN ASP.NET:
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City)
Values(@0,@1,@2)";
command = new SqlCommand(txtSQL);
command.Parameters.AddWithValue("@0",txtNam);
command.Parameters.AddWithValue("@1",txtAdd);
command.Parameters.AddWithValue("@2",txtCit);
command.ExecuteNonQuery();
INSERT INTO EN PHP:
$stmt = $dbh->prepare("INSERT INTO Customers (CustomerName,Address,City)
VALUES (:nam, :add, :cit)");
$stmt->bindParam(':nam', $txtNam);
$stmt->bindParam(':add', $txtAdd);
$stmt->bindParam(':cit', $txtCit);
$stmt->execute();