Aller au contenu principal

Vulnérabilités GET et POST

Vulnérabilités liées aux paramètres GET et POST

Notions théoriques

Les paramètres GET et POST sont utilisés pour transmettre des données entre un client (navigateur) et un serveur web.

info

Une mauvaise gestion des paramètres GET et POST peut entraîner des failles de sécurité exploitables par des attaquants.

Différences entre GET et POST

CritèreGETPOST
Visibilité des donnéesVisible dans l'URLCaché dans le corps de la requête
Taille des donnéesLimité (~2000 caractères)Illimité
Utilisation couranteRecherche, navigationFormulaires, authentification
SécuritéMoins sécurisé (exposé dans l'URL)Plus sécurisé (non stocké dans l'historique)

Vulnérabilités courantes

Injection SQL

  • Un attaquant peut modifier un paramètre GET/POST pour exécuter du SQL malveillant.
  • Exemple : ?id=1 OR 1=1 peut permettre d'afficher toutes les données d'une base.

Cross-Site Scripting (XSS)

  • L’attaquant injecte du JavaScript malveillant via un paramètre GET/POST.
  • Exemple : ?message=<script>alert('XSS')</script> affiche une alerte piégée.

Falsification de requête (CSRF)

  • Un attaquant force un utilisateur à exécuter une action à son insu.
  • Exemple : Un formulaire caché POST envoie une requête sans que l’utilisateur le sache.

Exposition de données sensibles

  • Les paramètres GET sont stockés dans l’historique du navigateur et peuvent être récupérés.
  • Exemple : ?password=123456 peut être visible dans les logs du serveur.

Exemple pratique

Voici un formulaire vulnérable et voyons comment un attaquant peut l'exploiter.

Code d’un formulaire non sécurisé

<!DOCTYPE html>
<html>
<head>
<title>Connexion</title>
</head>
<body>
<form action="login.php" method="GET">
<label>Nom d'utilisateur :</label>
<input type="text" name="username">
<label>Mot de passe :</label>
<input type="password" name="password">
<button type="submit">Se connecter</button>
</form>
</body>
</html>

Problèmes de sécurité

  1. Le mot de passe est envoyé en GET, donc visible dans l’URL (?username=admin&password=123456).
  2. Un attaquant peut injecter du SQL en testant ?username=admin' -- pour contourner l’authentification.
  3. Pas de validation côté serveur, donc vulnérable aux XSS (?username=<script>alert('Hacked')</script>).

Solution sécurisée

  • Utiliser POST au lieu de GET.
  • Échapper les entrées utilisateur (htmlspecialchars() en PHP).
  • Vérifier les entrées (preg_match() pour filtrer les caractères suspects).
  • Utiliser des requêtes préparées pour éviter l’injection SQL.

Test de mémorisation/compréhension


Quelle est la principale différence entre GET et POST ?


Pourquoi GET est-il moins sécurisé que POST ?


Qu'est-ce qu'une injection SQL ?


Comment éviter une injection SQL ?


Pourquoi le XSS est dangereux ?



TP pour réfléchir et résoudre des problèmes

Dans ce TP, vous allez analyser et corriger un formulaire vulnérable pour le rendre sécurisé afin de savoir :

✔️ Protéger un site contre les injections SQL
✔️ Empêcher les attaques XSS
✔️ Sécuriser les mots de passe et l’authentification
✔️ Tester les vulnérabilités et vérifier les protections

Étape 1 : Préparer l’environnement

Nous allons utiliser Debian avec Apache, PHP et MySQL.

1️⃣ Ouvrez un terminal et installez les services nécessaires :

sudo apt update
sudo apt install apache2 php php-mysql mariadb-server -y

2️⃣ Démarrez Apache et MySQL :

sudo systemctl start apache2
sudo systemctl start mariadb

3️⃣ Sécurisez MySQL (optionnel mais recommandé) :

sudo mysql_secure_installation

Répondez aux questions pour définir un mot de passe root et sécuriser l’accès.


Étape 2 : Créer une BD vulnérable

Nous allons créer une table users avec des identifiants stockés sans protection (ce qui est une mauvaise pratique).

1️⃣ Connectez-vous à MySQL :

sudo mysql -u root -p

2️⃣ Créez une base de données et une table :

CREATE DATABASE security_test;
USE security_test;

CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(50) NOT NULL
);

INSERT INTO users (username, password) VALUES ('admin', '123456'), ('alice', 'password');

3️⃣ Vérifiez les utilisateurs :

SELECT * FROM users;

Étape 3 : Créer un formulaire vulnérable

Nous allons créer une page de connexion non sécurisée.

1️⃣ Créez un fichier login.php dans /var/www/html/ :

sudo nano /var/www/html/login.php

2️⃣ Ajoutez le code suivant (⚠️ VULNÉRABLE ⚠️) :

<?php
$pdo = new PDO("mysql:host=localhost;dbname=security_test", "root", "");

// ⚠️ REQUÊTE NON SÉCURISÉE (VULNÉRABLE À L'INJECTION SQL)
$query = "SELECT * FROM users WHERE username = '" . $_GET['username'] . "' AND password = '" . $_GET['password'] . "'";
$result = $pdo->query($query);

if ($result->rowCount() > 0) {
echo "✔️ Connexion réussie !";
} else {
echo "❌ Échec de la connexion.";
}
?>

3️⃣ Créez une page HTML pour tester la connexion :

sudo nano /var/www/html/index.html

4️⃣ Ajoutez le formulaire suivant :

<!DOCTYPE html>
<html>
<head>
<title>Connexion</title>
</head>
<body>
<h2>Connexion</h2>
<form action="login.php" method="GET">
<label>Nom d'utilisateur :</label>
<input type="text" name="username">
<label>Mot de passe :</label>
<input type="password" name="password">
<button type="submit">Se connecter</button>
</form>
</body>
</html>

Étape 4 : Tester les failles de sécurité

Nous allons exploiter les vulnérabilités du formulaire.

Tester une injection SQL**

  1. Ouvrez un navigateur et entrez l’URL suivante :
    http://<IP_DU_SERVEUR>/login.php?username=admin'--&password=123
  2. Résultat attendu :
    ✔️ Connexion réussie !
    (L’attaque fonctionne car -- commente le reste de la requête SQL.)

Tester une attaque XSS**

  1. Essayez cette URL :
    http://<IP_DU_SERVEUR>/login.php?username=<script>alert('Hacked')</script>&password=123
  2. Résultat attendu :
    Une alerte JavaScript apparaît dans le navigateur.

➡️ Conclusion : Notre formulaire est vulnérable et doit être sécurisé !


Étape 5 : Sécuriser le formulaire

Nous allons corriger les failles en appliquant les bonnes pratiques.

1️⃣ Ouvrez login.php et modifiez le code :

sudo nano /var/www/html/login.php

2️⃣ Remplacez le code par une version sécurisée :

<?php
$pdo = new PDO("mysql:host=localhost;dbname=security_test", "root", "");

// ✔️ UTILISATION DE REQUÊTES PRÉPARÉES (PROTECTION CONTRE L'INJECTION SQL)
$query = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$query->execute([$_POST['username'], $_POST['password']]);

if ($query->rowCount() > 0) {
echo "✔️ Connexion réussie !";
} else {
echo "❌ Échec de la connexion.";
}
?>

3️⃣ Modifiez le formulaire pour utiliser POST :

sudo nano /var/www/html/index.html

4️⃣ Corrigez le formulaire :

<form action="login.php" method="POST">
<label>Nom d'utilisateur :</label>
<input type="text" name="username">
<label>Mot de passe :</label>
<input type="password" name="password">
<button type="submit">Se connecter</button>
</form>

Étape 6 : Vérifier la correction

Vérifier que les failles sont corrigées

1️⃣ Refaites les tests d’injection SQL :

  • Essayez admin'--Échec de la connexion ✔️
  • Essayez admin" OR 1=1 --Échec de la connexion ✔️

2️⃣ Refaites les tests XSS :

  • Essayez <script>alert('Hacked')</script>Aucun script ne s’exécute ✔️

3️⃣ Vérifiez que le mot de passe n’apparaît plus dans l’URL.


Étape 7 : Sécuriser les mots de passe

Nous allons maintenant hacher les mots de passe pour éviter de les stocker en clair.

1️⃣ Modifiez la création des utilisateurs dans MySQL :

ALTER TABLE users MODIFY password VARCHAR(255);
UPDATE users SET password = SHA2('123456', 256) WHERE username = 'admin';
UPDATE users SET password = SHA2('password', 256) WHERE username = 'alice';

2️⃣ Modifiez login.php pour vérifier un mot de passe haché :

$query = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$query->execute([$_POST['username']]);
$user = $query->fetch();

if ($user && hash('sha256', $_POST['password']) === $user['password']) {
echo "✔️ Connexion réussie !";
} else {
echo "❌ Échec de la connexion.";
}