204 lines
4.0 KiB
Markdown
204 lines
4.0 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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
|
|
|
|
```text
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```mermaid
|
|
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` :
|
|
|
|
```javascript
|
|
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
|
|
|
|
```mermaid
|
|
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 :
|
|
|
|
```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 :
|
|
|
|
```json
|
|
{
|
|
"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` :
|
|
|
|
```javascript
|
|
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
|
|
|
|
```mermaid
|
|
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 :
|
|
|
|
```sql
|
|
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
|
|
|
|
---
|