Audit de sécurité de la vitrine de démonstration — Round 9

Rédigé le 18 juin 2026 — 22:49 (Europe/Paris) · Notation CVSS v4.0 · Écosystème MySelf · AGPL-3.0

Document public. Audit interne assisté par IA sur un banc de démonstration jetable (données 100 % factices). Ce n'est pas un test red team externe indépendant — c'est notre auto-audit défensif, rendu public pour montrer ce que l'écosystème MySelf protège et comment nous corrigeons ce qui tombe. Dépersonnalisé : aucune adresse, aucun nom d'hôte, aucune valeur de marqueur, aucun identifiant réel. Cycle complet : trouver → corriger → re-valider.

TL;DR

1. Périmètre et méthode

Cible : un banc de démonstration en réseau local (Linux Debian 13), hébergeant les modules MySelf sous forme de sites séparés :

ModuleRôle
Landingpage de présentation
SelfRecoverrécupération de compte sans e-mail (niveaux L1 / L2 / L3 + variante Lite)
SelfDataGuardchiffrement des données
Forum (Lab)auth SelfRecover, messages privés, mémo chiffré de bout en bout, modération
SelfJusticedirectives juridiques

Accès : boîte grise raisonnable — un compte système non privilégié (la racine restait à conquérir), lecture de configuration autorisée, comptes applicatifs créés librement via l'inscription ouverte.

Outils (versionnés) : nmap, ssh-audit, sslscan, nuclei, httpx, ffuf, curl, scripts Python, plus des tests manuels (IDOR, mass-assignment, logique métier, cas-limites de modération, défi du mémo chiffré). Deux passes : audit applicatif depuis un poste de confiance, puis vérification que les défenses réseau bloquent réellement un poste non listé.

2. Ce que la vitrine protège

Défenses éprouvées qui tiennent.

DéfenseVérificationStatut
Mémo chiffré de bout en boutAucune voie HTTP ne sort le mémo en clair : la clé est dérivée du mot de passe dans le navigateur, jamais transmise.✅ imprenable
Messages privés (chiffrés au repos)Clé hors racine web, non lisible sans compromission disque (non atteinte).✅ tient
Contrôle d'accès forum (IDOR)L'identifiant de ressource provient toujours de la session ; les paramètres injectés (account_id, id…) sont ignorés.✅ tient
Mass-assignmentChamp privilégié injecté dans une mise à jour de profil → ignoré, aucune élévation.✅ tient
Injection SQLRequêtes préparées partout ; scanners et tests manuels négatifs.✅ tient
Modération coordonnée (pack-voting)3 votes négatifs coordonnés → neutralisés en temps réel, réputation restaurée, aucun bannissement injuste, vote légitime conservé.✅ tient
Exposition de fichiersAucune fuite : les accès à .git, .env, base, sauvegardes renvoient la page d'accueil (contrôleur frontal), vérifié par le contenu.✅ tient
Surface réseauSeuls 3 ports publics ; bases de données en écoute locale uniquement.✅ tient
SSHVersion récente, aucun algorithme faible, authentification par clé.✅ tient
Élévation de privilègesAucun chemin vers la racine : mot de passe requis, sudoers illisible, aucun secret world-readable. Racine non conquise.✅ tient
En-têtes HTTPHSTS, CSP, anti-clickjacking, anti-sniffing sur tous les modules ; bannière serveur masquée.✅ tient

Le cœur cryptographique de MySelf résiste à un attaquant authentifié disposant du code source.

3. Ce que nous avons trouvé — et corrigé

Vue d'ensemble. Chaque ligne a été re-testée après remédiation.

#SévéritéFindingRe-test
R9-01aincluse §4Énumération séquentielle des dossiers de récupération✅ fermé
R9-01bÉLEVÉEChaîne de prise de compte via la récupération assistée (voir §4)✅ fermé
R9-02MoyenneExposition publique du sel de dérivation des clés✅ fermé
R9-03MoyenneDurcissement PHP incomplet (fonctions dangereuses non désactivées)✅ fermé
R9-04MoyenneDéfenses réseau aveugles aux sources internes (voir §5)✅ fermé
R9-05FaibleJeton d'administration par défaut codé en dur (repli)✅ fermé
R9-06InfoAlgorithme de hachage non uniforme entre modules✅ fermé

Correctifs en bref :

4. Étude de cas — la chaîne de prise de compte (R9-01)

C'est le cas le plus instructif, car il illustre un correctif partiel qui révèle un problème plus profond, puis sa fermeture en couches.

4.1 Le finding initial

La consultation d'un dossier de récupération de niveau 3 se faisait sans autorisation : le numéro de dossier était séquentiel et énumérable. Un visiteur anonyme pouvait parcourir les dossiers et lire les conversations de preuve d'identité. (Un marqueur déposé dans une conversation a été exfiltré en une requête.)

4.2 Le premier correctif — et son angle mort

La correction a rendu le numéro non devinable (jeton aléatoire) + anti-bruteforce. L'énumération était bien morte. Mais le re-test a montré que ça ne suffisait pas :

→ Enchaînés : identifiant connu → numéro → lecture de la conversation → récupération du mot de passe régénéré dès l'accord = prise de compte. Le finding a été réévalué à la hausse (ÉLEVÉE).

4.3 Le correctif en profondeur (re-validé)

Quatre verrous, sans casser la contrainte structurelle « en récupération assistée, le propriétaire n'a plus de session » :

Re-test après correctif — chaîne rejouée de bout en bout :

Étape de l'attaqueRésultat
Ouvrir un dossier avec l'identifiant d'autrui« déjà ouvert », aucun numéro divulgué
Lire la conversation sans le sésamerefusé (403)
Lire via une URL (query-string)neutralisé (POST uniquement)
Re-définir le secret sans accord administrateurrefusé
Rejouer la chaîne avec le seul identifiantaucun accès, aucun secret

Chaîne brisée à chaque maillon. Le propriétaire légitime, lui, conserve son parcours.

5. Étude de cas — défenses réseau et angle mort interne (R9-04)

Le banc utilise un IDS comportemental + pare-feu. Le finding : par défaut, l'IDS exemptait les plages d'adresses privées — autrement dit, aucune protection contre un poste interne malveillant (mouvement latéral). Le pipeline fonctionnait (100 % des journaux analysés), mais toutes les requêtes d'attaque internes étaient « whitelistées ».

Correctif : retrait de l'exemption globale des plages privées, remplacée par une liste explicite de postes de confiance.

Re-test après correctif (preuve en conditions réelles) :

État nominal       : HTTP 200 · SSH OK
Rafale d'attaque   : depuis un poste interne non listé
→ premier blocage  : ~6 secondes
État final         : HTTP en timeout · SSH coupé · ICMP sans réponse
                     (l'adresse entière est droppée au niveau pare-feu)

✅ Un attaquant interne est désormais détecté et bloqué.

6. Limites assumées (honnêteté)

7. Invitation aux équipes de sécurité

Ce cycle montre notre posture : surface minimale, cœur cryptographique qui tient, et un processus trouver → corriger → re-valider documenté et daté. Les marqueurs « à défendre » (mémo de bout en bout, secrets de récupération, racine du serveur) n'ont pas été sortis.

Si vous êtes une équipe red team et souhaitez éprouver MySelf en conditions réelles, c'est exactement ce que nous recherchons. Les éléments protégés ci-dessus sont des défis ouverts.