Aller au contenu

PD-38 — Rétrospective

1. Contexte

Champ Valeur
Story ID PD-38
Titre Empreinte SHA3-256 documents chiffrés
Domaine crypto-proof
Projet backend
Date complétion 2026-01-05
Verdict ACCEPTÉ

2. Métriques

Métrique Valeur
Tests contractuels 4 suites, 113 tests PASS
Écarts identifiés 3 (E-01, E-02, E-03)
Écarts résolus 3/3

3. Learnings clés

  • Hash probatoire DOIT être calculé côté serveur : Toute donnée ayant valeur probatoire ne peut jamais être fournie par le client sans revalidation. L'implémentation initiale acceptait le hash client, cassant la garantie probatoire.

  • Dépendances inter-modules à anticiper : L'accès à S3 depuis DocumentsModule a nécessité l'import de UploadModule et la mise à jour de tous les mocks.

  • Comparaison constant-time non intuitive : L'utilisation de === sur des hashes semble correcte mais expose à des timing attacks. crypto.timingSafeEqual() est obligatoire.

  • Tests unitaires ne valident pas l'architecture : Les tests passaient avec le hash client. Seule l'analyse du flux métier a révélé le problème E-01.

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

4. Patterns applicables

Pattern existant : Streaming pour fichiers volumineux

async hashStream(stream: Readable): Promise<string> {
  const hash = crypto.createHash('sha3-256');
  for await (const chunk of stream) {
    hash.update(chunk);
  }
  return hash.digest('hex');
}

Nouveau pattern : Source de confiance côté serveur

Pour toute donnée probatoire : 1. Ne JAMAIS accepter de valeur fournie par le client 2. Calculer la valeur depuis la source de confiance (S3, DB, HSM) 3. Retourner la valeur calculée au client via endpoint dédié

// CORRECT : calcul depuis S3, pas depuis le body client
async getDocumentHash(docId: string): Promise<string> {
  const stream = await this.s3.getObjectStream(docId);
  return this.hashService.hashStream(stream);
}

Nouveau pattern : Comparaison timing-safe

verify(expected: string, actual: string): boolean {
  const expectedBuf = Buffer.from(expected, 'hex');
  const actualBuf = Buffer.from(actual, 'hex');
  if (expectedBuf.length !== actualBuf.length) return false;
  return crypto.timingSafeEqual(expectedBuf, actualBuf);
}

5. Signal CLAUDE.md

Priorité haute : Checklist "source de confiance".

### Source de Confiance — Données probatoires (2026-02-XX)

Pour toute donnée ayant valeur probatoire (hash, signature, timestamp) :

**Interdit** :
- Accepter la valeur fournie par le client
- Calculer sur le flux client avant stockage

**Obligatoire** :
- Calculer depuis la source de confiance (S3, DB, HSM)
- Exposer via endpoint dédié (`GET /documents/:id/hash`)
- Utiliser `crypto.timingSafeEqual()` pour comparaisons

6. Conclusion

PD-38 a livré le calcul d'empreinte SHA3-256 sur documents chiffrés après correction de l'écart bloquant E-01 (hash client → hash serveur). Les patterns "source de confiance côté serveur" et "comparaison timing-safe" sont désormais obligatoires pour toute donnée probatoire.


Rétrospective générée 2026-02-19 (Étape 10 batch crypto-proof)