Sécurité des Projets Utilisateur
Vue d’ensemble
Cette page documente la mise en place de la sécurisation des projets utilisateur dans l’architecture EXAI, garantissant que chaque utilisateur ne peut accéder qu’à ses propres projets.
Cette fonctionnalité corrige un trou de sécurité critique où tous les projets étaient accessibles à tous les utilisateurs. |
Problème de sécurité identifié (2025-01-25)
Description du problème
Vulnérabilité critique : - ❌ Tous les projets étaient accessibles à tous les utilisateurs connectés - ❌ Les endpoints de projets n’avaient aucune vérification d’appartenance - ❌ L'`user_id` était généré aléatoirement au lieu d’utiliser l’utilisateur connecté - ❌ Possible accès aux projets d’autres utilisateurs en devinant les IDs
Endpoints vulnérables :
- GET /projects
- Listait TOUS les projets
- POST /projects
- Créait des projets avec user_id
aléatoire
- GET /projects/{id}
- Accès à n’importe quel projet
- PUT /projects/{id}
- Modification de n’importe quel projet
- DELETE /projects/{id}
- Suppression de n’importe quel projet
- GET /projects/{id}/recommendations
- Recommandations de n’importe quel projet
Solution mise en place
Architecture de sécurité
graph TD
A[Frontend Angular] -->|JWT Token| B[API Gateway]
B -->|Authentification| C{Utilisateur valide?}
C -->|Non| D[Erreur 401]
C -->|Oui| E[Extraction user_id]
E -->|Header X-User-ID| F[Service Selection]
F -->|Filtrage par user_id| G[Base de données]
G -->|Projets de l'utilisateur uniquement| H[Réponse sécurisée]
Mécanisme d’authentification
1. API Gateway (Transmission de l’user_id)
Fichier : api-gateway/app/main.py
# Fonction proxy_request modifiée
headers = {
"Content-Type": "application/json",
"User-Agent": "API-Gateway-Proxy/1.0",
"X-User-ID": str(current_user.id), # ✅ ID utilisateur transmis
"X-User-Email": current_user.email # ✅ Email pour debug
}
Mécanisme :
- L’API Gateway extrait l’utilisateur connecté via current_active_user
- L'`user_id` est transmis au service-selection via le header X-User-ID
- Tous les endpoints de projets nécessitent une authentification
2. Service Selection (Vérification de l’user_id)
Fichier : service-selection/app/main.py
# Dépendance d'authentification
def get_current_user_id(x_user_id: str = Header(..., alias="X-User-ID")) -> UUID4:
try:
user_id = uuid.UUID(x_user_id)
return user_id
except ValueError:
raise HTTPException(status_code=401, detail="ID utilisateur invalide")
Fonctionnement : - Extraction automatique de l'`user_id` depuis les headers - Validation du format UUID - Erreur 401 si header manquant ou invalide
Endpoints sécurisés
GET /projects - Liste des projets
Avant (vulnérable) :
# ❌ Tous les projets de tous les utilisateurs
query = db.query(models.Project)
Après (sécurisé) :
# ✅ Seulement les projets de l'utilisateur connecté
current_user_id: UUID4 = Depends(get_current_user_id)
query = db.query(models.Project).filter(models.Project.user_id == current_user_id)
POST /projects - Création de projet
Avant (vulnérable) :
# ❌ user_id généré aléatoirement
user_id = uuid.uuid4() # Temporaire
Après (sécurisé) :
# ✅ user_id de l'utilisateur connecté
current_user_id: UUID4 = Depends(get_current_user_id)
db_project = models.Project(user_id=current_user_id, ...)
GET/PUT/DELETE /projects/{id} - Opérations sur projet
Avant (vulnérable) :
# ❌ N'importe quel projet accessible
project = db.query(models.Project).filter(models.Project.id == project_id).first()
Après (sécurisé) :
# ✅ Seulement les projets de l'utilisateur connecté
project = db.query(models.Project).filter(
models.Project.id == project_id,
models.Project.user_id == current_user_id # ✅ Vérification obligatoire
).first()
Gestion des erreurs de sécurité
if not project:
# ✅ Ne pas révéler l'existence du projet à d'autres utilisateurs
raise HTTPException(status_code=404, detail="Projet non trouvé")
Principe : Retourner 404 (non trouvé) plutôt que 403 (interdit) pour ne pas révéler l’existence de projets d’autres utilisateurs.
Logging de sécurité
Tous les endpoints incluent maintenant des logs de sécurité :
logger.info(f"✅ Utilisateur {current_user_id} - Action sur projet: {project_id}")
Types de logs : - Création de projet - Accès à un projet - Modification de projet - Suppression de projet - Génération de recommandations
Tests de sécurité
Scénarios de test
Test 1 : Isolation des projets par utilisateur
-
Utilisateur A se connecte et crée un projet
-
Utilisateur B se connecte
-
Utilisateur B tente d’accéder au projet de A
-
Résultat attendu : Erreur 404 "Projet non trouvé"
Considérations de performance
Conformité et audit
Migration et déploiement
Données existantes
Si des projets existaient avant la correction :
-- Identifier les projets avec user_id incorrect
SELECT id, name, user_id FROM projects WHERE user_id NOT IN (SELECT id FROM users);
-- Option 1: Supprimer les projets orphelins
DELETE FROM projects WHERE user_id NOT IN (SELECT id FROM users);
-- Option 2: Réassigner à un utilisateur administrateur
UPDATE projects SET user_id = 'admin-uuid' WHERE user_id NOT IN (SELECT id FROM users);