Réactis — Logiciel SaaS de gestion de crise — IFClubs SAS — Juillet 2026
| Mesure | État | Détail |
|---|---|---|
| Pare-feu | ✅ Actif | ufw, politique par défaut deny en entrée — seuls les ports 22 (SSH), 80 (HTTP) et 443 (HTTPS) sont ouverts, IPv4 et IPv6 |
| EDR / détection comportementale | ✅ Actif | CrowdSec + bouncer pare-feu — analyse en temps réel des logs SSH, HTTP et système, blocage automatique des IP malveillantes (brute force, exploitation de CVE HTTP, scénarios d'attaque connus de la communauté CrowdSec) |
| Audit système | ✅ Actif | auditd — journalisation des appels système sensibles, intégré à CrowdSec |
| Anti-bruteforce SSH | ✅ Actif | fail2ban — plusieurs milliers d'IP bannies historiquement sur tentatives de connexion SSH répétées |
| Mises à jour de sécurité | ✅ Actif | unattended-upgrades — application automatique des correctifs de sécurité du système |
| Paramètre | Valeur |
|---|---|
| Authentification par mot de passe | ❌ Désactivée — clé cryptographique uniquement (ED25519) |
| Connexion root | Restreinte — PermitRootLogin prohibit-password, clé uniquement, aucun mot de passe accepté |
| Traçabilité | Toutes les connexions SSH sont journalisées (/var/log/auth.log) et analysées en continu par CrowdSec |
Chaque établissement client dispose d'une instance logicielle indépendante : processus Node.js dédié, répertoire de données distinct sur le système de fichiers, base de données et identifiants propres (mots de passe hashés bcrypt). Il est techniquement impossible pour un tenant d'accéder aux données d'un autre.
| Canal / donnée | Mécanisme |
|---|---|
| Transport | TLS 1.2 / 1.3 + HSTS sur l'ensemble des domaines |
| Mots de passe | Hachage bcrypt (coût 10) — jamais stockés en clair |
| Secrets d'authentification forte (TOTP) | Chiffrement AES-256-GCM au repos, jamais en clair sur le serveur |
| Sauvegardes | Archives AES-256, clé dédiée par tenant, stockées hors du répertoire de production |
| Secrets applicatifs (.env) | Fichiers système, permissions restreintes, non versionnés dans le code |
Trois modes de connexion coexistent dans le logiciel, chaque établissement choisissant le sien :
Séparation stricte des rôles (admin / membre / invité) appliquée côté serveur sur chaque route, jamais côté client uniquement. Les actions sensibles (gestion utilisateurs, régénération IA, déploiement) sont réservées à des comptes identifiés nommément.
Principes appliqués systématiquement dans le code des 12 sites Réactis :
requireAuth / requireAdmin) — jamais de contrôle d'accès reposant uniquement sur le frontendUn audit de code ciblé (contrôle d'accès, injection de commande, traversée de chemin, secrets en dur, limitation de débit) a été mené sur l'ensemble du code des 4 périmètres (Établissement, Groupe, Régional, Master). Toutes les failles identifiées comme critiques ou élevées ont été corrigées :
| Constat | État | Correctif |
|---|---|---|
| Contrôle d'accès manquant sur plusieurs routes de lecture/écriture du journal de crise | ✅ Corrigé | Middleware d'autorisation serveur ajouté systématiquement (recherche de crises, historique des résumés, alertes email, points de situation) |
| Construction de chemin de fichier à partir d'un identifiant non filtré (risque de traversée de répertoire) | ✅ Corrigé | Fonction de nettoyage appliquée systématiquement avant toute lecture/écriture disque (les identifiants concernés sont des horodatages numériques — tout caractère hors chiffres est désormais rejeté) |
| Construction de commande système par concaténation de chaîne dans la console d'administration (provisioning de nouveaux clients) | ✅ Corrigé | Remplacé par un appel de processus sans interprétation shell, arguments transmis sans passer par une chaîne de commande — élimine la classe de vulnérabilité, y compris sur un champ texte libre du formulaire d'inscription public |
| Limitation de débit absente sur certaines routes de connexion et de changement de mot de passe | ✅ Corrigé | Limiteur de tentatives (15 min glissantes) étendu à toutes les routes d'authentification restantes |
| Endpoints de diagnostic WhatsApp accessibles sans mot de passe (statut, QR de connexion) | ✅ Corrigé | Authentification par mot de passe admin désormais exigée |
| Mot de passe administrateur de la console Master : valeur de secours codée en dur si la configuration serveur était incomplète | ✅ Corrigé | Le service refuse désormais de démarrer sans mot de passe explicitement configuré, aucune valeur par défaut possible |
| Résumé IA d'un message externe collé (WhatsApp/SMS/email) envoyé sans passer par le scanner de risques appliqué au journal — seul un masquage silencieux (sans blocage) protégeait ce point d'entrée précis | ✅ Corrigé | Le même scanner et le même réglage tenant que le journal (bloquant par défaut) sont désormais appliqués avant l'envoi à l'IA (20/07/2026) |
| Comptes-rendus de réunion remontés à un tenant régional/groupe : en mode avertissement local, un CR pouvait contenir des éléments à risque en clair, sans scanner propre au niveau régional/groupe pour les rattraper | ✅ Corrigé | Rédaction forcée (masquage mobile/email/NIR) à la source, sur la route de remontée /api/groupe/summary, indépendamment du mode local de l'établissement (20/07/2026) |
Deux points mineurs restent délibérément non modifiés à ce stade, avec justification documentée en interne : un identifiant technique utilisé pour l'authenticité d'un webhook Microsoft Teams n'a pas été régénéré à chaud pour ne pas casser une intégration déjà active (sera traité lors de la prochaine re-souscription du webhook) ; un lien d'impression de statistiques transmet un jeton dans l'URL par nécessité fonctionnelle (lien imprimable direct) plutôt que par un en-tête — accepté comme compromis fonctionnel, sans donnée sensible exposée.
Par souci de transparence, le détail ci-dessous décrit la stack réelle et l'organisation réelle des fichiers sur le serveur — aucune abstraction ni simplification de façade.
| Couche | Technologie | Détail |
|---|---|---|
| Backend | Node.js + Express.js | Un processus Node dédié par tenant, API REST, aucun framework low-code / no-code |
| Frontend | HTML/CSS/JavaScript | Pages servies statiquement par Express (express.static), pas de framework compilé côté client — code lisible tel quel, sans étape de build masquant le contenu |
| Persistance | Fichiers JSON sur disque | Pas de base de données relationnelle pour ce périmètre : chaque tenant a son propre jeu de fichiers JSON (journal de crise, membres, contacts, paramètres…) — voir détail ci-dessous |
| Dépendances | package.json déclaratif par service | Chaque backend déclare explicitement ses dépendances (Express, bcrypt, dotenv, express-rate-limit, multer, nodemailer, etc.) — npm audit exécuté sur les 7 services actifs le 19/07/2026, 0 vulnérabilité à date |
Structure réelle d'un répertoire de tenant (exemple représentatif, noms génériques) :
| Chemin | Contenu | Accès |
|---|---|---|
backend/index.js | Code applicatif (routes, logique métier) | Serveur uniquement, jamais exposé au web |
backend/.env | Secrets (JWT, mots de passe API, clés de chiffrement) | Permissions restreintes (lecture propriétaire uniquement), non versionné |
data/tenant.json, data/members.json, data/contacts.json… | Données métier du tenant (config, membres, contacts, historique) | Permissions restreintes au niveau système de fichiers ; accès applicatif exclusivement via routes authentifiées |
data/attachments/ | Pièces jointes du journal de crise (upload membre/coordinateur) | Servi via /attachments, middleware d'authentification obligatoire avant tout accès statique |
uploads/ | Relevés PDF importés | Servi via /uploads, même garde d'authentification |
logs/, data/logs/ | Journaux applicatifs et d'audit | Non exposés au web, accès serveur uniquement |
| Mesure | État | Détail |
|---|---|---|
| Limite de taille | ✅ Actif | 20 Mo (pièces jointes journal), 50 Mo (relevés PDF) — appliqué au niveau multer, requête rejetée au-delà |
| Filtrage de type | ✅ Actif | Liste blanche de types MIME (PDF, JPEG, PNG, WebP, GIF, texte, Word) pour les pièces jointes ; PDF uniquement pour les relevés |
| Vérification du contenu réel | ✅ Actif | Pour les relevés PDF, le type déclaré par le navigateur n'est pas considéré fiable à lui seul (usurpable) : une vérification de la signature binaire du fichier (en-tête %PDF-) est effectuée après réception, avant conservation |
| Nom de fichier | ✅ Actif | Le nom original est assaini (caractères non alphanumériques remplacés) et horodaté avant écriture sur disque — élimine tout risque de traversée de répertoire ou d'écrasement de fichier via un nom de fichier malveillant |
| Accès en lecture | ✅ Actif | Les répertoires d'upload ne sont jamais servis en statique nu : un middleware d'authentification s'exécute systématiquement avant toute réponse de fichier |
| Scanner de risques (contenu, 20/07/2026) | ✅ Actif | Chaque PDF déposé dans le plan blanc ou la base documentaire est analysé localement, sans aucun appel IA (contrôle par expressions déterministes) à la recherche d'éléments qui ne doivent jamais être transmis à un fournisseur IA externe : marqueur de classification restreinte/interne, numéro de mobile personnel, adresse email nominative. Comportement paramétrable par établissement : bloquant par défaut (le fichier est refusé et supprimé, le dépôt échoue) ou avertissement (le fichier est conservé mais signalé, et reste exclu du pipeline IA tant qu'il l'est) |
Un point d'entrée unique (callAI()) gère l'intégralité des appels IA. Aucun fallback automatique entre fournisseurs : le tenant reste strictement sur celui qu'il a configuré. Sur les environnements de démonstration, un garde-fou bloque toute requête réseau vers un fournisseur IA — zéro appel, zéro coût.
Aucun contenu ne part vers un fournisseur IA sans être passé, en amont, par un contrôle local et déterministe — jamais par un appel réseau vers un service tiers, ce qui recréerait précisément le risque que ce contrôle vise à prévenir. Ce filtrage est appliqué à chaque point d'entrée de texte libre saisi ou importé par un humain :
| Point d'entrée | Contrôle | Comportement |
|---|---|---|
| Documents déposés (plan blanc, base documentaire) | Scanner local : classification restreinte/interne, mobile, email | ✅ Actif — bloquant par défaut, + validation humaine indépendante (Valideur) |
| Journal de crise (main courante) | Scanner local : mobile, email, numéro de sécurité sociale (NIR) | ✅ Actif — bloquant par défaut, contrôle client ET serveur (non contournable) |
| Transcription de réunion (import Teams manuel ou automatique) | Même scanner que le journal, appliqué avant le filtrage IA du bruit | ✅ Actif — bloquant par défaut |
| Message externe résumé par l'IA (import WhatsApp/SMS/email) | Même scanner que le journal | ✅ Actif — bloquant par défaut, réglage tenant partagé avec le journal |
| Fournisseur | Localisation | Engagement RGPD |
|---|---|---|
| Mistral AI (défaut) | France (UE) | DPA signé · pas d'entraînement de modèle · traitement intégralement UE |
| Groq Inc. | USA | DPA signé · CCT/SCC · rétention 0 jour (traitement mémoire) |
| Anthropic PBC | USA | DPA signé · CCT/SCC · rétention 30j max (logs sécurité) |
| Azure OpenAI (Microsoft) | Déploiement client | Sous le contrat Microsoft propre du client |
La plateforme est aujourd'hui hébergée sur un VPS IONOS SE, en France, chez un hébergeur certifié ISO 27001 — mais Réactis ne traite aucune donnée de santé à caractère personnel (pas de dossier patient, pas de donnée médicale nominative), ce qui fait que la certification HDS n'est pas une obligation réglementaire pour ce périmètre. La migration vers un serveur OVH dédié certifié HDS est néanmoins planifiée (S1 2027), par choix de renforcement plutôt que par obligation.