logo

Injection SQL

L'injection SQL est une faille de sécurité dans les applications Web dans laquelle les attaquants insèrent du code SQL nuisible via la saisie de l'utilisateur. Cela peut leur permettre d’accéder au contenu de la base de données de modifications de données sensibles ou même de prendre le contrôle du système. Il est important de connaître l'injection SQL pour assurer la sécurité des applications Web.

L'injection SQL (SQLi) est une vulnérabilité de sécurité qui se produit lorsqu'un attaquant peut manipuler les requêtes de base de données d'une application Web en insérant du code SQL malveillant dans les champs de saisie utilisateur. Ces requêtes injectées peuvent manipuler la base de données sous-jacente pour récupérer, modifier ou supprimer des données sensibles. Dans certains cas, les attaquants peuvent même élever leurs privilèges pour obtenir un contrôle total sur la base de données ou le serveur.



injection SQL' title=

Exemple concret :

En 2019, la violation de données de Capital One s'est produite en raison d'une application Web mal configurée qui a permis à un attaquant d'exploiter une vulnérabilité d'injection SQL. Cela a entraîné la fuite des données personnelles de plus de 100 millions de clients, y compris les noms, adresses et cotes de crédit.

Niveau de sécurité des injections SQL

DVWA propose quatre niveaux de sécurité pour l'injection SQL afin d'aider les apprenants à voir comment les différentes protections affectent les attaques :



1. Faible sécurité

L'application prend votre entrée et la place directement dans la requête SQL sans filtrage.

$id = $_GET['id'];$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';
  • Entrer ': Rompt la requête et oblige la base de données à générer une erreur révélant qu'elle est vulnérable.
  • Entrer 1' OR '1'='1: Fait en sorte que la requête soit toujours vraie afin que tous les utilisateurs soient renvoyés.
  • Entrer 1' UNION SELECT user password FROM users--: Rejoint une autre requête pour récupérer des données cachées telles que des noms d'utilisateur et des mots de passe.

2. Sécurité moyenne

L'application applique une désinfection de base des entrées à l'aide de fonctions telles queaddslashes()s'échapper'.

$id = addslashes($_GET['id']);$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';

Comment peut-on attaquer :



Un simple'l’injection ne fonctionnera plus (car elle devient').

Mais les attaquants peuvent toujours contourner l’injection numérique (puisque les nombres n’ont pas besoin de guillemets).
Exemple:

java obtient l'heure actuelle
1 OR 1=1

Cela renvoie toujours tous les enregistrements.

3. Haute sécurité

L'application utilise des instructions préparées (requêtes paramétrées) pour gérer en toute sécurité les entrées de l'utilisateur.

$stmt = $pdo->prepare('SELECT first_name last_name FROM users WHERE user_id = ?');$stmt->execute([$id]);

Attaque:

Des tentatives comme' OR 1=1ouUNION SELECTne fonctionne plus.

La requête traite toutes les entrées comme des données et non comme du code SQL.

Types d'injection SQL

Il existe différents types d'injection SQL

1. Injection SQL basée sur les erreurs

L'injection SQL basée sur les erreurs est un type d'injection SQL intrabande dans lequel un attaquant amène intentionnellement la base de données à générer un message d'erreur. L'attaquant analyse ensuite ce message d'erreur pour obtenir des informations précieuses sur la structure de la base de données, telles que les noms de tables et de colonnes, qui peuvent être utilisées pour élaborer d'autres attaques plus précises.

Comment ça marche

Cette attaque cible les applications qui révèlent des erreurs brutes de base de données au lieu d'afficher des messages génériques. En injectant une entrée malveillante qui brise la syntaxe SQL, les attaquants déclenchent ces erreurs et obtiennent des indices précieux sur la structure de la base de données.

listes en java
  1. Identifiez une entrée vulnérable : L'attaquant trouve un champ de saisie comme une barre de recherche ou un paramètre d'URL qui interagit directement avec la base de données sans vérification appropriée des entrées.
  2. Injecter une charge utile malveillante : L'attaquant injecte un caractère spécial (comme un guillemet simple') ou une fonction connue pour provoquer une erreur de base de données.
  3. Analysez l'erreur : La base de données incapable de traiter la requête mal formée renvoie un message d'erreur détaillé. Ce message peut révéler des informations cruciales telles que :
    • Le système de base de données (par exemple MySQL Oracle SQL Server).
    • La version de la base de données.
    • La requête SQL complète en cours d'exécution.
    • Erreurs de syntaxe spécifiques pouvant être utilisées pour comprendre les noms de tables ou de colonnes.
  4. Affiner l'attaque : En utilisant les informations recueillies à partir du message d'erreur, l'attaquant peut affiner sa charge utile pour extraire davantage de données telles que les noms d'utilisateur et les mots de passe.

Exemple:

Étape 1 : Configurez votre environnement

  • Lancez DVWA. On y accède généralement en accédant à une URL telle quehttp://localhost/dvwadans votre navigateur.
déposer' loading='lazy' title=
  • Connectez-vous à DVWA avec les informations d'identification par défaut :admin/password.
déposer' loading='lazy' title=
  • Accédez à l’onglet Sécurité DVWA et définissez le niveau de sécurité sur faible. Cela garantira que les vulnérabilités sont faciles à exploiter.
déposer' loading='lazy' title=

Étape 2 : identifier la vulnérabilité

La page Injection SQL comporte une simple zone de saisie dans laquelle vous pouvez saisir un ID utilisateur. La requête backend ressemble probablement à quelque chose commeSELECT * FROM users WHERE id = 'user_input'

  • Entrez un identifiant valide comme1dans la zone de saisie et cliquez sur « Soumettre ». Vous devriez voir les détails de l’utilisateur avec l’ID 1.
déposer' loading='lazy' title=

Source d'injection SQL

PHP
 $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( '
' . ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ode ?>
  • Essayez maintenant d'interrompre la requête. Entrez un seul devis'dans la zone de saisie et soumettez.
déposer' loading='lazy' title=

La requête devient :

SELECT * FROM users WHERE id = ''';

Ici, la base de données voit un devis supplémentaire et ne sait pas comment compléter la requête.

qu'est-ce que mon espace

Au lieu de vous montrer les détails de l'utilisateur, l'application renverra une erreur SQL (quelque chose comme « Vous avez une erreur dans votre syntaxe SQL… »)

C'est ce qu'on appelle l'injection SQL basée sur les erreurs car :

  • L'attaquant envoie une entrée invalide (')
  • La base de données renvoie une erreur
  • Cette erreur divulgue des informations utiles sur la base de données (comme le type de base de données, le nombre de colonnes, etc.)

2. Injection SQL basée sur l'union

L'injection SQL basée sur l'Union est une technique dans laquelle les attaquants utilisent leUNIONopérateur pour combiner les résultats de deux ou plusieursSELECTinstructions dans un seul jeu de résultats. Cela peut leur permettre d'extraire des informations d'autres tables de la base de données. LeUNIONL’opérateur ne peut être utilisé que si :

  • Les deux requêtes ont le même nombre de colonnes
  • Les colonnes ont des types de données similaires
  • Les colonnes sont dans le même ordre

Opérateur UNION : LeUNIONL’opérateur est utilisé pour combiner l’ensemble de résultats de deux ou plusieursSELECTdéclarations.

  • ChaqueSELECTdéclaration dansUNIONdoit avoir le même nombre de colonnes
  • Les colonnes doivent avoir des types de données similaires
  • Les colonnes doivent être dans le même ordre
SELECT column_name(s) FROM table1UNIONSELECT column_name(s) FROM table2

Exemple:

Étape 1 : Tout d’abord, nous devons trouver le nombre de colonnes de la table existante sur le site Web pour injecter l’injection SQL basée sur UNION :

La page Injection SQL comporte une simple zone de saisie dans laquelle vous pouvez saisir un ID utilisateur. La requête backend ressemble probablement à quelque chose comme

 SELECT * FROM users WHERE id = 'user_input'

Essayez maintenant d'interrompre la requête. Entrez un seul devis'dans la zone de saisie et soumettez.

Si l'application est vulnérable, vous recevrez un message d'erreur détaillé. Cela pourrait ressembler à quelque chose comme :

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1

Étape 2 : Utilisez leUNIONMot-clé pour découvrir le nombre de colonnes

Pour utiliser leUNIONmot-clé (une étape suivante courante), vous devez connaître le nombre de colonnes dans la requête d'origine. Vous pouvez le découvrir en utilisant leORDER BYclause

chaîne Java
  • Essayez de trier les résultats par colonne
1: 1 ORDER BY 1. 
  • Soumettre. Cela devrait fonctionner.
déposer' loading='lazy' title=

Source d'injection SQL

PHP
 if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( '
' . ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '
'
); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo '
ID: {$id}  
First name:
{$first}
Surname:
{$last}
'
; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ?>
  • Incrémentez le nombre :
 1 ORDER BY 2. 

Soumettre. Cela devrait fonctionner.

déposer' loading='lazy' title=
  • Continuez à incrémenter jusqu'à ce que vous obteniez une erreur. Par exemple1 ORDER BY 4pourrait vous donner:Unknown column '4' in 'order clause'
  • Cela signifie que la requête comporte 3 colonnes.

3. Injection SQL aveugle

Injection SQL aveugle se produit lorsque les attaquants ne peuvent pas voir les résultats de la requête directement sur la page Web. Au lieu de cela, ils déduisent des informations de changements subtils dans le comportement ou le temps de réponse de l’application. Bien que plus lent et fastidieux que le SQLi classique, il peut être tout aussi efficace.

Au lieu de récupérer les données, l'attaquant déduit des informations en observant le comportement de la page Web. Cela se fait généralement de deux manières :

  1. SQLi aveugle basé sur des booléens : L'attaquant injecte une requête SQL qui renvoie un vrai ou FAUX résultat. La réponse de l'application Web change selon que la requête est vraie ou fausse. Par exemple, la page peut afficher un message différent ou afficher une mise en page différente.
  2. SQLi aveugle basé sur le temps : L'attaquant injecte une requête SQL qui amène la base de données à effectuer une action chronophage (comme uneSLEEP()fonction) si une condition est remplie. L'attaquant observe le temps nécessaire au chargement de la page pour déterminer si la condition injectée était vraie ou fausse.

Exemple:

Imaginez une page de connexion où vous entrez un nom d'utilisateur et un mot de passe. L'application construit une requête SQL comme celle-ci :

SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input'

Une injection SQL aveugle impliquerait de manipuler leuser_inputchamp pour poser une question à la base de données.

Au lieu d'obtenir une réponse directe, l'attaquant pourrait essayer quelque chose comme ceci :

user_input = 'admin' AND 1=1; --

Si la page se charge normalement, l'attaquant sait que1=1est un vrai déclaration.

user_input = 'admin' AND 1=2; --

Si la page affiche une erreur ou se comporte différemment, l'attaquant sait que1=2est un FAUX déclaration.

déposer' loading='lazy' title=

En utilisant une série de ces questions vrai/faux, un attaquant peut systématiquement deviner et extraire des informations un caractère à la fois. Le processus peut être automatisé pour tout deviner, des noms de tables aux mots de passe des utilisateurs.

Impact des attaques par injection SQL

  • Accès non autorisé à des données sensibles : Les attaquants peuvent récupérer des informations financières personnelles ou confidentielles stockées dans la base de données.
  • Problèmes d'intégrité des données : Les attaquants peuvent modifier, supprimer ou corrompre les données critiques, ce qui a un impact sur les fonctionnalités de l'application.
  • Élévation de privilèges : Les attaquants peuvent contourner les mécanismes d'authentification et obtenir des privilèges administratifs.
  • Temps d'arrêt des services : L'injection SQL peut surcharger le serveur, provoquant une dégradation des performances ou des pannes du système.
  • Dommages à la réputation : Une attaque réussie peut gravement nuire à la réputation d'une organisation, entraînant une perte de confiance des clients.

Prévenir les attaques par injection SQL

Il existe plusieurs bonnes pratiques pour prévenir les attaques par injection SQL :

1. Utilisez des instructions préparées et des requêtes paramétrées

Les instructions préparées et les requêtes paramétrées garantissent que les entrées utilisateur sont traitées comme des données plutôt que comme une partie de la requête SQL. Cette approche élimine le risque d’injection SQL.

Exemple en PHP (en utilisant MySQLi) :

$stmt = $conn->prepare('SELECT * FROM users WHERE username = ? AND password = ?'); $stmt->bind_param('ss' $username $password); $stmt->execute();

2. Utiliser des procédures stockées

Les procédures stockées sont des requêtes SQL prédéfinies stockées dans la base de données. Ces procédures peuvent contribuer à empêcher l’injection SQL, car elles ne construisent pas dynamiquement les requêtes SQL.

Exemple:

CREATE PROCEDURE GetUserByUsername (IN username VARCHAR(50)) BEGIN SELECT * FROM users WHERE username = username; END;

3. Validation des entrées de la liste blanche

Assurez-vous que les entrées utilisateur sont validées avant d'être utilisées dans les requêtes SQL. Autorisez uniquement certains caractères et modèles tels que la saisie alphanumérique pour des champs tels que les noms d'utilisateur ou les adresses e-mail.

année où l'ordinateur a été inventé

4. Utilisez les cadres ORM

Les frameworks de mappage objet-relationnel (ORM) comme Hiberner ou Cadre d'entité peut aider à empêcher l’injection SQL en gérant automatiquement la génération de requêtes empêchant la construction de requêtes dynamiques.

5. Restreindre les privilèges de base de données

Accordez les autorisations de base de données minimales requises aux utilisateurs. Assurez-vous que les applications ne peuvent effectuer que les actions nécessaires (par exemple, SELECT INSERT) et restreignez les autorisations telles que DROP TABLE ou ALTER.

6. Gestion des erreurs

Configurez la base de données et l'application pour ne pas afficher de messages d'erreur détaillés à l'utilisateur. Enregistrez plutôt les erreurs en interne et affichez des messages d’erreur génériques aux utilisateurs finaux.