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
UploadModuleet 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)