Files
gauvainboiche 3315cb2336 feat: Semaine 8
2026-05-11 09:25:19 +02:00

4.1 KiB

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.