Aller au contenu

PD-38 — Retour d'expérience (REX)


📚 Navigation User Story | Document | | | ---------- | -- | | 📋 [Spécification](PD-38-specification.md) | | | 🛠️ [Plan d'implémentation](PD-38-plan.md) | | | ✅ [Critères d'acceptation](PD-38-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

Élément Valeur
Objectif initial Implémenter le calcul d'empreinte SHA3-256 sur documents chiffrés pour garantir leur intégrité probatoire
Résultat obtenu Fonctionnalité complète après correction des 3 écarts identifiés
Verdict d'acceptabilité ✅ ACCEPTÉ (2026-01-05)
Tests contractuels 4 suites, 113 tests PASS

L'implémentation initiale présentait un écart bloquant majeur : le hash était fourni par le client au lieu d'être calculé côté serveur sur le fichier chiffré stocké sur S3. Après correction, la garantie probatoire est assurée.


2. Points fluides

  • Spécification claire : Les exigences cryptographiques (SHA3-256, NIST FIPS 202) étaient bien définies.
  • Bibliothèques matures : js-sha3 et node:crypto ont fourni les primitives nécessaires sans difficulté.
  • Architecture modulaire : La séparation HashService / HashStreamService permet une réutilisation aisée.
  • Tests vectoriels : Les vecteurs NIST ont permis une validation cryptographique fiable.
  • Streaming natif : Le support des fichiers volumineux via streaming était déjà prévu dans le plan.

3. Points difficiles

  • Calcul hash côté serveur vs client : L'implémentation initiale passait le hash fourni par le client, ce qui cassait la garantie probatoire. Cette erreur n'a été détectée qu'en revue d'acceptabilité.
  • Dépendances inter-modules : La correction E-01 a nécessité l'import de UploadModule dans DocumentsModule pour accéder à HashStreamService et S3MultipartAdapter.
  • Mocks de tests : L'ajout des dépendances S3 a imposé la mise à jour de tous les mocks dans les tests du service et du controller.
  • Comparaison constant-time : L'utilisation de === pour comparer les hashes n'a pas été immédiatement identifiée comme un problème de sécurité.

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

Hypothèse Impact
Le hash devait être calculé côté backend L'implémentation initiale supposait que le client pouvait fournir le hash, ce qui contredisait l'objectif probatoire
L'endpoint /documents/:id/hash était nécessaire Non explicité initialement comme endpoint dédié, mais requis pour la restitution au client
La comparaison des hashes devait être constant-time Mentionné dans le plan mais non vérifié lors de l'implémentation
Le fichier doit être récupéré depuis S3 pour calcul Le flux d'upload stocke d'abord sur S3, le hash est calculé a posteriori

5. Invariants complexes

Invariant Complexité Référence
Hash calculé sur ciphertext uniquement Moyenne Nécessite accès au fichier S3 après upload, pas au flux client direct
Unicité hash par utilisateur Faible Contrainte SQL + vérification RLS avant insertion
Hash jamais en clair dans logs Faible Validation par revue de code
Fichier vide = rejet systématique Faible Validation en entrée de HashService

6. Dette technique

Dette Impact Priorité
Pas de tests d'intégration E2E avec S3 réel Les mocks simulent S3, un test avec MinIO serait plus robuste Basse
hashFile() deprecated mais non supprimé Alias conservé pour compatibilité, à supprimer dans une prochaine version Basse
Absence de métriques de performance Pas de mesure du temps de calcul sur gros fichiers en production Basse

7. Risques résiduels

Risque Probabilité Impact Mitigation
Performance sur fichiers > 1GB Faible Moyen Streaming implémenté, à valider en charge
Erreur S3 pendant calcul hash Faible Moyen L'opération échoue proprement, fichier déjà uploadé reste sur S3
Collision SHA3-256 Négligeable Critique Probabilité 2^-128, acceptable pour usage probatoire
Timing attack sur verify() Très faible Faible Mitigé par timingSafeEqual

8. Améliorations de processus

Amélioration Bénéfice attendu
Revue d'acceptabilité dès la fin du dev Détection précoce des écarts bloquants comme E-01
Checklist "source de confiance" Vérifier systématiquement que les données critiques (hash, signatures) sont calculées côté serveur
Tests de sécurité automatisés Intégrer des vérifications constant-time dans le linter ou les tests
Template de test hash Fournir des vecteurs NIST pré-intégrés pour toute US cryptographique

9. Enseignements clés

  1. Le hash probatoire DOIT être calculé côté serveur : Toute donnée ayant valeur probatoire ne peut jamais être fournie par le client sans revalidation.

  2. Les dépendances inter-modules doivent être anticipées : L'accès à S3 depuis le module Documents a nécessité un refactoring des imports et exports.

  3. La sécurité des comparaisons cryptographiques n'est pas intuitive : L'utilisation de === sur des hashes semble correcte mais expose à des timing attacks.

  4. La revue d'acceptabilité est un filet de sécurité essentiel : Sans cette revue, l'écart E-01 aurait pu passer en production, compromettant la valeur probatoire.

  5. Les tests unitaires ne suffisent pas à valider l'architecture : Les tests passaient avec le hash client, seule l'analyse du flux métier a révélé le problème.


Annexes

Commits de référence

Commit Description
4cd7be7 Fix E-01/E-02/E-03 : calcul hash côté serveur, endpoint dédié, constant-time
761ef85 Fix Prettier formatting

Fichiers modifiés

Fichier Modification
src/modules/crypto/hash.service.ts Ajout timingSafeEqual dans verify()
src/modules/documents/services/document-secure.service.ts Calcul hash depuis S3 via HashStreamService
src/modules/documents/documents.controller.ts Ajout endpoint GET /documents/:id/hash
src/modules/documents/dto/create-document-secure-request.dto.ts Suppression fileHash du DTO client
src/modules/documents/documents.module.ts Import UploadModule
src/modules/upload/upload.module.ts Export S3MultipartAdapter