Aller au contenu

PD-24 — Retour d'expérience


📚 Navigation User Story | Document | | | ---------- | -- | | 📋 [Spécification](PD-24-specification.md) | | | 🛠️ [Plan d'implémentation](PD-24-plan.md) | | | ✅ [Critères d'acceptation](PD-24-acceptability.md) | | | 📝 **Retour d'expérience** | *(ce document)* | [← Retour à crypto-proof](../PD-189-epic.md) · [↑ Index User Story](index.md)

1. Résumé exécutif

La User Story PD-24 visait à implémenter la Phase 1 du protocole SRP-6a pour une authentification strictement Zero-Knowledge : génération client-side du salt/verifier à l'inscription, et initialisation du challenge SRP à la connexion. L'implémentation fournit un SrpService complet avec groupe 3072 bits (RFC 5054), SHA3-256, validations de sécurité (A mod N ≠ 0), et stockage sessions Redis avec TTL 5 minutes. Cependant, 1 écart MAJEUR est identifié : absence de rate limiting sur /auth/login/challenge malgré l'exigence de protection DoS. Verdict : ACCEPTÉ AVEC RÉSERVES.


2. Points fluides

  • Paramètres RFC 5054 : groupe 3072 bits (N, g) correctement définis avec référence explicite
  • SHA3-256 (Keccak) : utilisation de js-sha3 conforme aux specs ProbatioVault (pas SHA-256)
  • BigInt natif : calculs cryptographiques avec bigint JavaScript, évite les dépendances externes
  • Fonction modPow : exponentiation modulaire implémentée sans overflow
  • Calcul k = SHA3-256(N || PAD(g)) : padding à la taille du groupe respecté
  • Validation A mod N ≠ 0 : protection contre l'attaque A=0 implémentée
  • Validation verifier ∈ [1, N-1] : rejet des verifiers invalides à l'inscription
  • Validation salt 16-32 bytes : contrainte de taille respectée
  • Sessions Redis : SrpSessionStoreService avec TTL 5 minutes et suppression après usage
  • DTOs class-validator : RegisterDto, LoginChallengeDto avec @IsHexadecimal, @IsEmail
  • Tests unitaires : couverture des validations de format et cas limites
  • Endpoint GET /auth/srp-params : paramètres publics N, g exposés séparément
  • Architecture modulaire : SrpService + SrpSessionStoreService séparés
  • Documentation inline : commentaires JSDoc décrivant le flux Zero-Knowledge

3. Points difficiles

Difficulté Contexte
Rate limiting absent Contrainte "Limitation des tentatives" non implémentée sur /auth/login/challenge
Réponse challenge divergente TA-2 attend {salt, B, N, g} mais l'API retourne {salt, B} uniquement
Tests RFC 5054 Aucun test de conformité aux vecteurs officiels RFC 5054
Validation B mod N ≠ 0 Non testée explicitement dans les tests unitaires
Redis obligatoire Pas de fallback en mémoire, Redis requis même en dev/test

4. Hypothèses révélées tardivement

Hypothèse initiale Réalité découverte
N/g dans chaque réponse FAUX — Choix architectural : N/g via endpoint dédié /auth/srp-params, pas dans /login/challenge
Tests de conformité RFC 5054 FAUX — Tests limités aux validations de format, pas de vecteurs officiels
Stockage en mémoire pour dev FAUX — Redis obligatoire dans tous les environnements, tests utilisent ioredis-mock
Rate limiting inclus dans scope FAUX — Mentionné dans spec et plan mais non implémenté

5. Invariants complexes à implémenter

Invariant Complexité
A mod N ≠ 0 Sécurité critique, rejet immédiat si violation
B mod N ≠ 0 Génération serveur doit être régénérée si B=0 (très improbable)
u ≠ 0 Rejet si SHA3-256(A
Verifier ∈ [1, N-1] Validation à l'inscription pour éviter les cas dégénérés
Padding à GROUP_SIZE Tous les BigInt doivent être paddés à 384 bytes avant hash
Sessions usage unique Suppression obligatoire après verify pour éviter replay
TTL 5 minutes Protection contre accumulation de sessions abandonnées

6. Dette technique

Dette Impact Priorité
Rate limiting absent DoS possible sur /auth/login/challenge HAUTE
Tests RFC 5054 manquants Conformité non prouvée par tests automatisés MOYENNE
Réponse TA-2 non alignée Spec/API divergent, documentation à mettre à jour BASSE
Redis obligatoire partout Complexifie setup dev/CI sans Docker BASSE
Délai aléatoire absent Protection timing attack non implémentée MOYENNE

7. Risques résiduels

Risque Probabilité Impact Mitigation suggérée
DoS /login/challenge Moyenne ÉLEVÉ Implémenter rate limiting (throttler NestJS)
Timing attack Faible MOYEN Ajouter délai aléatoire côté serveur
Non-conformité RFC 5054 Faible ÉLEVÉ Ajouter tests avec vecteurs officiels
Session hijacking Faible MOYEN TTL strict + usage unique déjà en place
Redis down Faible ÉLEVÉ Health check + circuit breaker sur Redis

8. Améliorations processus

Amélioration Bénéfice attendu
Implémenter rate limiting dès la spec Éviter écart MAJEUR sur contraintes sécurité
Inclure vecteurs RFC dans tests Prouver conformité dès l'implémentation
Aligner spec et API avant merge Éviter divergence TA-2 vs réponse réelle
Prévoir fallback mémoire pour tests Simplifier CI sans Redis réel
Tests E2E complets Valider flux inscription → challenge → verify

9. Enseignements clés

  1. Les contraintes de sécurité doivent être testées automatiquement — L'absence de rate limiting n'a pas été détectée car non testée. Les contraintes de la spec (protection DoS, timing attack) doivent avoir des tests correspondants.

  2. SHA3-256 ≠ SHA-256 — Le choix de SHA3-256 (Keccak) est correct mais nécessite une bibliothèque dédiée (js-sha3). Les tests de conformité doivent vérifier que ce n'est pas SHA-256 par erreur.

  3. BigInt natif suffit pour SRP — Pas besoin de bibliothèques externes (bn.js, bignum) pour les calculs modulaires 3072 bits. L'implémentation de modPow avec BigInt natif est suffisante et plus simple.

  4. Redis impose des contraintes d'environnement — Le choix de Redis pour les sessions SRP est robuste (TTL automatique, scalable) mais complexifie les tests et le dev local. L'injection de ioredis-mock via setRedisClient() est un bon pattern.

  5. La divergence spec/API doit être détectée tôt — TA-2 attendait {salt, B, N, g} mais l'implémentation retourne {salt, B}. Ce choix (N/g via endpoint dédié) est valide mais aurait dû être discuté avant l'implémentation pour éviter l'écart documentaire.