Files
live-campus-mcs-p-2027.2/Semaine_08/secuvault/ATTACKS.md
T
gauvainboiche 3315cb2336 feat: Semaine 8
2026-05-11 09:25:19 +02:00

72 lines
4.1 KiB
Markdown

# BONUS - Résistance aux attaques
## Scénario 1 - Accès direct à un secret via l'URL (IDOR)
**Description**
Un utilisateur authentifié tente d'accéder à un secret appartenant à une équipe dont il n'est **pas** membre, en devinant ou en réutilisant un identifiant de secret dans l'URL.
**Procédure de test**
1. Se connecter en tant qu'**alice** (membre de `devops` uniquement).
2. Identifier l'identifiant du secret `Mailchimp API` (appartenant à `marketing`) - il est visible en parcourant la base de données ou en étant connecté en tant que BOB.
3. En tant qu'alice, accéder à `http://127.0.0.1:8000/secrets/<id_marketing>`.
**Résultat attendu**
HTTP 403 - page d'erreur « Accès refusé. »
**Résultat obtenu**
HTTP 403 - la route `GET /secrets/{secret_id}` délègue à `services.reveal_secret()`, qui appelle `check_team_membership(user, secret.team_id)`. Alice n'étant pas membre de `marketing`, une `AccessDeniedError` est levée dans la couche domaine, et la route retourne la page d'erreur 403 sans révéler aucune information sur le secret.
## Scénario 2 - Création d'un secret pour une équipe étrangère
**Description**
Un utilisateur authentifié soumet un formulaire de création de secret en falsifiant le champ `team_id` pour cibler une équipe dont il n'est **pas** membre.
**Procédure de test**
1. Se connecter en tant qu'**alice** (membre de `devops` uniquement).
2. Ouvrir les outils développeur du navigateur ou utiliser `curl` / Postman.
3. Envoyer une requête `POST /secrets` avec `name=test&value=hack&team_id=<id_marketing>`.
**Résultat attendu**
HTTP 403 - accès refusé, secret non créé.
**Résultat obtenu**
HTTP 403 - la route `POST /secrets` délègue à `services.create_secret()`, qui appelle `check_team_membership(user, team_id)` avant tout chiffrement ou écriture en base. La règle métier bloque la création et la route renvoie la page d'erreur 403.
## Scénario 3 - Enumération d'identifiants (ID enumeration)
**Description**
Un attaquant authentifié tente de lister tous les secrets en parcourant séquentiellement les identifiants (`/secrets/1`, `/secrets/2`, `/secrets/3`…).
**Procédure de test**
1. Se connecter en tant qu'**alice** (membre de `devops` uniquement).
2. Parcourir l'URL `http://127.0.0.1:8000/secrets/1`, `/secrets/2`, à partir de 1 en incrémentant.
3. L'ID 1 appartient à `devops` → alice peut le voir.
4. L'ID 2 appartient à `marketing` → alice ne devrait pas y avoir accès.
**Résultat attendu**
- `/secrets/1` → HTTP 200, valeur déchiffrée affichée (alice est membre de devops).
- `/secrets/2` → HTTP 403, page d'erreur « Accès refusé. »
**Résultat obtenu**
Conforme aux attentes. La protection n'est pas basée sur l'obscurcissement des identifiants mais sur le contrôle d'accès systématique dans `services.reveal_secret()` : chaque accès vérifie l'appartenance à l'équipe propriétaire du secret, quelle que soit la valeur de l'identifiant.
## Bonus - Conflit de rotation concurrente (Optimistic Locking)
**Description**
Deux utilisateurs membres d'une même équipe ouvrent simultanément le formulaire de rotation d'un secret et soumettent tous les deux leurs modifications.
**Procédure de test**
1. Se connecter en tant que **bob** dans deux onglets/navigateurs différents.
2. Dans les deux onglets, ouvrir le formulaire de rotation du secret `AWS root key` (équipe devops).
3. Soumettre la rotation dans le premier onglet → succès, la version passe à 2.
4. Soumettre la rotation dans le second onglet (qui contient toujours `expected_version=1`).
**Résultat attendu**
Le deuxième envoi est rejeté avec un message de conflit (HTTP 409).
**Résultat obtenu**
`services.rotate_secret()` compare `expected_version` avec la version courante en base. Si elles diffèrent, une `ConflictError` est levée avant toute modification. En base, la requête `UPDATE … WHERE id = ? AND version = ?` ne met à jour aucune ligne si la version a changé (`rowcount == 0`), ce qui constitue un second filet de sécurité. L'utilisateur voit le formulaire rechargé avec le message d'avertissement et la version actuelle du secret.