Aller au contenu principal

Security Misconfiguration (mauvaise configuration de sécurité)

Schéma

  • Comprendre comment une application peut rester vulnérable même sans erreur dans son code, à cause de la façon dont elle est configurée et déployée (Security Misconfiguration, n°2 du Top 10 de l'OWASP (2025)).
  • Apprendre à retirer les réglages de développement avant la mise en production : pages de diagnostic, messages d'erreur détaillés, comptes par défaut.
attention

Un code parfaitement sécurisé peut quand même tout révéler si son environnement ne l'est pas : une page oubliée, une option de débogage laissée active, ou un compte jamais reconfiguré suffisent à donner à un attaquant tout ce dont il a besoin.


1. Création du projet vulnérable​

Créez un dossier tp-config contenant trois fichiers : des réglages laissés tels quels depuis le développement du site du club de randonnée.

diagnostic.php, une page créée pendant le développement pour vérifier la configuration du serveur, jamais retirée :

<?php
// Page créée pendant le développement, pour vérifier la configuration du serveur
phpinfo();

statistiques.php, qui affiche le nombre d'adhérents du club :

<?php
// Affiche quelques statistiques du club de randonnée
$pdo = new PDO('mysql:host=sql.club-randonnee.interne;dbname=club_randonnee', 'club_app', 'R@ndo2019!');

$nombreAdherents = $pdo->query('SELECT COUNT(*) FROM adherent')->fetchColumn();
echo "Nombre d'adhérents : $nombreAdherents";

admin.php, l'espace d'administration du club :

<?php
session_start();

$erreur = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Compte administrateur créé lors de l'installation du site, pour les premiers tests
if ($_POST['pseudo'] === 'admin' && $_POST['mot_de_passe'] === 'admin') {
$_SESSION['admin'] = true;
echo "Bienvenue dans l'administration du club de randonnée.";
exit;
}
$erreur = 'Identifiants incorrects.';
}
?>
<!DOCTYPE html>
<html lang="fr">
<head><meta charset="UTF-8"><title>Administration - Club de randonnée</title></head>
<body>
<h1>Administration du club de randonnée</h1>
<?php if ($erreur): ?><p style="color:red;"><?= htmlspecialchars($erreur) ?></p><?php endif; ?>
<form method="post" action="">
<p><label>Pseudo : <input type="text" name="pseudo"></label></p>
<p><label>Mot de passe : <input type="password" name="mot_de_passe"></label></p>
<button type="submit">Se connecter</button>
</form>
</body>
</html>
info

sql.club-randonnee.interne ne correspond à aucun serveur réellement joignable dans ce TP : c'est volontaire, pour provoquer une erreur de connexion à l'étape 3, exactement comme le ferait une base de données momentanément indisponible sur un vrai site.


2. Démarrer le serveur Web​

Dans le dossier tp-config, démarrez le serveur Web intégré à PHP, en activant volontairement l'affichage des erreurs (ce qui correspond au réglage display_errors = On d'un php.ini laissé en configuration de développement) :

php -S localhost:8000 -d display_errors=1

3. Repérer une page de diagnostic oubliée​

Ouvrez http://localhost:8000/diagnostic.php dans votre navigateur.

Question : Quelles informations cette page révèle-t-elle ? En quoi peuvent-elles aider un attaquant, alors qu'elles ne contiennent ni mot de passe ni donnée personnelle ?

📌 Une réponse

attention

diagnostic.php est un exemple classique de fonctionnalité de développement oubliée en production : utile pour déboguer en local, dangereuse si elle reste accessible à n'importe qui, une fois le site mis en ligne.


4. Provoquer une erreur verbeuse​

Ouvrez maintenant http://localhost:8000/statistiques.php.

Résultat attendu : une erreur PHP s'affiche directement dans le navigateur, avec une pile d'appels (stack trace) complète.

Question : Sans lire aucun mot de passe (PHP le masque automatiquement dans ce message d'erreur depuis la version 8.2), quelles informations exploitables un attaquant obtient-il quand même de ce message ?

📌 Une réponse

info

Depuis PHP 8.2, les paramètres marqués #[\SensitiveParameter] (dont le mot de passe de PDO::__construct()) sont automatiquement masqués dans les messages d'erreur et les traces d'appel. C'est une excellente protection, mais elle ne concerne que ce paramètre précis : tout le reste du message (chemins, hôtes, noms d'utilisateur) continue d'être affiché tel quel si display_errors est activé.


5. Utiliser le compte administrateur par défaut​

Ouvrez http://localhost:8000/admin.php et connectez-vous avec le pseudo admin et le mot de passe admin.

Résultat attendu : la connexion réussit immédiatement, sans qu'aucun mot de passe n'ait été deviné ni cassé.

Question : D'où vient ce compte, et pourquoi est-il si dangereux qu'il ait des identifiants aussi simples ?

📌 Une réponse

attention

Contrairement aux TP précédents (injection, XSS, CSRF, force brute), aucune attaque technique n'a été nécessaire ici : les trois failles de ce TP s'exploitent en lisant une page, en provoquant une erreur normale, ou en essayant le compte le plus évident. C'est ce qui rend la mauvaise configuration si fréquente : elle ne demande aucune compétence particulière à exploiter.


6. Supprimer la page de diagnostic​

La première correction est la plus simple : une page de diagnostic n'a jamais sa place sur un site en production. Supprimez le fichier diagnostic.php.

Rechargez http://localhost:8000/diagnostic.php.

Résultat attendu : une erreur 404 (page non trouvée) s'affiche : il n'y a plus rien à découvrir.

Bonne pratique - Retirer, pas seulement cacher

Ne protégez pas une page de diagnostic par un mot de passe « temporaire » en pensant la retirer plus tard : avec le temps, ces pages sont oubliées et finissent par rester accessibles pendant des années. La bonne pratique consiste à les supprimer du serveur de production dès que leur usage de développement n'est plus nécessaire.


7. Masquer les erreurs et les journaliser​

Modifiez tp-config/statistiques.php pour cesser d'afficher les erreurs au visiteur, tout en conservant le détail dans un fichier journal, utile à l'équipe technique :

<?php
// En production, l'affichage des erreurs est désactivé et les erreurs sont journalisées
ini_set('display_errors', '0');
ini_set('log_errors', '1');
ini_set('error_log', __DIR__ . '/erreurs.log');

try {
$pdo = new PDO('mysql:host=sql.club-randonnee.interne;dbname=club_randonnee', 'club_app', 'R@ndo2019!');
$nombreAdherents = $pdo->query('SELECT COUNT(*) FROM adherent')->fetchColumn();
echo "Nombre d'adhérents : $nombreAdherents";
} catch (PDOException $e) {
error_log('Erreur base de données : ' . $e->getMessage());
http_response_code(500);
echo "Une erreur est survenue. Merci de réessayer plus tard.";
}

Rechargez http://localhost:8000/statistiques.php, puis ouvrez le fichier tp-config/erreurs.log.

Résultat attendu : le navigateur affiche seulement « Une erreur est survenue. Merci de réessayer plus tard. », tandis que erreurs.log contient le détail complet de l'erreur (hôte, utilisateur, message exact).

Question : Pourquoi ne faut-il pas simplement supprimer l'information d'erreur, plutôt que de la déplacer vers un fichier journal ?

📌 Une réponse


8. Supprimer le compte par défaut​

Modifiez enfin tp-config/admin.php pour remplacer le compte codé en dur par un vrai compte, avec un mot de passe haché et propre au club :

<?php
session_start();

function trouverAdmin(string $pseudo): ?array
{
$admins = json_decode(file_get_contents(__DIR__ . '/admin.json'), true);
foreach ($admins as $admin) {
if ($admin['pseudo'] === $pseudo) {
return $admin;
}
}
return null;
}

$erreur = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$admin = trouverAdmin($_POST['pseudo'] ?? '');
if ($admin && password_verify($_POST['mot_de_passe'] ?? '', $admin['mot_de_passe'])) {
$_SESSION['admin'] = true;
echo "Bienvenue dans l'administration du club de randonnée.";
exit;
}
$erreur = 'Identifiants incorrects.';
}
?>
<!DOCTYPE html>
<html lang="fr">
<head><meta charset="UTF-8"><title>Administration - Club de randonnée</title></head>
<body>
<h1>Administration du club de randonnée</h1>
<?php if ($erreur): ?><p style="color:red;"><?= htmlspecialchars($erreur) ?></p><?php endif; ?>
<form method="post" action="">
<p><label>Pseudo : <input type="text" name="pseudo"></label></p>
<p><label>Mot de passe : <input type="password" name="mot_de_passe"></label></p>
<button type="submit">Se connecter</button>
</form>
</body>
</html>

avec un fichier admin.json contenant le nouveau compte :

[
{
"pseudo": "admin",
"mot_de_passe": "$2y$12$rLs4Xb0XZy336OLQmLobw.VNJmSwoCcVX7oWdhDWWj7aEhFhdwkD."
}
]

Rejouez l'étape 5 avec admin / admin.

Résultat attendu : la connexion est refusée. Le mot de passe réel de ce compte (que vous ne connaissez pas, comme un attaquant) a été choisi au moment de la mise en production, puis haché avec password_hash(), comme vu dans la séance sur le hachage sécurisé.

Bonne pratique - Pas de compte sans mot de passe propre

Un compte créé pour l'installation ou les premiers tests doit soit être supprimé, soit recevoir un mot de passe unique et robuste avant la mise en production. Cette règle vaut aussi pour les comptes des logiciels tiers installés sur le serveur (base de données, outils d'administration...), qui sont souvent livrés avec un identifiant et un mot de passe par défaut, documentés publiquement.


Notions théoriques​

La Security Misconfiguration (« mauvaise configuration de sécurité ») regroupe les failles qui ne viennent pas d'une erreur dans le code, mais de la façon dont l'application, le serveur ou les services qui l'entourent sont réglés et déployés.

remarque

Contrairement aux Authentication Failures, qui portent sur la façon dont une identité est vérifiée, la mauvaise configuration peut rendre une application vulnérable même si son code d'authentification est irréprochable.

Les principales formes de mauvaise configuration​

  • Fonctionnalités de développement oubliées : pages de diagnostic, comptes de test, jeux de données d'exemple, laissés accessibles après la mise en ligne.
  • Comptes par défaut non modifiés : identifiants fournis par un logiciel (base de données, CMS, outil d'administration) à l'installation, jamais changés.
  • Messages d'erreur trop détaillés : chemins de fichiers, requêtes SQL, versions de logiciels affichés directement à l'utilisateur.
  • En-têtes de sécurité absents ou mal réglés : voir la séance sur les vulnérabilités des headers HTTP, qui détaille cette partie de la mauvaise configuration, au niveau du serveur Web lui-même.
  • Environnements de développement et de production mal distingués : les mêmes identifiants, les mêmes réglages permissifs utilisés partout.
  • Permissions excessives sur un service cloud (par exemple un espace de stockage accessible à tous, alors qu'il ne devrait l'être qu'à l'application).
  • Mises à jour de sécurité non appliquées, qui laissent actives des failles déjà corrigées par l'éditeur du logiciel.

Pourquoi cette faille est-elle si fréquente ?​

D'après l'OWASP, en 2025, la totalité des applications testées présentaient au moins une forme de mauvaise configuration. Cette fréquence s'explique par un paradoxe : plus un système est configurable (ce qui est généralement une qualité), plus il offre de réglages qu'il est possible d'oublier ou de mal renseigner. Une seule case cochée par erreur, ou un seul fichier oublié, suffit.

Comment se protéger contre la mauvaise configuration ?​

  • Un processus de déploiement reproductible, qui installe toujours la même configuration durcie, plutôt que des réglages ajustés manuellement serveur par serveur.
  • Des environnements de développement et de production identiquement configurés, avec des identifiants différents dans chacun.
  • Une installation minimale : ne garder que les fonctionnalités, bibliothèques et comptes réellement nécessaires au fonctionnement du site.
  • La désactivation de l'affichage des erreurs en production, combinée à une journalisation systématique.
  • Un changement systématique des identifiants par défaut, pour l'application comme pour tous les services qu'elle utilise.
  • Une vérification régulière et automatisée de la configuration effectivement en place.
attention

Un site protégé contre l'injection SQL, le XSS et le CSRF, mais dont une page de diagnostic oubliée affiche encore la version exacte du serveur et le chemin complet de ses fichiers, facilite grandement la recherche d'une autre faille à exploiter. La mauvaise configuration n'est généralement pas la faille finale d'une attaque, mais souvent celle qui rend les autres possibles ou plus faciles.


Test de mémorisation/compréhension​


Qu'est-ce que la Security Misconfiguration, au sens de l'OWASP ?


Dans le TP, que révèle la page diagnostic.php à un visiteur ?


Pourquoi les informations de phpinfo() sont-elles utiles à un attaquant, même sans mot de passe ?


Que révèle le message d'erreur verbeux de statistiques.php, à l'étape 4 ?


Pourquoi le mot de passe de connexion à la base de données n'apparaît-il pas dans la trace d'erreur du TP ?


D'où vient le compte admin / admin utilisé à l'étape 5 ?


Qu'est-ce qui distingue ce TP de ceux sur l'injection SQL, le XSS ou le CSRF ?


Après la correction de l'étape 6, que se passe-t-il en ouvrant à nouveau diagnostic.php ?


Dans statistiques_corrige.php, où part le détail réel de l'erreur de connexion à la base de données ?


Que change admin_corrige.php par rapport à la version initiale d'admin.php ?


Pourquoi une page de diagnostic ne doit-elle jamais être seulement protégée par un mot de passe, plutôt que supprimée ?


Pourquoi dit-on que la mauvaise configuration rend souvent d'autres failles « possibles ou plus faciles » ?



Bonnes pratiques​

  • Ne jamais déployer de page ou de compte de développement sur un serveur de production : supprimer plutôt que masquer.
  • Désactiver display_errors en production, et journaliser systématiquement les erreurs côté serveur (log_errors, error_log).
  • Changer tous les identifiants par défaut, pour l'application comme pour les services qu'elle utilise (base de données, outils d'administration...).
  • Configurer les environnements de développement et de production de façon identique, avec des identifiants différents.
  • Automatiser le déploiement pour obtenir une configuration reproductible, plutôt que des réglages ajustés à la main.
  • Vérifier régulièrement la configuration réellement en place (en-têtes de sécurité, permissions, mises à jour disponibles).
attention

Un fichier de configuration contenant de vrais identifiants (base de données, clé d'API) ne doit jamais être envoyé dans un dépôt Git public. Un historique Git mal nettoyé peut continuer à exposer d'anciens identifiants, même après leur suppression du fichier actuel.


Ce que fait Symfony​

Symfony distingue automatiquement les environnements grâce à la variable APP_ENV (dev, prod...) : en environnement prod, les erreurs ne sont jamais affichées en détail au visiteur (une page générique est montrée), alors qu'elles le sont largement en dev, pour faciliter le travail du développeur.

# .env (jamais commité avec de vraies valeurs en production)
APP_ENV=prod
APP_DEBUG=0

Le bundle Symfony Maker ne génère également aucun compte ni aucune page de diagnostic par défaut : chaque compte administrateur doit être créé explicitement, avec son propre mot de passe, haché via UserPasswordHasherInterface.

attention

Le fichier .env ne doit contenir aucun secret réel lorsqu'il est versionné avec le code : les valeurs sensibles (mots de passe, clés d'API) se placent dans un fichier .env.local, exclu du dépôt Git par le .gitignore fourni avec Symfony.