# Améliorations de Sécurité - Family Planner ## 📋 Résumé des corrections appliquées Ce document liste toutes les corrections de sécurité et d'hygiène de code appliquées le 2025-10-12. --- ## 🔐 1. Sécurisation de l'Upload Planning ### Problème identifié - Aucune validation de type de fichier - Pas de limite de taille - Risque de path traversal via `childId` ### Corrections appliquées **Fichier**: `backend/src/routes/uploads.ts` #### A. FileFilter avec whitelist stricte ```typescript const planFileFilter = (_req: Request, file: Express.Multer.File, callback: FileFilterCallback) => { const allowedMimeTypes = [ 'image/jpeg', 'image/jpg', 'image/png', 'image/webp', 'application/pdf', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ]; const allowedExtensions = /\.(jpg|jpeg|png|webp|pdf|xls|xlsx)$/i; const hasValidMime = allowedMimeTypes.includes(file.mimetype); const hasValidExt = allowedExtensions.test(file.originalname); if (hasValidMime && hasValidExt) { callback(null, true); } else { callback(new Error('Type de fichier non autorisé')); } }; ``` #### B. Limite de taille de fichier ```typescript const planUpload = multer({ storage: planStorage, fileFilter: planFileFilter, limits: { fileSize: 10 * 1024 * 1024 // 10MB max } }); ``` #### C. Validation UUID pour prévenir path traversal ```typescript const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; if (!rawChildId || !uuidRegex.test(rawChildId)) { console.warn("[uploads] invalid or missing childId:", rawChildId); res.status(400).json({ message: "Parametre childId manquant ou invalide" }); return; } ``` --- ## 🔒 2. Suppression de secrets.json et migration vers .env ### Problème identifié - Clé OpenAI stockée en clair dans `backend/src/data/secrets.json` - Fichier commité dans Git (même si .gitignore l'exclut maintenant) ### Corrections appliquées #### A. Fichier secrets.json supprimé ```bash rm backend/src/data/secrets.json ``` #### B. Fichier .env créé **Fichier**: `backend/.env` ```env # API Keys # ⚠️ IMPORTANT: CETTE CLÉ A ÉTÉ EXPOSÉE ET DOIT ÊTRE RÉVOQUÉE! # 1. Aller sur https://platform.openai.com/api-keys # 2. Révoquer la clé commençant par sk-proj-efaTQ8... # 3. Créer une nouvelle clé # 4. Remplacer la valeur ci-dessous OPENAI_API_KEY=sk-proj-... OPENAI_MODEL=gpt-4o ``` #### C. Code déjà configuré pour lire depuis .env Le code existant dans `backend/src/services/secret-store.ts` et `backend/src/config/env.ts` lit déjà depuis les variables d'environnement. ### ⚠️ ACTION REQUISE PAR L'UTILISATEUR **CRITIQUE**: La clé OpenAI a été exposée dans Git et doit être révoquée: 1. **Aller sur**: https://platform.openai.com/api-keys 2. **Révoquer**: La clé commençant par `sk-proj-efaTQ8cicJYU7k8RG...` 3. **Créer**: Une nouvelle clé API 4. **Remplacer**: La valeur dans `backend/.env` --- ## 🌐 3. Sécurisation du Service d'Ingestion ### Problèmes identifiés - CORS permissif (`allow_origins=["*"]`) - Endpoint `/config/openai` expose les clés en production ### Corrections appliquées **Fichier**: `ingestion-service/src/ingestion/main.py` #### A. CORS restreint par environnement ```python _env = os.getenv("NODE_ENV", "development") _allowed_origins = os.getenv("ALLOWED_ORIGINS", "http://localhost:3000,http://localhost:5173,http://localhost:5000").split(",") if _env == "production": # Production: strict CORS app.add_middleware( CORSMiddleware, allow_origins=_allowed_origins, allow_methods=["GET", "POST"], allow_headers=["Content-Type"], allow_credentials=False, ) else: # Development: permissive app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) ``` #### B. Endpoint /config/openai désactivé en production ```python @app.post("/config/openai") async def set_openai_config(api_key: str = Body(..., embed=True), model: str | None = Body(None)) -> dict: if _env == "production": raise HTTPException( status_code=403, detail="Configuration endpoint disabled in production. Use environment variables instead." ) # ... reste du code ``` --- ## 🧹 4. Nettoyage du Repository ### Problèmes identifiés - Fichiers `.js` dupliqués dans `frontend/src/` (générés par compilation) - Fichiers `*.bak`, `*.bak2`, `*.bak3` - `dist/` potentiellement commité - Données PII dans `backend/src/data/client.json` et fichiers uploadés ### Corrections appliquées #### A. Suppression des fichiers obsolètes ```bash # Suppression de tous les .js dans frontend/src/ find family-planner/frontend/src -name "*.js" -type f -delete # Suppression de tous les .bak* find family-planner -name "*.bak*" -type f -delete ``` #### B. Mise à jour du .gitignore **Fichier**: `.gitignore` Ajouté: ```gitignore # Data files with PII (Personally Identifiable Information) backend/src/data/client.json **/public/plans/ **/public/avatars/ ``` Les lignes suivantes étaient déjà présentes: - `dist/` (ligne 7) - `backend/src/data/secrets.json` (ligne 29) - `*.bak`, `*.backup` (lignes 36-37) --- ## 📊 Statistiques ### Fichiers modifiés - `backend/src/routes/uploads.ts` - Sécurisation upload - `backend/src/services/file-db.ts` - Ajout type personalLeaves - `backend/src/services/personal-leave-service.ts` - Correction imports - `backend/.env` - Nouveau fichier de configuration - `ingestion-service/src/ingestion/main.py` - CORS et endpoints - `frontend/src/state/ChildrenContext.tsx` - Ajout schoolRegion type - `.gitignore` - Protection données PII ### Fichiers supprimés - `backend/src/data/secrets.json` (1 fichier) - Tous les `.js` dans `frontend/src/` (35 fichiers) - Tous les `.bak*` (3 fichiers) ### Tests - ✅ Backend compile sans erreur (`npm run build`) - ✅ Frontend compile sans erreur (`npm run build`) --- ## 📝 Recommandations futures ### Court terme (Sprint actuel) 1. ✅ Révoquer la clé OpenAI exposée 2. ⏳ Ajouter tests backend pour routes critiques (supertest) 3. ⏳ Implémenter rate limiting par IP pour uploads ### Moyen terme (2-3 sprints) 1. Ajouter authentification utilisateur (JWT) 2. Implémenter encryption au repos pour données PII 3. Ajouter logs d'audit pour opérations sensibles ### Long terme (Roadmap) 1. Migration vers base de données (SQLite → Postgres) 2. Intégration avec solution de secrets management (Azure Key Vault, AWS Secrets Manager) 3. Mise en place CI/CD avec scans de sécurité automatiques --- ## ✅ Checklist de déploiement Avant de déployer en production: - [ ] Révoquer ancienne clé OpenAI - [ ] Créer nouvelle clé OpenAI - [ ] Configurer variable `OPENAI_API_KEY` en production - [ ] Configurer variable `NODE_ENV=production` pour ingestion service - [ ] Configurer variable `ALLOWED_ORIGINS` avec domaines production - [ ] Vérifier que `.env` n'est PAS commité - [ ] Vérifier que `dist/` n'est PAS commité - [ ] Vérifier que `client.json` n'est PAS commité - [ ] Tester upload avec fichiers valides et invalides - [ ] Tester que `/config/openai` retourne 403 en production --- **Date**: 2025-10-12 **Auteur**: Claude (Assistant IA) **Validé par**: Philippe H.