Files
FamilyPlanner/docs/archive/SECURITY_IMPROVEMENTS.md
philippe fdd72c1135 Initial commit: Family Planner application
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>
2025-10-14 10:43:33 +02:00

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:

  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

_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 .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

# 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 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.