Comment Protéger ses Applications Contre les Injections SQL ?

Les injections SQL (SQL Injection) sont l’une des attaques les plus courantes et les plus dangereuses contre les applications web. Elles permettent à un attaquant d’exécuter des commandes SQL malveillantes pour voler des données, modifier la base de données ou prendre le contrôle du serveur.

Dans cet article, nous allons voir comment fonctionnent les injections SQL et les meilleures pratiques pour sécuriser votre application.


1. Qu’est-ce qu’une Injection SQL ?

Une injection SQL se produit lorsqu’une application insère directement des entrées utilisateur dans une requête SQL sans validation ni protection.

📌 Exemple d’une application vulnérable

Imaginons une page de connexion qui vérifie l’utilisateur avec cette requête SQL :

sqlCopierModifierSELECT * FROM users WHERE username = 'admin' AND password = '1234';

Si le développeur ne protège pas ses requêtes, un attaquant peut entrer la valeur suivante dans le champ username :

bashCopierModifier' OR '1'='1

La requête devient alors :

sqlCopierModifierSELECT * FROM users WHERE username = '' OR '1'='1' AND password = '1234';

Résultat : L’attaquant accède au compte sans connaître le mot de passe !


2. Conséquences des Injections SQL

Une attaque SQL Injection peut causer :
Vol de données sensibles (identifiants, cartes bancaires, emails, etc.).
Modification ou suppression des données.
Exécution de commandes malveillantes sur le serveur.
Prise de contrôle total de la base de données.


3. Comment Protéger son Application Contre les Injections SQL ?

1️⃣ Utiliser des Requêtes Préparées (Prepared Statements)

La meilleure défense contre les injections SQL est d’utiliser des requêtes préparées, qui séparent le code SQL des données de l’utilisateur.

✅ Exemple en Python avec MySQL

pythonCopierModifierimport mysql.connector

conn = mysql.connector.connect(user='root', password='password', database='test_db')
cursor = conn.cursor()

username = input("Entrez votre nom d'utilisateur : ")
password = input("Entrez votre mot de passe : ")

query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password))

result = cursor.fetchall()
print(result)

✔ Ici, les valeurs sont traitées comme des données, et non comme du code SQL exécutable.

✅ Exemple en PHP avec PDO

phpCopierModifier$conn = new PDO("mysql:host=localhost;dbname=test_db", "root", "password");

$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
$stmt->execute();

$result = $stmt->fetch();
print_r($result);

Aucun risque d’injection SQL avec cette méthode.


2️⃣ Ne Jamais Insérer Directement des Entrées Utilisateur

Mauvaise pratique (vulnérable)

phpCopierModifier$query = "SELECT * FROM users WHERE username = '" . $_GET['username'] . "'";

Bonne pratique : toujours valider et échapper les entrées utilisateur.


3️⃣ Échapper les Entrées Utilisateur

Si vous utilisez encore des requêtes dynamiques (non recommandées), vous devez protéger les entrées utilisateur.

✅ Exemple en PHP avec mysqli_real_escape_string()

phpCopierModifier$username = mysqli_real_escape_string($conn, $_GET['username']);
$query = "SELECT * FROM users WHERE username = '$username'";

Attention ! Cette méthode n’est pas aussi efficace que les requêtes préparées.


4️⃣ Appliquer le Principe du Moindre Privilège

Limitez les permissions des comptes de base de données :
Créez un utilisateur avec un accès RESTREINT (pas d’accès en écriture ou suppression si non nécessaire).

sqlCopierModifierCREATE USER 'app_user'@'localhost' IDENTIFIED BY 'secure_password';
GRANT SELECT ON my_database.* TO 'app_user'@'localhost';

Évitez d’utiliser l’utilisateur root pour se connecter à la base.


5️⃣ Désactiver l’Affichage des Erreurs en Production

Mauvaise pratique : afficher les erreurs SQL dans le navigateur.

phpCopierModifierecho "Erreur SQL : " . mysqli_error($conn);

Bonne pratique :

phpCopierModifierif ($debug_mode) {
    error_log("Erreur SQL : " . mysqli_error($conn));
}

Cela empêche un attaquant de voir des informations sensibles sur votre base de données.


6️⃣ Limiter les Tentatives de Connexion (Protection Contre les Attaques Brute-Force)

Implémentez un système de limitation des tentatives de connexion.

✅ Exemple en PHP

phpCopierModifierif ($_SESSION['failed_attempts'] > 5) {
    die("Trop de tentatives. Veuillez réessayer plus tard.");
}

✔ Utilisez aussi reCAPTCHA ou authentification multi-facteurs (MFA).


7️⃣ Analyser et Sécuriser Votre Code Régulièrement

Utilisez des outils de sécurité pour détecter les failles SQL Injection :
🔹 OWASP ZAP – Scanner de sécurité pour applications web.
🔹 SQLMap – Outil de test d’injection SQL.
🔹 Snyk – Analyse de sécurité des dépendances.


4. Exemple de Code Sécurisé Complet

Un exemple sécurisé en Python avec Flask et MySQL :

pythonCopierModifierfrom flask import Flask, request
import mysql.connector

app = Flask(__name__)

conn = mysql.connector.connect(user='root', password='password', database='test_db')
cursor = conn.cursor()

@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']
    password = request.form['password']

    query = "SELECT * FROM users WHERE username = %s AND password = %s"
    cursor.execute(query, (username, password))

    if cursor.fetchone():
        return "Connexion réussie !"
    else:
        return "Identifiants incorrects."

if __name__ == '__main__':
    app.run(debug=False)

Ce code utilise des requêtes préparées et ne stocke pas les mots de passe en clair.


Conclusion

Les injections SQL sont une menace critique pour les applications web. Pour protéger votre application :

Utilisez toujours des requêtes préparées.
Ne faites jamais confiance aux entrées utilisateur.
Appliquez le principe du moindre privilège sur la base de données.
Désactivez l’affichage des erreurs en production.
Analysez régulièrement votre code avec des outils de sécurité.

🚀 Une application sécurisée est une application fiable et professionnelle !

carle
carle