Compte Rendu - TP Sécurité PHP

Exercice 1 : Mise en place et configuration initiale

Objectif : Récupérer le fichier EssaiSecurite.php, l'adapter pour qu'il fonctionne dans l'environnement local, créer des utilisateurs de test dans la base de données et vérifier le bon fonctionnement du système d'authentification.
Approche de réalisation :
  • Récupération du fichier EssaiSecurite.php depuis ecampus
  • Création d'un sous-répertoire dans public_html pour organiser le projet
  • Adaptation des paramètres de connexion à la base de données
  • Création de deux utilisateurs de test avec droits d'accès
  • Test complet du système d'authentification
Code de configuration de la base de données :
// CONFIGURATION DE LA CONNEXION À LA BASE DE DONNÉES
function valid(){
    $link = mysqli_connect("localhost", "guewennmennegaut_secu", "MDP", "guewennmennegaut_securite");
    if (!$link) {
        die("Erreur de connexion : " . mysqli_connect_error());
    }
    
}
Structure de la table utilisateurs :
SQL de création de la table :
CREATE TABLE utilisateurs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    login VARCHAR(50) NOT NULL,
    password VARCHAR(50) NOT NULL
);
Utilisateurs créés pour les tests :
INSERT INTO utilisateurs (login, password) VALUES 
('a', '1'),
('b', 'a');
Tests de fonctionnement :
Scénarios de test effectués :
  • Connexion avec login "a" et mot de passe "1" → Accès autorisé
  • Connexion avec login "b" et mot de passe "a" → Accès autorisé
  • Connexion avec identifiants incorrects → Message d'erreur affiché
Capture d'écran de la structure des tables :
Structure des tables

Exercice 2 : Injection SQL

Objectif : Démontrer la vulnérabilité d'injection SQL dans le système d'authentification et mettre en place les protections nécessaires pour empêcher l'exécution de requêtes SQL non autorisées.
Approche de réalisation :
  • Test du formulaire avec des identifiants valides et invalides pour comprendre le comportement normal
  • Exploitation de la faille avec une injection SQL basique utilisant ' OR '1=1
  • Analyse de la requête SQL vulnérable et compréhension du mécanisme de contournement
  • Implémentation de mysqli_real_escape_string() pour échapper les caractères spéciaux et sécuriser les entrées utilisateur
Code vulnérable initial :
function valid(){
    $link = mysqli_connect("localhost", "guewennmennegaut_secu", "MDP", "guewennmennegaut_securite");
    
    // RÉCUPÉRATION NON SÉCURISÉE DES DONNÉES
    $log = isset($_POST['nom']) ? $_POST['nom'] : '';
    $password = isset($_POST['pass']) ? $_POST['pass'] : '';

    // REQUÊTE SQL VULNÉRABLE AUX INJECTIONS
    $sql = "SELECT * FROM utilisateurs WHERE login='$log' AND password='$password'";
    
    $result = mysqli_query($link, $sql);
    
    if ($result && mysqli_num_rows($result) != 0) {
        $_SESSION['login'] = $_POST["nom"];
        header("Location: ".$_SERVER['PHP_SELF']);
        exit;
    } else {
        formulaire_identif();
        echo "identification erronée, monsieur " . $_POST["nom"];
    }
}
Test d'exploitation :
Scénario de test :
- Utilisation d'un login existant dans la base de données
- Mot de passe : ' OR '1=1
- Résultat observé : Connexion réussie sans connaître le mot de passe réel de l'utilisateur
Explication du fonctionnement :
La requête SQL vulnérable :
SELECT * FROM utilisateurs WHERE login='admin' AND password='motdepasse'
Devient après injection :
SELECT * FROM utilisateurs WHERE login='admin' AND password='' OR '1=1'
Ce qui est équivalent à :
SELECT * FROM utilisateurs WHERE (login='admin' AND password='') OR TRUE
La condition OR TRUE rend toujours la condition globale vraie, permettant ainsi un contournement complet du système d'authentification.
Capture d'écran du code sécurisé contre les injections SQL :
Code sécurisé contre les injections SQL

Exercice 3 : Attaque XSS (Cross-Site Scripting)

Objectif : Démontrer la vulnérabilité XSS dans l'affichage des messages d'erreur et mettre en place la protection avec htmlentities() pour neutraliser l'exécution de code JavaScript malveillant.
Approche de réalisation :
  • Test avec injection d'un script JavaScript simple dans le champ de login
  • Observation de l'exécution du code malveillant dans le navigateur
  • Analyse du mécanisme d'affichage non sécurisé des données utilisateur
  • Implémentation de htmlentities() pour convertir les caractères spéciaux en entités HTML
Code vulnérable :
// AFFICHAGE DIRECT ET NON SÉCURISÉ DES DONNÉES UTILISATEUR
function valid(){
    // ... code de validation ...
    
    if ($result && mysqli_num_rows($result) != 0) {
        // Connexion réussie
    } else {
        formulaire_identif();
        // VULNÉRABILITÉ XSS : affichage non sécurisé
        echo "identification erronée, monsieur " . $_POST["nom"];
    }
}
Test d'exploitation :
Scénario de test :
- Login : <script>document.title='this site sucks';</script>
- Mot de passe : quelconque (échec d'authentification forcé)
- Résultat observé : Le titre de la page est modifié en "this site sucks"
Capture d'écran du titre modifié par l'attaque XSS :
Titre modifié par XSS
Explication du fonctionnement :
Lors de l'échec d'authentification, le message d'erreur affiche directement la valeur du champ "nom" sans aucune filtration. Le code JavaScript injecté est interprété par le navigateur et exécuté dans le contexte de la page, permettant une modification non autorisée du contenu.
Capture d'écran du code sécurisé contre les attaques XSS :
Code sécurisé contre XSS
Risques supplémentaires identifiés :
  • Accès aux cookies de session via document.cookie
  • Modification complète du contenu de la page
  • Redirection vers des sites malveillants
  • Vol d'informations sensibles

Exercice 4 : Attaque CSRF (Cross-Site Request Forgery)

Objectif : Démontrer la vulnérabilité CSRF dans le système de vote et mettre en place une protection par token pour vérifier l'origine des requêtes.
Approche de réalisation :
  • Création d'une page malveillante AttaqueCSRF.php avec une image invisible
  • Test de déclenchement du vote sans consentement de l'utilisateur
  • Analyse de l'absence de vérification de l'origine des requêtes GET
  • Implémentation d'un token CSRF basé sur le temps pour sécuriser le formulaire
Code de la page malveillante AttaqueCSRF.php :
<!DOCTYPE html>
<html>
<head>
    <title>Page</title>
</head>
<body>
    <img src="https://guewenn.mennegaut.mmi-velizy.fr/TP%20NOTE%20PHP/SECURITE/EssaiSecurite.php?choix=1" 
         alt="Image innocente" 
         width="1" 
         height="1" 
         style="display:none">
</body>
</html>
Capture d'écran du code de la page AttaqueCSRF.php :
Code de la page AttaqueCSRF
Test d'exploitation :
Scénario de test :
  1. Ouverture d'EssaiSecurite.php dans un onglet
  2. Authentification réussie avec un compte valide
  3. Navigation vers AttaqueCSRF.php sans fermer la session
  4. Vérification du fichier vote.txt
Résultat observé : Le fichier vote.txt contient un vote enregistré alors que l'utilisateur n'a pas volontairement voté
Capture d'écran du fichier vote.txt après l'attaque :
Résultat du vote forcé
Explication du fonctionnement :
La vulnérabilité réside dans le fait que le système de vote accepte les requêtes GET sans vérifier leur origine :
if (isset($_GET["choix"]) && $_GET["choix"]==1){
    // Enregistrement du vote sans vérification CSRF
    $f=fopen("vote.txt","a+");
    fwrite($f, $_SESSION['login']);
}
L'image invisible dans AttaqueCSRF.php envoie une requête GET à EssaiSecurite.php avec le paramètre choix=1, déclenchant le vote automatiquement lorsque la page est chargée. Le navigateur envoie automatiquement les cookies de session avec la requête, ce qui permet d'identifier l'utilisateur connecté.
Capture d'écran du code de protection CSRF :
Code de protection CSRF
Explication de la parade :
La protection CSRF fonctionne sur trois niveaux :
  1. Génération d'un token unique : Un token aléatoire est généré avec bin2hex(random_bytes(32)) et stocké en session
  2. Inclusion dans le formulaire : Le token est ajouté comme champ caché dans le formulaire légitime
  3. Vérification à la soumission : Le système vérifie que le token reçu correspond à celui stocké en session
Utilisation de time() :
  • Le token est associé à un timestamp avec $_SESSION['csrf_token_time'] = time()
  • La vérification (time() - $_SESSION['csrf_token_time']) > 3600 limite la durée de vie du token à 1 heure
  • Empêche la réutilisation de tokens volés après expiration
Cette approche garantit que seules les requêtes provenant du formulaire légitime (contenant le token valide) peuvent déclencher des actions sensibles comme le vote. L'attaque CSRF échoue car la page malveillante ne peut pas connaître le token CSRF valide.

Exercice 5 : Register Globals

Objectif : Démontrer la vulnérabilité liée à l'activation de register_globals et comprendre les risques de sécurité associés à cette fonctionnalité dépréciée de PHP.
Approche de réalisation :
  • Vérification de l'état d'activation de register_globals avec ini_get()
  • Analyse du code vulnérable utilisant des variables globales non initialisées
  • Test de contournement d'authentification via paramètre GET
  • Compréhension du mécanisme d'injection de variables globales
Structure des tables
Test de configuration :
echo "register_globals = " . ini_get('register_globals');
Résultat : register_globals = 1 (activé)
Code vulnérable EssaiSecurite.php :
session_start();

$authentifie = false;
$login = '';

if (isset($_POST['login']) && isset($_POST['password'])) {
    if ($_POST['login'] === 'admin' && $_POST['password'] === 'secret') {
        $authentifie = true;
        $_SESSION['authentifie'] = true;
        $_SESSION['login'] = $_POST['login'];
    }
}

if ($authentifie) {
    echo "Bienvenue, vous êtes authentifié !";
} else {
    echo "Veuillez vous authentifier";
}
Test d'exploitation :
Scénario de test :
  1. Déconnexion de EssaiSecurite.php
  2. Accès direct via l'URL : https://guewenn.mennegaut.mmi-velizy.fr/TP%20NOTE%20PHP/SECURITE/EssaiSecurite.php?authentifie=1
  3. Observation du résultat
Résultat observé : Accès à la zone sécurisée sans authentification
Explication du fonctionnement :
Avec register_globals activé, PHP crée automatiquement des variables globales à partir des paramètres GET, POST et COOKIE. Lors de l'accès à l'URL avec le paramètre ?authentifie=1 :
  • PHP crée automatiquement la variable globale $authentifie = 1
  • La condition if ($authentifie) devient vraie
  • L'utilisateur accède à la zone sécurisée sans fournir d'identifiants valides
Impact : Contournement complet du système d'authentification
Solution recommandée :
session_start();

if (isset($_SESSION['authentifie']) && $_SESSION['authentifie'] === true) {
    echo "Bienvenue, vous êtes authentifié !";
} else {
    echo "Veuillez vous authentifier";
}
Mesures de protection :
  • Désactivation de register_globals dans php.ini
  • Utilisation exclusive des superglobales ($_GET, $_POST, $_SESSION)
  • Initialisation systématique de toutes les variables
  • Vérification stricte de l'origine des données

Exercice 6 : Faille RFI (Remote File Inclusion)

Objectif : Démontrer la vulnérabilité d'inclusion de fichiers distants et mettre en place une protection par liste blanche pour empêcher l'exécution de fichiers non autorisés.
Approche de réalisation :
  • Création d'un fichier de configuration séparé (conf.php)
  • Modification du code pour permettre l'inclusion dynamique de fichiers
  • Test d'inclusion de fichier malveillant local (hack.php)
  • Implémentation d'une liste blanche pour sécuriser les inclusions
Fichier conf.php créé :
$link = mysqli_connect("localhost", "guewennmennegaut_secu", "MDP", "guewennmennegaut_securite");
if (!$link) {
    die("Erreur de connexion : " . mysqli_connect_error());
}
Code vulnérable EssaiSecurite.php :
$page = $_GET['page'];
include($page . ".php");
session_start();
Test d'inclusion normale :
URL : https://guewenn.mennegaut.mmi-velizy.fr/TP%20NOTE%20PHP/SECURITE/EssaiSecurite.php?page=conf
Résultat : Inclusion réussie du fichier conf.php
Fichier hack.php créé :
echo "SCRIPT MALVEILLANT EXÉCUTÉ !";
file_put_contents('hacked.txt', 'Site compromis le ' . date('Y-m-d H:i:s'));
system('ls -la');
Test d'exploitation :
URL : https://guewenn.mennegaut.mmi-velizy.fr/TP%20NOTE%20PHP/SECURITE/EssaiSecurite.php?page=hack
Résultat observé : Exécution du script malveillant hack.php
Risques identifiés :
  • Exécution de code PHP arbitraire
  • Création/modification de fichiers sur le serveur
  • Exécution de commandes système
  • Inclusion de fichiers distants si allow_url_include est activé
Dans le fichier hack.php
Ajout d'un echo
Résultat observé : Affichage du "Hack réussi !"
resultat
Protection par liste blanche :
$allowed_pages = ['conf', 'login', 'functions'];

$page = $_GET['page'];
if (in_array($page, $allowed_pages)) {
    include($page . ".php");
} else {
    die("Tentative d'inclusion non autorisée");
}

session_start();
Explication de la protection :
La liste blanche restreint les inclusions aux seuls fichiers autorisés :
  • Tableau des fichiers autorisés : $allowed_pages contient les noms sans extension
  • Vérification stricte : in_array() valide que le fichier demandé est dans la liste
  • Rejet immédiat : Les tentatives d'inclusion non autorisées sont bloquées
  • Extension fixe : L'extension .php est ajoutée automatiquement
Avantages :
  • Empêche l'inclusion de fichiers malveillants
  • Contrôle total sur les fichiers inclus
  • Protection contre les inclusions distantes
  • Facile à maintenir et auditer