Aller au contenu principal

Politique de Sécurité

Ce fichier est la référence sécurité de la plateforme. Il répond à trois questions : comment nous nous protégeons, quoi faire si quelque chose est compromis, et comment nous gardons les dépendances saines. C'est pour nous d'abord, pour un auditeur ensuite.

Surface d'attaque — Ce qui est exposé publiquement

Cette section documente exactement ce qui est accessible sans authentification :

Endpoint / RessourcePublicAuthentifiéAdmin uniquement
POST /api/v1/auth/login
POST /api/v1/auth/register
GET /api/v1/internships
POST /api/v1/applications✅ (L3/M)
GET /api/v1/admin/users
Frontends (HTML/JS/CSS)

Règle : Tout ce qui n'est pas dans la colonne "Public" doit être refusé par le backend si le token est absent ou invalide. Le frontend n'est pas une protection.


Protection contre les attaques communes

Cette section documente chaque mesure en place et comment la vérifier :

Injection SQL

  • Mesure : SQLAlchemy ORM avec requêtes paramétrées. Aucune requête SQL construite à la main avec des f-strings.
  • Ce qui est interdit : f"SELECT * FROM users WHERE email='{email}'" — jamais.
  • Comment vérifier : Grep le code pour text( (requêtes SQL raw dans SQLAlchemy) — chaque occurrence doit être justifiée et utiliser des paramètres bindés.

XSS (Cross-Site Scripting)

  • Mesure : React échappe automatiquement le contenu des variables dans le JSX.
  • Ce qui est interdit : dangerouslySetInnerHTML sans sanitization explicite.
  • Cookie httpOnly : Le refresh token est inaccessible au JavaScript — même si du JS malicieux s'exécute, il ne peut pas voler le token de session.

CSRF (Cross-Site Request Forgery)

  • Mesure : SameSite=Lax sur les cookies + validation de l'origine dans les headers CORS côté backend.
  • Comment ça protège : Un site tiers ne peut pas déclencher des requêtes authentifiées à notre API depuis le browser d'un user connecté.

CORS

  • Mesure : Liste blanche explicite des origines autorisées dans FastAPI (jamais allow_origins=["*"] avec credentials).
  • Où c'est configuré : app/main.py, constante ALLOWED_ORIGINS.
  • Comment vérifier : Tester depuis une origine non listée → doit recevoir une erreur CORS.

Rate Limiting

  • Mesure : Nous limitons les endpoints sensibles (login, register, forgot-password) pour bloquer le brute force.
  • Outil recommandé : slowapi (FastAPI) ou rate limiting au niveau du reverse proxy (Nginx/Railway).
  • Seuils minimaux : Login → 10 tentatives / minute / IP. Register → 5 / minute / IP.
  • Nous documentons ici les seuils exacts configurés.

Mots de passe

  • Mesure : Hachage avec bcrypt (coût minimum 12). Jamais MD5, jamais SHA1, jamais en clair.
  • Aucun mot de passe ne doit apparaître dans les logs — vérifier que le schéma Pydantic de login exclut le password des logs.

Logs d'audit — Ce qui est tracé

Cette section documente quelles actions sont loggées et où :

ActionLoggée ?Ce qui est enregistré
Login réussiDB table audit_logsuser_id, IP, timestamp
Login échouéDB table audit_logsemail tenté, IP, timestamp
LogoutDB table audit_logsuser_id, timestamp
Action admin (suppression, modification)DB table audit_logsadmin_id, action, target_id, timestamp
Erreurs 500SentryStack trace complète

Règle : Les logs d'audit ne doivent jamais contenir de données sensibles (mot de passe, token complet, données personnelles non nécessaires).

Durée de rétention : Définir ici combien de temps les logs sont conservés (ex : 90 jours).


Gestion des dépendances vulnérables

Le vrai risque silencieux : une lib que nous utilisons a une faille connue et nous ne le savons pas.

Procédure de vérification (à faire chaque mois)

Backend (Python) :

pip install pip-audit
pip-audit
# Liste les CVE connues dans nos dépendances

Frontend (Node.js) :

npm audit
# ou
npm audit --fix # Correction automatique des failles non-breaking

Règle de réponse selon la sévérité

SévéritéDélai de correctionResponsable
Critique (CVSS ≥ 9)24h maximumDev senior en priorité absolue
Haute (CVSS 7-9)1 semaineDev senior
Moyenne (CVSS 4-7)Prochain sprintN'importe quel dev
Faible (CVSS < 4)BacklogTraité quand possible

Configurer GitHub Dependabot pour recevoir automatiquement des PRs quand une dépendance a une faille connue. C'est gratuit et ça prend 5 minutes à configurer.


Procédure d'incident — Si quelque chose est compromis

C'est le document le plus important à lire avant qu'un incident arrive, pas pendant.

Scénario 1 : Secret/credential exposé (API key, DB password dans un commit)

  1. Immédiatement (< 5 min) : Révoquer et régénérer le credential compromis — avant même de comprendre comment c'est arrivé
  2. Dans l'heure : Vérifier les logs pour détecter une utilisation non autorisée du credential
  3. Dans la journée : Identifier comment c'est arrivé, corriger le processus (.gitignore, pre-commit hook, etc.)
  4. Nous documentons : Ajouter un post-mortem dans security/incidents/YYYY-MM-DD-description.md

Scénario 2 : Compte admin compromis

  1. Immédiatement : Changer le mot de passe du compte (la révocation de token n'est pas encore implémentée — voir lacunes connues — le token actif reste valide maximum 15 minutes jusqu'à expiration naturelle)
  2. Immédiatement : Examiner les logs d'audit pour toutes les actions effectuées par ce compte dans les 24-72h précédentes

Scénario 3 : Faille découverte dans notre code

  1. Ne pas patcher en prod directement — créer une branche hotfix/
  2. Évaluer l'impact réel avant de paniquer : la faille est-elle exploitable ? A-t-elle été exploitée ?
  3. Patcher, tester sur staging, déployer
  4. Post-mortem obligatoire

Contacts d'urgence

Nous documentons ici (pas dans ce guide public, dans notre version interne) :

  • Qui appeler en dehors des heures de bureau
  • Accès Railway/Vercel en urgence (qui a les droits ?)
  • Si obligation légale de notification : contact CNIL

RGPD — Données personnelles collectées

Documenter ce que nous stockons et pourquoi — utile si quelqu'un demande la suppression de ses données ou si la CNIL pose des questions.

DonnéeOù stockéePourquoiDurée de rétention
EmailDB usersAuthentificationJusqu'à suppression du compte
Mot de passe (haché)DB usersAuthentificationJusqu'à suppression du compte
CV (fichier)Stockage fichiersCandidatureJusqu'à suppression du compte
Logs d'activitéDB audit_logsSécurité90 jours

Procédure de suppression de compte : Nous documentons exactement quelles tables sont touchées quand un user demande la suppression de ses données (droit à l'effacement RGPD).


Ce qui n'est PAS encore en place (et c'est ok)

Être honnête sur ce qui manque évite de fausser un futur audit. Nous documentons les lacunes connues avec une date cible :

MesureStatutPrioritéDate cible
Pentest externe❌ Pas faitMoyenneQuand 500+ users actifs
2FA pour les admins❌ Pas implémentéHauteSprint 3
Chiffrement des fichiers au repos❌ Pas faitMoyennePhase 2
Audit trail complet🟡 PartielHauteSprint 2
Révocation immédiate des tokens❌ Pas implémentéHauteSprint 2
Tokens en mémoire JS (pas localStorage)❌ À corrigerHauteSprint 1

Révocation des tokens : Currently Redis est utilisé comme cache de performance, pas comme gestionnaire de sessions. Le JWT est la seule source de vérité — si un token est volé ou si un compte admin est compromis, il est impossible de révoquer l'accès avant l'expiration naturelle du token (15 min access, 7j refresh). Solution cible : stocker les sessions actives dans Redis et vérifier à chaque requête.

localStorage vs mémoire : L'access token est actuellement stocké dans localStorage côté frontend. localStorage est accessible par tout script JS sur la page — une faille XSS permettrait de voler tous les tokens. Solution cible : access token en mémoire JS, refresh token en cookie httpOnly uniquement.

Pourquoi documenter les lacunes ? Parce qu'un auditeur les trouvera de toute façon. Mieux vaut montrer que nous en sommes conscients et que nous avons un plan.


Ce qu'il ne faut PAS mettre ici

  • ❌ Des credentials, tokens, ou mots de passe réels
  • ❌ Des détails d'exploitation de failles (comment attaquer notre propre système en détail — ça va dans un document privé séparé si nécessaire)
  • ❌ Des fausses assurances ("nous sommes totalement sécurisés") — personne ne l'est

Questions à se poser avant de valider ce document

  • Si un incident arrive demain, l'équipe sait quoi faire sans lire autre chose ?
  • Les lacunes connues sont-elles documentées honnêtement ?
  • Les logs d'audit couvrent-ils toutes les actions sensibles ?