🔐 Architecture de sécurité
Transparence assumée. Cette page documente nos défenses
et leurs limites.
Pas de sécurité par l'obscurité : une red team mérite de savoir ce qu'elle attaque. Tout le code est
sous licence
AGPL-3.0. Pour le cadre du test, voir les
règles d'engagement ;
pour les démonstrations, l'
Attack Simulator.
1. Authentification — SelfRecover sans email
- Aucun email, aucun n° de téléphone. À l'inscription : mot de récupération choisi →
password (16 car.) + passphrase diceware EFF générés côté serveur.
- Stockage :
bcrypt(password), bcrypt(passphrase), bcrypt(clé_dérivée) — coût 12. Aucun secret en clair.
- Dérivation par domaine :
HMAC-SHA256(secret, domaine ‖ sel_du_site) → un secret hameçonné sur un autre domaine ne produit pas la bonne clé.
- Rate-limit progressif (5 échecs / 15 min) + limite d'inscription par IP (anti-énumération, anti-spam).
2. Chiffrement des données — deux modèles selon la sensibilité
a) Blind-key serveur (profil : bio, localisation, lien) — AES-256-GCM, clé dérivée d'un secret serveur stocké hors base et hors webroot. Un dump SQL ne révèle que des blobs.
b) Bout-en-bout côté client (mémo perso) — chiffré dans le navigateur (WebCrypto). PBKDF2 (600k) → HKDF par étiquette → une vault_key aléatoire chiffre le mémo, wrappée dans deux enveloppes (mot de passe + passphrase de secours). Le serveur ne détient aucune clé.
✅ Ce que ça protège
- Blind-key : vol de disque, dump SQL, injection
- E2E : même un accès admin ou root sur le serveur → le mémo reste illisible
⛔ Ce que ça ne protège pas (V1, assumé)
- Blind-key : un admin / un RCE qui lit la clé peut déchiffrer le profil & les DM
- E2E : un serveur compromis persistant servant un JS piégé captant le mot de passe au déverrouillage (faille du « code servi »)
3. Le socle commun — mapping SelfRecover ⇄ SelfDataGuard
- Un seul secret racine mémorisé, une primitive de dérivation partagée, des clés filles séparées par étiquette (
auth / data-enc / data-recover).
- Règle d'or : jamais la même clé pour l'authentification et le chiffrement (le serveur voit l'auth, il ne doit jamais pouvoir déchiffrer).
- Récupération unifiée : le même mot/passphrase de secours rend l'accès et les données. La force du secours = entropie de l'entrée (passphrase diceware), pas la taille du hash.
4. Durcissement applicatif
- CSRF : jeton HMAC lié à la session, vérifié sur chaque action d'écriture (en-tête
X-CSRF-Token).
- En-têtes :
Content-Security-Policy, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy, HSTS.
- Sessions : jeton aléatoire 192 bits, cookie
HttpOnly/SameSite=Lax, TTL 24 h + purge.
- Anti-énumération : messages d'erreur non discriminants, limite par IP.
5. Modération — SelfModerate anti-manipulation
- Réputation par membre (départ 20/30), vote ±1 sur les messages et les membres.
- Anti-Sybil : un compte de moins de 24 h sans contribution ne peut pas voter.
- Anti pack-voting : 3+ votes négatifs coordonnés en moins de 60 s → annulés, réputation restaurée.
- Anti upvote-farming : votes mutuels répétés neutralisés. Sanctions graduées (perte du vote, bannissement 24 h → 7 j → 30 j → permanent).
6. Modèle de menace — honnête
✅ Neutralisé
- Exfiltration de la base (dump, disque volé) — blobs
- Bruteforce de mot de passe (rate-limit)
- Manipulation de la modération (Sybil, pack-voting)
- CSRF, clickjacking, vol de session passif
- Vol du mémo, même avec un accès root (E2E au repos)
⚠️ Limites connues (V1)
- Profil & DM lisibles par un admin / un RCE (blind-key)
- Serveur compromis persistant → altération du code servi (« code servi »)
- Métadonnées non chiffrées (qui parle à qui, quand)
7. Feuille de route (hors V1)
E2E étendu aux messages privés et au profil · Argon2id en remplacement de PBKDF2 · superviseur d'intégrité externe (détection du code servi altéré + comportement anormal, confinement automatique réversible) · quorum distribué (Shamir) pour les clés critiques.