Apprendre la cybersécurité - Activités pratiques en développement sécurisé
- Neo's calling
- 8 juin 2024
- 3 min de lecture
Dernière mise à jour : 11 juin 2024
La sécurité en développement est un pilier crucial de la cybersécurité. Elle consiste à intégrer des pratiques sécuritaires dès les premières étapes de la conception et du développement d'applications, afin de prévenir les vulnérabilités et de protéger les données sensibles. Dans le contexte actuel où les cyberattaques sont de plus en plus sophistiquées, comprendre et mettre en œuvre des mesures de sécurité dans le développement logiciel est essentiel.
Ces exercices vous guideront à travers des scénarios pratiques pour identifier et corriger les vulnérabilités courantes dans le code. Vous apprendrez à sécuriser vos applications contre des attaques telles que les injections SQL et les failles XSS (Cross-Site Scripting). Chaque exercice est conçu pour vous familiariser avec des techniques spécifiques, en vous fournissant les connaissances nécessaires pour développer des applications robustes et sécurisées.

Validation des Entrées Utilisateur
Objectif :
Apprendre à valider et à assainir les entrées utilisateur pour prévenir les vulnérabilités courantes telles que les injections SQL, les failles XSS, et autres attaques basées sur les entrées non sécurisées.
Prérequis :
Connaissance de base en PHP et HTML.
Serveur web local (comme LAMP, XAMPP ou WAMP).
Instructions :
Créez un simple formulaire HTML permettant à l'utilisateur d'entrer son nom et son adresse email.
Traiter les données en PHP pour éviter les inclusions de caractères malicieux.
Correction et explications
Correction
Création d'un formulaire de saisie des noms et e-mails.
html
<form method="post" action="">
Nom : <input type="text" name="nom"><br>
Email : <input type="email" name="email"><br>
<input type="submit" value="Envoyer">
</form>
Traitement des données en PHP pour éviter les inclusions de caractères malicieux.
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$nom = $_POST['nom'];
$email = $_POST['email'];
// Validation et assainissement des données
$nom = trim($nom);
$nom = stripslashes($nom);
$nom = htmlspecialchars($nom);
$email = filter_var($email, FILTER_SANITIZE_EMAIL);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo "Adresse email invalide.";
} else {
echo "Nom : $nom<br>";
echo "Email : $email<br>";
}
}
?>
Explications
Validation et Assainissement des Données
trim($nom) : Supprime les espaces blancs en début et en fin de chaîne.
stripslashes($nom) : Supprime les antislashs ( \ ) ajoutés par certaines fonctions PHP pour échapper les caractères spéciaux.
htmlspecialchars($nom) : Convertit les caractères spéciaux en entités HTML (par exemple, < devient <), empêchant ainsi l'exécution de code HTML ou JavaScript.
Validation de l'Email
filter_var($email, FILTER_SANITIZE_EMAIL) : Supprime les caractères invalides pour une adresse email.
filter_var($email, FILTER_VALIDATE_EMAIL) : Valide que l'email est bien formé.
Correction et Explications Détailées
Suppression des Espaces et Caractères Inutiles :
$nom = trim($nom);
Cette fonction élimine les espaces blancs ou autres caractères prédéfinis (comme des sauts de ligne) en début et en fin de chaîne.
Élimination des Antislashs :
$nom = stripslashes($nom);
stripslashes() retire les antislashs ajoutés pour échapper les guillemets dans certaines configurations PHP, protégeant ainsi contre certaines formes d'injections.
Conversion des Caractères Spéciaux :
$nom = htmlspecialchars($nom);
htmlspecialchars() convertit les caractères spéciaux en entités HTML pour empêcher les attaques XSS. Par exemple, < devient <, > devient >, et ainsi de suite.
Assainissement de l'Email :
$email = filter_var($email, FILTER_SANITIZE_EMAIL);
FILTER_SANITIZE_EMAIL retire tous les caractères non autorisés dans une adresse email.
Validation de l'Email :
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo "Adresse email invalide.";
}
FILTER_VALIDATE_EMAIL vérifie que l'adresse email est bien formée selon le standard des adresses email. Si l'email n'est pas valide, un message d'erreur est affiché.
Protection contre l'Injection SQL
Objectif : Comprendre et implémenter des mesures de sécurité pour prévenir les attaques par injection SQL.
Instructions
Créez une base de données simple avec une table d'utilisateurs.
Écrivez une requête SQL vulnérable à l'injection SQL.
Modifiez le code pour utiliser des requêtes préparées afin de prévenir l'injection SQL.
Étapes
1. Création de la base de données et de la table :
Utilisez un SGBD (par exemple, MariaDB, MySQL ou PostegreSQL) pour créer une base de données et une table users.
Insérez ensuite au moins un utilisateur dans cette table (par exemple, admin)
2. Requête SQL vulnérable :
Écrivez une requête SQL dans un fichier en PHP (par exemple, login.php) qui est vulnérable à l'injection SQL.
Ouvrez votre navigateur et accédez au fichier login.php.
Injectez des requêtes SQL malveillantes pour voir si l'application est vulnérable.
3. Utilisation de requêtes préparées :
Modifiez le code pour utiliser des requêtes préparées et prévenir l'injection.
Re testez l'application en utilisant la même injection SQL que précédemment.

Correction et explications
1. Création de la base de données et de la table
Corrigé de la requête SQL pour la création de la base de données et la table :
CREATE DATABASE security_test;
USE security_test;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(50)
);
Insertion de données :
INSERT INTO users (username, password) VALUES ('admin', 'password123'), ('user1', 'pass1');
Explications des commandes MySQL :
CREATE DATABASE security_test; : Cette commande crée une nouvelle base de données nommée security_test.
USE security_test; : Cette commande sélectionne la base de données security_test pour que les commandes suivantes soient exécutées dans ce contexte.
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50), password VARCHAR(50)); : Cette commande crée une table users avec trois colonnes : id (clé primaire auto-incrémentée), username et password (toutes deux de type VARCHAR avec une longueur maximale de 50 caractères).
INSERT INTO users (username, password) VALUES ('admin', 'password123'), ('user1', 'pass1'); : Cette commande insère deux enregistrements dans la table users.
Ces étapes permettent de créer un environnement de test simple pour les exercices sur les injections SQL.
2. Requête SQL vulnérable
Contenu du fichier login.php :
<?php
$conn = new mysqli('localhost', 'root', '', 'security_test');
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $conn->query($query);
if ($result->num_rows > 0) {
echo "Login successful!";
} else {
echo "Invalid credentials.";
}
}
?>
<form method="post" action="">
Username: <input type="text" name="username">
Password: <input type="password" name="password">
<input type="submit" value="Login">
</form>
Explication du code :
Connexion à la base de données : new mysqli('localhost', 'root', '', 'security_test'); crée une connexion à la base de données security_test sur localhost avec l'utilisateur root sans mot de passe.
Requête SQL : $query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'"; construit dynamiquement une requête SQL basée sur les entrées de l'utilisateur.
Vérification des résultats : if ($result->num_rows > 0) vérifie si la requête a retourné des lignes, indiquant une connexion réussie.
Vulnérabilité :
En injectant une requête SQL malveillante dans les champs de saisie, par exemple, admin' OR '1'='1 comme nom d'utilisateur et anything comme mot de passe, l'attaquant peut contourner l'authentification.
Détails de l'Injection SQL
Exemple d'attaque
Nom d'utilisateur : admin' OR '1'='1
Mot de passe : anything
Construction de la requête SQL :
Lorsque ces valeurs sont envoyées via le formulaire web, le code PHP vulnérable construit la requête SQL suivante :
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = 'anything';
Pour mieux comprendre, décomposons cette requête :
Clause WHERE :
username = 'admin' : Vérifie si le nom d'utilisateur est admin.
OR '1'='1' : Toujours vrai car '1' est égal à '1'.
AND password = 'anything' : Vérifie si le mot de passe est anything.
Évaluation de la clause WHERE :
En SQL, les opérateurs AND et OR suivent une logique précise :
A OR B est vrai si l'une des conditions A ou B est vraie.
A AND B est vrai si les deux conditions A et B sont vraies.
Dans ce cas :
La condition username = 'admin' peut être vraie ou fausse.
La condition '1'='1' est toujours vraie.
La condition password = 'anything' peut être vraie ou fausse.
La présence de OR '1'='1' signifie que la clause entière username = 'admin' OR '1'='1' est toujours vraie, peu importe ce que contient le champ username.
Résultat de la requête :
Étant donné que OR '1'='1' est toujours vrai, la requête peut se réduire à :
SELECT * FROM users WHERE TRUE AND password = 'anything';
Ce qui équivaut à :
SELECT * FROM users WHERE password = 'anything';
Toutefois, l'AND avec une condition toujours vraie et une condition sans importance (password = 'anything') signifie que MySQL renverra la première ligne de la table si une ligne correspond au mot de passe fourni, ou même toutes les lignes si l'une des conditions est fausse. Mais comme OR '1'='1' est toujours vrai, la requête retourne tous les utilisateurs.
Impact :
La requête retourne une ligne de la table users, ce qui fait croire au script PHP que l'authentification a réussi.
L'attaquant est ainsi authentifié avec succès sans connaître le mot de passe réel.Utilisation de requêtes préparées
Modification du fichier login.php :
<?php
$conn = new mysqli('localhost', 'root', '', 'security_test');
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
echo "Login successful!";
} else {
echo "Invalid credentials.";
}
}
?>
<form method="post" action="">
Username: <input type="text" name="username">
Password: <input type="password" name="password">
<input type="submit" value="Login">
</form>
Explication du code :
1. La Classe mysqli_stmt
La classe mysqli_stmt en PHP représente une requête SQL préparée. Elle permet d'exécuter des requêtes SQL de manière sécurisée, en évitant les injections SQL. La classe est utilisée conjointement avec un objet mysqli (qui représente une connexion à une base de données).
2. Création d'une Requête Préparée
Ligne de code :
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$conn->prepare() est une méthode de l'objet mysqli qui prend en paramètre une chaîne de caractères contenant la requête SQL avec des points d'interrogation ? comme espaces réservés pour les paramètres.
Cette méthode retourne un objet mysqli_stmt représentant la requête préparée.
Les points d'interrogation ? indiquent les emplacements où les valeurs des variables seront insérées de manière sécurisée.
3. Association des Paramètres
Ligne de code :
$stmt->bind_param("ss", $username, $password);
bind_param() est une méthode de l'objet mysqli_stmt utilisée pour lier les variables PHP aux espaces réservés ? dans la requête préparée.
Le premier argument "ss" est une chaîne de caractères spécifiant les types des paramètres :
"s" pour string (chaîne de caractères)
"i" pour integer (entier)
"d" pour double (nombre à virgule flottante)
"b" pour blob (données binaires)
Dans ce cas, "ss" indique que les deux paramètres sont des chaînes de caractères.
Les arguments suivants sont les variables à lier : $username et $password.
4. Exécution de la Requête
Ligne de code :
$stmt->execute();
execute() est une méthode de l'objet mysqli_stmt qui exécute la requête préparée avec les valeurs des paramètres liées.
Lorsque execute() est appelé, la requête SQL est envoyée au serveur de base de données avec les valeurs des variables insérées à la place des espaces réservés.
5. Récupération des Résultats
Ligne de code :
$result = $stmt->get_result();
get_result() est une méthode de l'objet mysqli_stmt qui retourne un objet mysqli_result représentant les résultats de la requête.
Cet objet peut être utilisé pour accéder aux données retournées par la requête SQL.
Importance des Requêtes Préparées
L'utilisation de requêtes préparées empêche de telles injections car les entrées de l'utilisateur ne sont pas directement insérées dans la requête SQL. Les requêtes préparées traitent les entrées comme des données brutes, séparées des commandes SQL.
Protection contre les failles XSS
Objectif : Apprendre à identifier et à prévenir les failles XSS en comprenant comment un attaquant peut injecter des scripts malveillants dans une application web.
Prérequis :
Connaissance de base en PHP et HTML.
Serveur web local (comme XAMPP ou WAMP).
Étapes :
1. Création d'une Application Web Vulnérable
Créez un simple formulaire HTML permettant à l'utilisateur de soumettre un commentaire, puis affichez ce commentaire sur la même page sans validation.
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$comment = $_POST['comment'];
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Commentaires</title>
</head>
<body>
<form method="post" action="">
Commentaire: <input type="text" name="comment">
<input type="submit" value="Soumettre">
</form>
<h2>Commentaires:</h2>
<p><?php echo $comment; ?></p>
</body>
</html>
2. Injection d'un Script Malveillant :
Soumettez le formulaire avec un script malveillant comme commentaire :
<script>alert('XSS Attack!');</script>
Lorsque le commentaire est affiché, le script sera exécuté, montrant une alerte avec le message "XSS Attack!".
3. Compréhension du Comportement de la Requête :
Le formulaire envoie les données du commentaire via une requête POST.
La valeur de $_POST['comment'] est affichée directement sans validation, ce qui permet l'injection de code JavaScript.
4. Prévention de la Faille XSS
Modifiez le script PHP pour utiliser htmlspecialchars() afin de convertir les caractères spéciaux en entités HTML, empêchant ainsi l'exécution du script.
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$comment = htmlspecialchars($_POST['comment'], ENT_QUOTES, 'UTF-8');
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Commentaires</title>
</head>
<body>
<form method="post" action="">
Commentaire: <input type="text" name="comment">
<input type="submit" value="Soumettre">
</form>
<h2>Commentaires:</h2>
<p><?php echo $comment; ?></p>
</body>
</html>
5. Vérification de la Protection
Soumettez à nouveau le formulaire avec le script malveillant :
<script>alert('XSS Attack!');</script>
Cette fois, le script ne sera pas exécuté, et le commentaire affichera littéralement <script>alert('XSS Attack!');</script>.
Comments