Derniers tutoriels de développement web
 

SQL Injection


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();