# Modèle de sécurité — Immbot AI ## Authentification - **Sessions serveur** : cookie `immbot_session` httpOnly, `SameSite=Lax`, `Secure` en production, identifiant aléatoire 256 bits, **haché (SHA-256) avant stockage** dans la table `sessions` (un vol de la BD ne permet pas de rejouer une session). Expiration 14 jours glissants, révocation à la déconnexion et depuis l'admin. - **Mots de passe** : bcrypt (coût 12) via bcryptjs. Politique : ≥ 10 caractères. `admin123` explicitement refusé comme mot de passe permanent. - **Compte initial** : créé par script de seed depuis `INITIAL_ADMIN_USERNAME` / `INITIAL_ADMIN_PASSWORD` (défauts admin/admin123), champ `must_change_password=1` → redirection forcée vers le changement de mot de passe, bannière d'avertissement tant que le mot de passe initial est actif. `DISABLE_INITIAL_ADMIN=true` en production le désactive. - **Limitation des tentatives** : 8 échecs / 15 min par (IP + identifiant), à mémoire serveur + journalisées dans `auth_events` (connexions, échecs, changements de mot de passe, déconnexions). - **Récupération** : changement par l'utilisateur (mot de passe actuel requis) ; réinitialisation par l'admin (mot de passe temporaire + changement forcé). Pas de courriel en v1 (documenté). - **CSRF** : mutations via `fetch` même origine + vérification systématique de l'en-tête `Origin`/`Sec-Fetch-Site` sur toutes les routes mutantes + cookies SameSite. Pas de formulaires cross-site. - **SSO futur** : la table `users` porte `auth_provider` (`local` aujourd'hui) et un identifiant externe nullable — l'ajout d'OIDC (Microsoft/Google/UQO) n'exige pas de migration. ## Autorisation - Rôles : `student` < `instructor` < `admin` (l'admin a tout ; l'instructeur a la pédagogie et le contenu, pas la gestion des utilisateurs). - **Contrôle d'accès par cours** : table `enrollments` ; toute requête chat/RAG/apprentissage vérifie l'inscription au cours visé, côté serveur. - **Espaces de connaissances** : chaque fragment porte `space` (`official-imm1003`, `official-imm1033`, `student-temporary-upload`, `student-persistent-files`, `instructor-private`, `general-knowledge`). Les requêtes étudiantes ne touchent jamais `instructor-private` ni les téléversements d'un autre étudiant (filtre SQL systématique, testé). - Routes `/admin` et `/api/admin/*` : middleware + revérification du rôle dans chaque handler. ## Secrets et données - `OPENROUTER_API_KEY` uniquement côté serveur (routes API) ; jamais dans un composant client, jamais journalisée. `.env` gitignoré ; `.env.example` sans valeurs réelles. - Journaux structurés sans secrets ni contenu de mot de passe ; les messages d'erreur client ne fuient pas les détails internes. - Données étudiantes : minimisation (nom d'utilisateur, courriel optionnel) ; les statistiques professeur sont **agrégées et anonymisées** (seuil de 3 étudiants minimum avant affichage d'un agrégat) ; le contenu individuel n'est jamais montré. - `submissions.db` du prototype et le matériel d'examen : exclus / `instructor-private` (voir repository-analysis.md). - Sauvegardes : `scripts/backup.sh` (copie datée de `data/` hors uploads temporaires). ## Défenses applicatives - Validation zod de toutes les entrées API ; limites de taille (messages 32 k, uploads 25 Mo, types MIME vérifiés par signature). - Requêtes SQL exclusivement préparées (aucune concaténation). - Rendu Markdown sans HTML brut (`skipHtml`) → pas de XSS via réponses de modèle. - En-têtes : CSP (script-src 'self'), X-Content-Type-Options, Referrer-Policy, X-Frame-Options DENY. - Injection de prompt : le contenu récupéré et les fichiers étudiants sont encadrés de délimiteurs et le prompt système précise qu'ils sont des **données**, pas des instructions ; la validation de citations empêche l'exfiltration de fragments non autorisés (le serveur ne fournit au modèle que les fragments auxquels l'utilisateur a déjà droit). - Limites d'usage : budgets quotidiens/mensuels par utilisateur et globaux, appliqués côté serveur avant chaque appel modèle. ## Journalisation et audit `auth_events` (sécurité), `usage_log` (appels modèles : utilisateur, modèle, jetons, coût, latence), `ingestion_runs` (contenu), `report_flags` (réponses signalées). Consultables dans l'admin.