Aller au contenu

Session 8 — Chaos Sécurité — 9 failles OWASP implémentées

Durée : ~8 heures (3 conversations Claude) Objectif initial : Implémenter le Chaos Sécurité selon le prompt de conception livré en Session 7 Objectif final : 9 failles OWASP opérationnelles + UI chaos-admin + onglet monitoring + 5 passes de revue de code


🎯 Réalisations

1. SecurityChaosService.java — service central

Temps : ~1h30 Difficulté : ⭐⭐⭐⭐

Service Java construit sur le même pattern que BusinessChaosService :

  • AtomicInteger level (0–3) + 9 AtomicLong compteurs par faille
  • ConcurrentLinkedDeque activity log ring buffer 200 entrées max
  • 9 flags booléens : isInjectionActive(), isIdorActive(), isPasswordExposed(), isXssActive(), isPriceTamperingActive(), isTimingAttackActive(), isWeakTokenActive(), isPathTraversalActive(), isMassAssignmentActive()

Méthodes utilitaires exposées aux controllers

Méthode Faille Comportement
recordSqlInjection(q, email) S1 Détecte les patterns SQLi dans le paramètre q
recordIdorAccess(requesterId, ownerId, orderId) S2 Logue l'accès cross-user
recordPasswordHashExposed(email) S3 Incrémente compteur S3
processShippingAddress(addr) S4 Retourne l'adresse non sanitisée en N2+
recordPriceTampering(email, orig, received) S5 Logue l'écart prix
recordTimingAttack(email, exists, ms) S6 Logue le timing et le δt
generateWeakToken(userId) S7 HMAC-SHA256 clé "secret123"
validateWeakToken(token) S7 Vérifie la signature
processInvoiceFormat(format, id, email) S8 Simule le path traversal
detectAndRecordMassAssignment(body, user) S9 Détecte champs sensibles dans le body

Token S7 — format détaillé

base64url(userId:timestamp).base64url(hmac-sha256("secret123", "userId:timestamp"))

HMAC calculé via javax.crypto.Mac JDK natif — zéro dépendance Maven externe.

Records Java 17 :

record WeakTokenValidation(boolean valid, Long userId, Long timestamp, String error) {}
record PathTraversalResult(boolean traversalAttempted, String filename, String content, String detectedPath) {}

S8 — simulation pédagogique

simulateFileContent() retourne du contenu fictif pour les chemins reconnus (passwd, application.yml, .env, shadow) afin de montrer l'impact d'un vrai path traversal sans accéder au filesystem réel.

Champs sensibles S9

Set.of("email", "password", "id", "createdAt", "lastLogin")

role n'existe pas dans l'entité User — décision architecturale prise lors de la conception pour rester fidèle au modèle de données réel.


2. SecurityChaosController.java — endpoints admin + publics

Temps : ~30 min Difficulté : ⭐⭐

Pattern identique à BusinessChaosController, sous @RequestMapping("/api") :

Endpoints admin (auth AdminAuth requise) :

POST /api/admin/chaos/security          → setLevel(level)
GET  /api/admin/chaos/security/status   → statut complet + compteurs
POST /api/admin/chaos/security/reset    → reset niveau + compteurs
POST /api/admin/chaos/security/logs/clear

Endpoints publics (sans auth, pour le monitoring) :

GET /api/chaos/public/security/status
GET /api/chaos/public/security/logs
GET /api/chaos/public/security/faults?level=N


3. Modifications des controllers existants — 7 fichiers

Temps : ~2h Difficulté : ⭐⭐⭐⭐

Chaque faille est un hook conditionnel dans le controller cible. Niveau 0 = comportement 100% nominal, aucun impact.

ProductController — S1

if (securityChaosService.isInjectionActive()) {
    List<Product> raw = productRepository.slowSearchFullScan(q); // SQL native non paramétrée
    securityChaosService.recordSqlInjection(q, email);
    return ResponseEntity.ok(raw);
}
// Fallback N0 : JPQL paramétré sécurisé
return ResponseEntity.ok(productService.searchProducts(...));

OrderController — S2, S4, S5, S8

  • S2 : dans getOrder() et getOrderDetails(), la vérification order.getUser().getId().equals(userId) est court-circuitée en N1+ avec log cross-user si détecté
  • S4 : dans createOrder(), l'adresse de livraison passe par processShippingAddress() en N2+
  • S5 : dans createOrder(), si unitPrice est présent dans le body, il est injecté via la clé _chaosClientPrice dans OrderService
  • S8 : nouvel endpoint GET /api/orders/{id}/invoice — validé en N0-2, path traversal simulé en N3+

OrderService — S5

Object chaosPrice = rawItem.get("_chaosClientPrice");
if (chaosPrice instanceof BigDecimal cp) basePrice = cp;
// → prix client accepté sans revalidation

UserController — S3, S9

  • S3 : getProfile() appelle buildProfileDtoWithHash() en N1+ — copie du DTO standard avec ajout du champ password (hash BCrypt $2a$...)
  • S9 : updateProfile() bypasse la whitelist en N3+ via detectAndRecordMassAssignment(), applique email et password directement

AuthController — S6, S7

  • S6 : mesure System.currentTimeMillis() avant/après authService.login() + recordTimingAttack() en N2+
  • S7 : generateWeakToken(user.getId()) → header X-Debug-Token dans la réponse de login en N3+

ChaosController — reset global

resetAll() appelle securityChaosService.reset() — le bouton "Reset tout" du chaos-admin couvre désormais les 5 systèmes chaos.


4. UI chaos-admin — onglet Chaos Sécurité

Temps : ~45 min Difficulté : ⭐⭐⭐

Extension du chaos-admin/public/index.html :

  • Tab 🔒 Chaos Sécurité + section dédiée
  • 4 cartes de niveau cliquables (0 Désactivé → 3 Expert) avec couleur et description pédagogique
  • Bandeau statut : niveau actif + compteur total d'événements de sécurité
  • Description courte de chaque faille active par niveau
  • loadSecurityStatus() appelé au switch d'onglet

5. Monitoring — onglet Sécurité

Temps : ~1h Difficulté : ⭐⭐⭐

Extension du monitoring/public/index.html :

  • Tab 🔐 Chaos Sécurité
  • Bandeau niveau actif + compteurs hits globaux
  • Grille KPI 9 cases (S1-S9) : compteur de déclenchements + état actif/inactif selon niveau
  • Grille failles actives/inactives avec badge sévérité (Junior/Confirmé/Expert)
  • Table logs sécurité : 60 dernières entrées, colonnes timestamp/faille/sévérité/utilisateur/détail
  • fetchSecurity() toutes les 2 secondes

6. Cinq passes de revue de code

Temps : ~2h Difficulté : ⭐⭐⭐

Revue exhaustive après chaque bloc d'implémentation majeur. Deux bugs corrigés :

Bug #1 — fetchSecurity() : garde paused incorrecte (revue 3)

La fonction utilisait if (paused) au lieu de if (!autoRefresh) — cohérence avec le pattern des autres onglets (fetchMetier, fetchScripting).

Bug #2 — Accolade fermante parasite dans fetchSecurity() (revue 5)

Une accolade } orpheline créait une SyntaxError JavaScript au chargement de la page — erreur silencieuse côté serveur mais bloquante côté navigateur. Corrigée via edit_block ciblé.

GO compilation donné après revue 5.


🎢 Chronologie Détaillée

Phase 1 (~2h) : SecurityChaosService + Controller 🟢

  • Définition des 9 flags et compteurs
  • Implémentation des méthodes utilitaires S1-S9
  • Token HMAC S7 via javax.crypto.Mac
  • Pattern PathTraversalResult et WeakTokenValidation (Java 17 records)
  • Ressenti : 🟢 Architecture très proche du Chaos Métier — copier/adapter, pas créer

Phase 2 (~2h) : Modifications des 7 controllers/services 🟢

  • ProductController S1
  • OrderController S2, S4, S5, S8
  • OrderService S5
  • UserController S3, S9
  • AuthController S6, S7
  • ChaosController reset global
  • Ressenti : 🟢 Chaque hook isolé, niveau 0 toujours nominal

Phase 3 (~1h45) : UI chaos-admin + monitoring 🟢

  • Section chaos-admin : 4 cartes de niveau
  • Onglet monitoring : KPIs + logs sécurité
  • CSS dédié : .sec-kpi-grid, .sec-fault, .sec-log-table, badges sévérité
  • Ressenti : 🟢 Cohérence visuelle avec les onglets Métier et Scripting

Phase 4 (~2h) : 5 passes de revue de code 🟢

  • Revues 1-2 : aucun problème
  • Revue 3 : garde paused vs !autoRefresh
  • Revue 5 : accolade orpheline SyntaxError
  • Compilation Maven : 47 sources, BUILD SUCCESS sur le code Java
  • Ressenti : 🟢 Confiance haute, peu d'erreurs, revue efficace

🧠 Moments Clés d'Apprentissage

1. Zéro dépendance Maven externe grâce au JDK natif

HMAC-SHA256 via javax.crypto.Mac et java.util.Base64 disponibles dans tout JDK 8+. Pas besoin de librairie externe pour les opérations cryptographiques usuelles.

Règle : avant d'ajouter une dépendance Maven, vérifier si le JDK standard couvre déjà le besoin (java.security, javax.crypto, java.util.Base64).

2. Java 17 records pour les types de retour complexes

PathTraversalResult et WeakTokenValidation encapsulent proprement plusieurs valeurs de retour sans créer des classes entières. Plus lisible qu'un Map<String, Object>, plus léger qu'un DTO classique.

record WeakTokenValidation(boolean valid, Long userId, Long timestamp, String error) {}

3. S8 simulé = pédagogie sans risque

Simuler le contenu d'un path traversal (/etc/passwd, application.yml) sans accéder au filesystem réel permet : - De montrer l'impact d'un vrai LFI (Local File Inclusion) avec du contenu réaliste - D'éviter tout accès non autorisé au système de fichiers du container - De maîtriser exactement ce que l'étudiant voit (contenu fictif maîtrisé)

4. Le pattern "hook conditionnel" est scalable

La même architecture s'applique sur 4 systèmes chaos (Backend sliders, Scripting tokens, Métier anomalies, Sécurité failles) : service central + méthodes utilitaires + hooks conditionnels dans les controllers existants + endpoints publics pour le monitoring.

5. La revue de code sur le JavaScript est plus délicate qu'en Java

Les erreurs JS comme l'accolade orpheline (bug #2) ne lèvent aucune erreur côté serveur — le fichier est servi, le navigateur échoue silencieusement (ou affiche une SyntaxError dans la console DevTools). En Java, le compilateur Maven refuse de produire le .jar.

Règle : toujours tester les pages modifiées dans le navigateur après chaque changement JS, DevTools console ouverte.


📊 Métriques de la Session

Métrique Valeur
Durée totale ~8 heures
Conversations Claude 3
Fichiers Java créés 2 (SecurityChaosService, SecurityChaosController)
Fichiers Java modifiés 5 (ProductController, OrderController, OrderService, UserController, AuthController, ChaosController)
Fichiers HTML modifiés 2 (chaos-admin/index.html, monitoring/index.html)
Failles implémentées 9 (S1-S9)
Passes de revue de code 5
Bugs corrigés en revue 2
Sources Maven compilées 47 (sans erreur)
Lignes de code ~1200 (Java + HTML + JS)

🎯 Difficultés Rencontrées

🟢 Faible (⭐⭐)

Problème : role ciblé en S9 mais absent de l'entité User Temps perdu : ~5 min
Solution : Cible email + password uniquement — fidèle au modèle de données réel Leçon : Toujours vérifier l'entité JPA avant de cibler un champ en mass assignment

🟢 Faible (⭐⭐)

Problème : Bug JS accolade orpheline — SyntaxError silencieux côté serveur Temps perdu : ~10 min (détecté en revue 5) Solution : edit_block ciblé sur l'accolade parasite Leçon : Tester le JS dans le navigateur après chaque modification, DevTools console ouverte


✅ Ce Qui a Bien Fonctionné

Architecture mature — copier/adapter, pas créer

La Session 8 a bénéficié de toutes les décisions architecturales précédentes. SecurityChaosService est une variante de BusinessChaosService — même ring buffer, mêmes patterns, même philosophie. Le temps de conception architecturale était quasi nul.

HMAC sans dépendance externe

javax.crypto.Mac + java.util.Base64 suffisent pour HMAC-SHA256. Contrainte "zéro dépendance Maven" respectée à 100% malgré la complexité du token S7.

Ratio de bugs le plus bas du projet

5 passes de revue de code n'ont révélé que 2 bugs, tous mineurs (JS). C'est le meilleur ratio depuis le début du projet — signe d'une architecture maîtrisée et d'une méthodologie de développement rodée.

Compilation Maven propre

47 sources compilées sans erreur Java. Le warning unchecked sur OrderController (cast générique) est intentionnel et documenté. Aucune régression sur le code existant.


🎓 Conclusion

Cette session de ~8 heures en vibe coding a permis de :

Implémenter le Chaos Sécurité complet — 9 failles OWASP sur 3 niveaux, toutes observables ✅ Zéro dépendance Maven externe — HMAC-SHA256 via JDK natif, token forgeable pédagogiquement ✅ S8 path traversal simulé — contenu fictif réaliste sans accès filesystem réel ✅ 5 passes de revue de code — 2 bugs détectés et corrigés, compilation Maven propre ✅ Documentation MkDocs complètechaos/security.md + mise à jour intro, roadmap, guides, index

Ratio temps productif / temps total : ~94% Objectifs atteints : 100% — les 5 systèmes chaos (Backend, Frontend, Scripting, Métier, Sécurité) sont opérationnels

La Session 8 est la session la plus productive du projet en ratio. La maturité architecturale accumulée sur 7 sessions s'est pleinement exprimée : les hooks conditionnels, les ring buffers, les endpoints publics pour le monitoring, les cartes de niveau dans le chaos-admin — tout était déjà là. Il ne restait qu'à le décliner pour la cinquième couche chaos.

La leçon de cette session : investir du temps en architecture propre et en patterns réutilisables sur les premières sessions se rembourse exponentiellement sur les sessions suivantes. La Session 1 a coûté ~3h15 en erreurs pour ~6h de travail (46%). La Session 8 n'a coûté que ~30 min en erreurs pour ~8h de travail (94%).


🤖 Erreurs imputables à Claude AI — Session 8


❌ Erreur S8-1 — Garde paused au lieu de !autoRefresh dans fetchSecurity()

Ce que j'ai proposé : Le monitoring fetchSecurity() utilisait if (paused) pour gérer la pause du refresh automatique.

Ce qui s'est passé : Le pattern établi dans les autres onglets (fetchMetier, fetchScripting) utilise if (!autoRefresh). La variable paused n'existe pas dans ce contexte — l'onglet sécurité ne se mettait jamais en pause réellement.

Pourquoi c'était une erreur : Incohérence avec la convention établie depuis la Session 6. J'aurais dû relire les fonctions fetchMetier() et fetchScripting() avant d'écrire fetchSecurity() pour reprendre exactement le même pattern.

Temps perdu : ~10 min (détecté revue 3) | Sévérité : ⭐⭐


❌ Erreur S8-2 — Accolade fermante orpheline dans fetchSecurity()

Ce que j'ai proposé : La fonction fetchSecurity() avec une accolade } parasite en fin de bloc try/catch.

Ce qui s'est passé : SyntaxError JavaScript bloquant le chargement complet de la page monitoring — aucun onglet ne se chargeait, erreur visible uniquement dans la console DevTools.

Pourquoi c'était une erreur : Faute de frappe/décompte classique dans un bloc try/catch imbriqué. La revue de code humaine manuelle (sans linter) ne détecte pas toujours ce type d'erreur au premier coup d'œil sur 50+ lignes de JS.

Temps perdu : ~15 min (détecté revue 5, edit_block ciblé) | Sévérité : ⭐⭐⭐


📊 Récapitulatif Session 8

# Erreur Temps perdu Sévérité
S8-1 Garde paused vs !autoRefresh dans fetchSecurity() ~10 min ⭐⭐
S8-2 Accolade orpheline — SyntaxError JS ~15 min ⭐⭐⭐
TOTAL ~25 min

Pattern : Incohérence de convention JS — le même type d'erreur que les bugs CSS chips en Session 7 (chip-PROMO_OK vs chip-PROMO). La frontière compilateur/interpréteur reste le principal angle mort : Java refuse de compiler, JS échoue silencieusement côté serveur.

Progrès notable : 2 bugs en 5 passes de revue sur ~8h de développement — le ratio erreurs/code le plus faible de toutes les sessions. La maturité architecturale du projet se traduit directement en qualité de livraison.