Complete family planning application with: - React frontend with TypeScript - Node.js/Express backend with TypeScript - Python ingestion service for document processing - Planning ingestion service with LLM integration - Shared UI components and type definitions - OAuth integration for calendar synchronization - Comprehensive documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
7.2 KiB
7.2 KiB
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
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
const planUpload = multer({
storage: planStorage,
fileFilter: planFileFilter,
limits: {
fileSize: 10 * 1024 * 1024 // 10MB max
}
});
C. Validation UUID pour prévenir path traversal
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é
rm backend/src/data/secrets.json
B. Fichier .env créé
Fichier: backend/.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:
- Aller sur: https://platform.openai.com/api-keys
- Révoquer: La clé commençant par
sk-proj-efaTQ8cicJYU7k8RG... - Créer: Une nouvelle clé API
- Remplacer: La valeur dans
backend/.env
🌐 3. Sécurisation du Service d'Ingestion
Problèmes identifiés
- CORS permissif (
allow_origins=["*"]) - Endpoint
/config/openaiexpose les clés en production
Corrections appliquées
Fichier: ingestion-service/src/ingestion/main.py
A. CORS restreint par environnement
_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
@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
.jsdupliqués dansfrontend/src/(générés par compilation) - Fichiers
*.bak,*.bak2,*.bak3 dist/potentiellement commité- Données PII dans
backend/src/data/client.jsonet fichiers uploadés
Corrections appliquées
A. Suppression des fichiers obsolètes
# 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é:
# 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 uploadbackend/src/services/file-db.ts- Ajout type personalLeavesbackend/src/services/personal-leave-service.ts- Correction importsbackend/.env- Nouveau fichier de configurationingestion-service/src/ingestion/main.py- CORS et endpointsfrontend/src/state/ChildrenContext.tsx- Ajout schoolRegion type.gitignore- Protection données PII
Fichiers supprimés
backend/src/data/secrets.json(1 fichier)- Tous les
.jsdansfrontend/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)
- ✅ Révoquer la clé OpenAI exposée
- ⏳ Ajouter tests backend pour routes critiques (supertest)
- ⏳ Implémenter rate limiting par IP pour uploads
Moyen terme (2-3 sprints)
- Ajouter authentification utilisateur (JWT)
- Implémenter encryption au repos pour données PII
- Ajouter logs d'audit pour opérations sensibles
Long terme (Roadmap)
- Migration vers base de données (SQLite → Postgres)
- Intégration avec solution de secrets management (Azure Key Vault, AWS Secrets Manager)
- 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_KEYen production - Configurer variable
NODE_ENV=productionpour ingestion service - Configurer variable
ALLOWED_ORIGINSavec domaines production - Vérifier que
.envn'est PAS commité - Vérifier que
dist/n'est PAS commité - Vérifier que
client.jsonn'est PAS commité - Tester upload avec fichiers valides et invalides
- Tester que
/config/openairetourne 403 en production
Date: 2025-10-12 Auteur: Claude (Assistant IA) Validé par: Philippe H.