Examiner et prévenir une régression de sécurité

CybersécuritéBeginner
Pratiquer maintenant

Introduction

Un paramètre de débogage temporaire est revenu dans une nouvelle version du service DeskLite. Les requêtes réussissent toujours, mais les journaux opérationnels contiennent maintenant un identifiant fictif. Une simple vérification de réussite fonctionnelle n'a pas détecté cette régression.

Vous suivrez les preuves de véritables requêtes, arrêterez les nouvelles fuites, remplacerez l'identifiant exposé et ajouterez une assertion qui bloque un candidat présentant réellement une fuite. Les journaux historiques restent des preuves ; aucun document d'investigation n'est requis. L'émetteur local, le client, le service, les témoins de comparaison et les utilitaires d'artefacts sont préparés.

Repérer l'événement réel de l'incident

Dans cette étape, vous mettrez en relation une requête avec la version et la configuration de journalisation actuelles.

cd /srv/ticket-regression

tail -n 5 lit les cinq dernières lignes, ce qui limite l'affichage. Utilisez votre lecture autorisée en tant qu'administrateur pour le journal du service préparé :

sudo tail -n 5 /opt/labex-ticket-regression/requests.log

Repérez request_id=initial-001, version=logging-v2, path=/tickets et status=200. Cette requête historique a réussi, mais la même ligne contient Authorization et l'ancien jeton fictif. Toutes les valeurs appartiennent uniquement à ce lab isolé.

grep affiche les lignes contenant un motif textuel fourni. Les apostrophes maintiennent ce motif littéral dans un seul argument :

sudo grep 'request_id=initial-001' /opt/labex-ticket-regression/requests.log
cat logging.conf

include_authorization = true explique la présence du champ sensible. L'heure, l'ID de requête, la version et le statut de l'événement relient le comportement observé à la configuration active. Conservez le journal d'origine ; l'effacer supprimerait des preuves sans empêcher les fuites futures.

Arrêter les champs sensibles dans les nouveaux événements

Dans cette étape, vous modifierez la politique de journalisation tout en conservant des champs d'audit utiles.

nano logging.conf

Utilisez :

[logging]
include_authorization = false

Enregistrez avec Ctrl+O, Enter et Ctrl+X. Appliquez la configuration enregistrée avec le point d'entrée de redémarrage préparé :

bash restart.sh

Donnez à une nouvelle requête de santé un ID connu. X-Request-ID est un en-tête de requête utilisé pour retrouver son nouvel événement :

curl -H 'X-Request-ID: after-policy-fix' http://127.0.0.1:8080/health
sudo grep 'request_id=after-policy-fix' /opt/labex-ticket-regression/requests.log

L'heure, la version, l'ID, le chemin et status=200 sont attendus, sans champ Authorization. L'ancien événement initial-001 reste présent. Évaluez les nouveaux événements à partir de leurs propres ID au lieu d'exiger que chaque ligne historique soit exempte de secret.

Révoquer et remplacer l'identifiant exposé

Dans cette étape, vous retirerez le pouvoir d'authentification de l'ancien jeton avec la méthode d'émetteur déjà apprise.

Modifier la politique de journalisation n'invalide pas une valeur exposée. Révoquez son ID de gestion :

course-token revoke legacy
curl -i -H 'Authorization: Bearer labex_012345abcdefghijklmnopqrstuvwxyz' http://127.0.0.1:8080/tickets

Le résultat attendu est 401. Émettez maintenant l'identifiant de remplacement sans l'afficher :

course-token issue /srv/ticket-regression/api.token

Protégez-le avec le modèle administrateur/groupe du client des labs sur les permissions et les jetons :

sudo chown root:deskclient api.token
sudo chmod 640 api.token

L'émetteur a créé la valeur ; vous définissez seulement son accès. Ne la copiez pas dans le code source des tests, le script client ou un rapport écrit.

Rétablir le client qui lit le fichier

Dans cette étape, vous ferez utiliser au client existant l'identifiant de remplacement protégé.

nano sender.sh

Enregistrez la même forme de lecture de fichier enseignée précédemment :

#!/bin/bash
exec sudo -u deskclient /usr/bin/python3 /opt/labex-ticket-regression/send.py --token-file /srv/ticket-regression/api.token

Utilisez Ctrl+O, Enter, Ctrl+X.

bash sender.sh

La sortie attendue est HTTP 200 et le ticket Printer offline d'origine. Lisez les événements opérationnels récents :

sudo tail -n 5 /opt/labex-ticket-regression/requests.log

La nouvelle requête réussie conserve les champs d'audit sans valeur d'identifiant. Une ancienne valeur divulguée peut rester dans l'historique d'incident conservé alors que son pouvoir d'authentification a été retiré. Cette distinction évite à la fois de supprimer les preuves et de considérer l'ancienne exposition comme un chemin d'authentification qui réussit encore.

Comprendre pourquoi le test existant a manqué la fuite

Dans cette étape, vous inspecterez le petit modèle de test avant d'ajouter la nouvelle exigence.

cat test_security.py

Le test positif utilise le modèle de requête du lab sur l'écriture de tests. L'utilitaire api préparé fournit token depuis la source d'identifiants de la cible et renvoie le véritable statut HTTP, le corps et l'événement de journal réel de cette requête. "Bearer " + token assemble deux chaînes pour former une valeur d'en-tête ; la valeur n'est pas copiée dans le code source.

Deux témoins distincts utilisent le jeton de test public fictif : good omet les champs sensibles du journal, tandis que logging-regression enregistre délibérément ce jeton de test. Ils n'utilisent ni n'exposent votre nouvel identifiant de remplacement opérationnel.

course-regression-tests good
course-regression-tests logging-regression

Les deux réussissent actuellement test_valid_token : le statut et les données métier restent corrects dans chaque implémentation. L'exigence manquante concerne le véritable événement dans response["log"]. Chaque requête de l'utilitaire utilise un ID unique : le journal renvoyé appartient donc à cette nouvelle requête, pas à un événement historique sans rapport.

Ajouter une véritable assertion de masquage des données sensibles du journal

Dans cette étape, vous compléterez le test avec des exigences d'absence et de présence pour le nouvel événement.

En Python, in vérifie si une chaîne apparaît à l'intérieur d'une autre. not in exige son absence. Ces assertions concernent le véritable texte du journal renvoyé, pas un fichier de preuve fourni manuellement.

nano test_security.py

Conservez le test positif et utilisez ce fichier complet :

from api import request, token

def test_valid_token():
    response = request("/tickets", {"Authorization": "Bearer " + token})
    assert response["status"] == 200
    assert response["body"] == {"tickets": [{"id": 1, "title": "Printer offline"}]}

def test_log_is_redacted():
    response = request("/tickets", {"Authorization": "Bearer " + token})
    assert response["status"] == 200
    assert "Authorization" not in response["log"]
    assert token not in response["log"]
    assert "request_id=" in response["log"]
    assert "path=/tickets" in response["log"]
    assert "status=200" in response["log"]

Enregistrez avec Ctrl+O, Enter, Ctrl+X. Le nouveau test rejette le champ sensible et la valeur d'identifiant tout en exigeant l'ID de requête, le chemin métier et le statut de réussite. Vider le journal ferait échouer ces exigences positives.

L'utilitaire fournit en interne un jeton propre à la cible. Les tests du service normal lisent l'identifiant de remplacement protégé ; les témoins de comparaison utilisent le jeton de test public fictif. Aucune de ces valeurs n'a sa place dans ce fichier de test.

Prouver que le test détecte la régression connue

Dans cette étape, vous validerez la nouvelle assertion face à un comportement sûr et à un comportement présentant délibérément une fuite.

course-regression-tests good

Les deux tests doivent réussir.

course-regression-tests logging-regression

Seul test_log_is_redacted doit échouer avec AssertionError, en renvoyant le code de sortie 1. Il s'agit d'une détection intentionnelle, pas d'une demande d'affaiblir l'assertion. Le test métier positif doit continuer à réussir.

course-regression-tests live

Les deux tests doivent réussir contre votre véritable service corrigé. Ces tests n'inspectent que les événements de leurs nouvelles requêtes ; l'événement historique divulgué d'origine est intentionnellement conservé. Une erreur de syntaxe, une erreur de connexion ou un échec inconditionnel ne démontrerait pas une couverture efficace du masquage des données sensibles.

Relier le nouveau test à la livraison du candidat

Dans cette étape, vous empêcherez la livraison d'un futur candidat lorsque la nouvelle assertion échoue.

Le contrôle préparé utilise la même structure vérification/construction/test/déploiement que dans le lab précédent sur les contrôles bloquants. build.sh empaquette le serveur d'origine et la politique de journalisation actuelle, puis démarre ce véritable candidat sur un port local distinct. Le test.sh existant vérifie son comportement avec jeton valide/absent/erroné ; il ne vérifie pas les journaux.

nano gate.sh

Ajoutez l'appel de non-régression après la construction et avant les tests fonctionnels existants. Utilisez :

#!/bin/bash
bash checks.sh
status=$?
if [ "$status" -eq 1 ]; then
    exit 1
fi
if [ "$status" -ne 0 ]; then
    exit 2
fi
bash build.sh || exit 2
bash regression.sh candidate || exit 2
bash test.sh || exit 2
bash deploy.sh

Enregistrez avec Ctrl+O, Enter, Ctrl+X. candidate sélectionne la véritable application qui vient d'être construite : l'assertion ajoutée protège donc l'artefact sur le point d'être déployé. || exit 2 arrête la livraison si ses tests échouent.

bash gate.sh

Le contrôle préalable des identifiants, la construction du véritable candidat, la réussite des nouveaux tests de non-régression, celle des tests fonctionnels et le déploiement de ce candidat sur le port local opérationnel sont attendus. Laisser simplement un fichier de test inutilisé n'apporterait pas cette prévention.

Confirmer les nouveaux événements et l'historique conservé

Dans cette étape, vous vérifierez le comportement livré et réfléchirez aux preuves sans rédiger de fichier de rapport.

bash sender.sh
sudo tail -n 5 /opt/labex-ticket-regression/requests.log

Les nouveaux événements opérationnels doivent conserver l'heure, la véritable version livrée, les ID de requêtes, les chemins et les statuts sans identifiants. La version livrée est maintenant une empreinte d'artefact au lieu du libellé logging-v2 d'origine.

sudo grep 'request_id=initial-001' /opt/labex-ticket-regression/requests.log

L'événement d'incident d'origine existe toujours. Son ancien jeton est révoqué ; l'identifiant de remplacement protégé fonctionne. Le témoin distinct de régression délibérée est une comparaison pédagogique, pas le service déployé.

Expliquez-vous quel événement a révélé le problème, quel paramètre l'a causé, pourquoi la seule correction de politique était insuffisante et comment la nouvelle assertion sur le candidat empêche sa réapparition. La vérification du cours exerce un candidat présentant réellement la régression, confirme que le contrôle le bloque et vérifie que l'artefact sûr précédemment en cours d'exécution est préservé. Aucun document d'investigation à format imposé n'est requis.

Résumé

Vous avez relié un véritable événement d'incident à sa politique de journalisation, arrêté les nouvelles fuites, révoqué et remplacé l'identifiant exposé, et conservé les preuves historiques. Une nouvelle assertion détecte la régression délibérée et s'exécute sur le véritable candidat à l'intérieur du contrôle de livraison, préservant un comportement sûr en cours d'exécution lorsqu'un futur candidat échoue.