Introduction
La défense en profondeur consiste à utiliser plusieurs contrôles combinés afin qu'une erreur isolée ne suffise pas à exposer un actif important. Une vérification de jeton, une liaison réseau locale, des permissions de fichiers et une journalisation protègent chacune une partie différente du même service.
Dans ce laboratoire, vous allez renforcer un petit service Python qui lit un fichier secret. Vous effectuerez une petite modification à la fois, exécuterez le service, le testerez avec curl et vérifierez que les couches fonctionnent ensemble.
Partir d'un secret exposé
Dans cette étape, vous allez inspecter le service et observer le premier contrôle : une requête sans le jeton attendu est rejetée, tandis qu'une requête avec le jeton réussit. La défense en profondeur commence par vérifier ce qui est déjà protégé et ce qui nécessite une couche supplémentaire.
Déplacez-vous dans le répertoire du projet :
cd /home/labex/project
Listez les fichiers préparés :
ls -l
Vous devriez voir secret_service.py, secret.txt et service-check.py.
Démarrez le service en arrière-plan. Le & à la fin indique au shell de maintenir le service en cours d'exécution pendant que vous continuez à saisir des commandes :
python3 secret_service.py > service.log 2>&1 &
Enregistrez l'identifiant du processus en arrière-plan afin de pouvoir l'arrêter proprement plus tard :
echo $! > service.pid
Essayez de lire le secret sans jeton :
curl -i http://127.0.0.1:8081/secret
La réponse devrait inclure 403 Forbidden. Envoyez maintenant l'en-tête de jeton requis :
curl -s -H "X-Access-Token: lab-token-2026" http://127.0.0.1:8081/secret
Vous devriez voir :
Project launch code: ORBIT-742
Arrêtez le service avant de continuer :
kill "$(cat service.pid)"
Exécutez le vérificateur pour la couche de jeton :
python3 service-check.py token
Le résultat attendu est :
token: complete
Maintenir le service en local
Dans cette étape, vous allez confirmer la couche d'exposition réseau. Un service qui ne nécessite qu'un accès local doit se lier à 127.0.0.1, également appelé localhost. Cette adresse n'accepte que les connexions provenant de la même machine.
Inspectez le paramètre d'hôte par défaut du service :
grep 'default="127.0.0.1"' secret_service.py
Vous devriez voir la définition de l'argument pour l'option --host. Cette valeur par défaut signifie que l'exécution de python3 secret_service.py démarre le service sur localhost.
Redémarrez le service :
python3 secret_service.py > service.log 2>&1 &
Enregistrez l'identifiant du processus :
echo $! > service.pid
Utilisez ss pour inspecter les sockets TCP en écoute. Les options -ltn signifient écoute, TCP et adresses numériques :
ss -ltn | grep ':8081'
La sortie devrait afficher 127.0.0.1:8081, ce qui prouve que le service est uniquement local :
LISTEN ... 127.0.0.1:8081 ...
Arrêtez le service :
kill "$(cat service.pid)"
Exécutez le vérificateur pour la couche localhost :
python3 service-check.py localhost
Le résultat attendu est :
localhost: complete
Restreindre le fichier secret
Dans cette étape, vous allez ajouter une couche de permissions de système de fichiers. Même si le service présente une vulnérabilité, le fichier secret ne devrait pas être lisible par tous les comptes locaux.
Vérifiez les permissions actuelles du fichier :
ls -l secret.txt
Le fichier commence avec des permissions larges afin que vous puissiez les améliorer. Utilisez chmod 600 pour rendre le fichier lisible et modifiable uniquement par son propriétaire :
chmod 600 secret.txt
Vérifiez à nouveau les permissions :
ls -l secret.txt
Les bits de permission devraient maintenant commencer par -rw------- :
-rw------- ... secret.txt
Exécutez le vérificateur pour cette couche :
python3 service-check.py permissions
Le résultat attendu est :
permissions: complete
Journaliser les requêtes rejetées
Dans cette étape, vous allez tester la couche de détection. Bloquer une requête non autorisée est utile, mais enregistrer ce rejet fournit aux opérateurs la preuve que quelqu'un a tenté d'accéder à la route protégée.
Supprimez tout ancien fichier journal pour que cette étape commence proprement :
rm -f access.log
Démarrez le service :
python3 secret_service.py > service.log 2>&1 &
Enregistrez l'identifiant du processus :
echo $! > service.pid
Envoyez une requête sans le jeton :
curl -s http://127.0.0.1:8081/secret
Le corps de la réponse devrait être :
forbidden
Affichez le journal d'accès :
cat access.log
Le journal devrait contenir rejected, /secret et missing_or_bad_token.
Arrêtez le service :
kill "$(cat service.pid)"
Exécutez le vérificateur pour la couche de journalisation :
python3 service-check.py logging
Le résultat attendu est :
logging: complete
Vérifier les couches ensemble
Dans cette étape, vous allez vérifier le résultat complet de la défense en profondeur. Le service doit exiger le jeton, rester local par défaut, protéger le fichier secret avec des permissions réservées au propriétaire et journaliser les requêtes rejetées.
Exécutez le vérificateur complet :
python3 service-check.py all
Chaque couche devrait être complète :
token: complete
localhost: complete
permissions: complete
logging: complete
Démarrez le service une dernière fois :
python3 secret_service.py > service.log 2>&1 &
Enregistrez l'identifiant du processus :
echo $! > service.pid
Confirmez que le secret fonctionne toujours pour une requête autorisée :
curl -s -H "X-Access-Token: lab-token-2026" http://127.0.0.1:8081/secret
Vous devriez toujours voir :
Project launch code: ORBIT-742
Arrêtez le service :
kill "$(cat service.pid)"
Cette vérification finale est importante car la défense en profondeur doit protéger le service sans entraver l'utilisation autorisée prévue.
Résumé
Vous avez mis en pratique la défense en profondeur en superposant des contrôles autour d'un petit service. Vous avez vérifié l'exigence d'un jeton, la liaison locale uniquement, les permissions de fichiers réservées au propriétaire et la journalisation des accès rejetés.
La leçon principale est que chaque couche protège un point de défaillance différent tout en permettant au comportement autorisé du service de fonctionner normalement.



