2025-12-18 15:17:27 +01:00
2025-12-18 15:17:27 +01:00
2025-12-18 15:17:27 +01:00
2025-12-18 15:17:27 +01:00
2025-12-18 15:17:27 +01:00
2025-12-18 15:17:27 +01:00
2025-12-18 15:17:27 +01:00
2025-12-18 15:17:27 +01:00
2025-12-18 15:17:27 +01:00

Démonstration : injection SQL avec Node.js, Express et SQLite

Ce projet démontre comment une simple concaténation SQL peut rendre une application vulnérable à une injection SQL, et comment corriger cette faille à l'aide de requêtes préparées.

Il propose deux routes :

  • /demo-vulnerable/login → version vulnérable
  • /demo-secure/login → version sécurisée

Installation

npm install
nodemon ./bin/www

L'application démarre sur :

http://localhost:3000

Objectifs pédagogiques

Cette mini-démonstration permet de :

  • comprendre ce qu'est une injection SQL

  • observer clairement la différence entre :

    • une requête créée par concaténation (dangereux)
    • une requête préparée avec paramètres (sécurisé)
  • manipuler Express, SQLite et les routes API

  • visualiser l'impact d'une exploitation sur une base de données


Structure du projet

project/
│── app.js
│── db/
│    └── database.js
│── routes/
│    ├── auth_vulnerable.js
│    └── auth_secure.js
└── bin/www

Comprendre l'architecture

1. Initialisation de la base en mémoire

const db = new sqlite3.Database(':memory:');

La base est volatile, recréée à chaque démarrage, et contient deux utilisateurs :

  • admin / password123
  • user / userpass

Diagramme — création de la base

flowchart TD
    a["demarrage de l'application"] --> b["creation de la base en memoire"]
    b --> c["creation de la table users"]
    c --> d["insertion de l'utilisateur admin"]
    c --> e["insertion de l'utilisateur user"]

2. Version vulnérable : concaténation SQL

Dans auth_vulnerable.js :

const sqlQuery = "SELECT * FROM users WHERE username = '" + username +
        "' AND password = '" + password + "'";

Cette méthode permet à un utilisateur d'injecter du code SQL.

Diagramme — route vulnérable

sequenceDiagram
    participant client
    participant serveur
    participant sqlite

    client->>serveur: envoi de donnees username et password
    serveur->>serveur: creation d'une requete concatenee
    serveur->>sqlite: execution de la requete non protegee
    sqlite-->>serveur: renvoi d'une ligne ou non
    serveur-->>client: reponse json

Tests de démonstration

Test 1 : attaque réussie (vulnérable)

Envoyer un POST :

POST http://localhost:3000/demo-vulnerable/login

Body JSON :

{
  "username": "' OR 1=1 --",
  "password": "peu-importe"
}

Résultat attendu :

Connexion acceptée, vous devenez admin même sans connaître le mot de passe.


Test 2 : l'attaque échoue (sécurisé)

Même requête mais vers :

POST http://localhost:3000/demo-secure/login

Body identique :

{
  "username": "' OR 1=1 --",
  "password": "peu-importe"
}

Résultat attendu :

Connexion refusée : l'injection est traitée comme du texte.


3. Version sécurisée : requêtes préparées

Dans auth_secure.js :

const sqlQuery = "SELECT * FROM users WHERE username = ? AND password = ?";
const params = [username, password];
db.get(sqlQuery, params, (...));

SQLite protège automatiquement les valeurs et empêche l'injection.

Diagramme — route sécurisée

flowchart TD
    a["reception de la requete http"] --> b["construction de la requete preparee"]
    b --> c["envoi de la requete avec parametres"]
    c --> d["sqlite assainit les valeurs"]
    d --> e["execution de la requete securisee"]

Comprendre la faille SQL

Exemple vulnérable

Requête générée :

SELECT * FROM users WHERE username = '' OR 1=1 --' AND password='peu-importe'

OR 1=1 rend la condition toujours vraie.


Bonnes pratiques

  • toujours utiliser des requêtes préparées
  • jamais concaténer des valeurs utilisateur dans du SQL
  • toujours valider / nettoyer les entrées
  • activer des logs SQL en développement
  • éviter les messages d'erreurs trop détaillés en production

Description
No description provided
Readme 66 KiB
Languages
JavaScript 100%