First commit
This commit is contained in:
203
README.md
Normal file
203
README.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# 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
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user