PD-251 — Revue Sécurité
Résumé
| Critère | Statut |
| Forbidden patterns | ❌ |
| Injection SQL | ✅ |
| Auth/Authz | ❌ |
| Fuite données | ❌ |
| Validation | ⚠️ |
Verdict : ❌ NON_CONFORME
Raison principale : plusieurs vecteurs d'attaque applicatifs reproductibles (IDOR/absence d'authorization fine, absence de rate limiting sur opérations critiques, contrôle append-only DB non démontré par migration, et transition d'état non journalisée de manière strictement préalable).
Barrières primaires identifiées
| Barrière | Composant | Atténuation |
| HSM PKCS#11 (signature) | IntegrityJournalService, ForensicSnapshotServiceImpl, IncidentReportService | Limite la falsification cryptographique des preuves lorsque HSM disponible |
| Requêtes SQL paramétrées | DataSource.query(..., [params]) dans guards/services/processors | Réduit fortement le risque d'injection SQL sur entrées utilisateur |
| Verrou distribué Redis (SET NX PX) | PeriodicRunProcessor, ReconciliationProcessor | Empêche l'exécution concurrente du même type d'opération |
| Guard JWT global controller | IntegrityController (@UseGuards(JwtAuthGuard)) | Exige une authentification avant accès aux endpoints integrity |
Note defense-in-depth : ces barrières n'atténuent pas l'absence de contrôle d'autorisation objet (ownership/tenant) sur les endpoints de lecture d'incident, ni l'absence de limitation de débit sur déclenchements manuels.
Audit des forbidden patterns
| Pattern interdit | Recherché | Trouvé |
| Ajouter un état enum hors machine | ArchiveIntegrityState + ALLOWED_TRANSITIONS | ✅ (non trouvé) |
Schéma hors vault_integrity (entités PD-251) | @Entity(... schema: 'vault_integrity') | ✅ (non trouvé) |
Math.random() pour identifiants | Recherche usages ID | ✅ (non trouvé) |
| Transition sortante depuis état terminal | ArchiveStateMachineService.transition | ✅ (bloqué) |
| UPDATE/DELETE journal applicatif | services/repositories | ✅ (non trouvé dans code applicatif) |
| Trigger append-only journal effectivement déployé | migration 1740800000000-PD-251-CreateIntegritySchema.ts | ❌ (fichier vide, garantie DB non démontrée) |
| Transition sans journal préalable | ArchiveStateMachineService.transition | ❌ (journal écrit post-commit) |
Tentatives de bypass
| Attaque | Résultat | Commentaire |
Injection SQL via archiveId="'; DROP TABLE--" sur endpoints UUID | Bloqué | ParseUUIDPipe stoppe l'entrée, et SQL paramétré côté query |
Bypass auth sans JWT sur /integrity/* | Bloqué | JwtAuthGuard au niveau contrôleur |
| Accès incident d'une archive tierce avec JWT valide d'un autre user | Réussi | Aucun contrôle ownership/tenant explicite dans getIncidents/getLatestReport |
DoS logique via spam POST /integrity/runs | Réussi partiellement | Lock Redis évite concurrence d'exécution, mais pas flood de soumissions; pas de ThrottlerGuard |
| Tampering journal par UPDATE/DELETE SQL | Potentiellement possible | Trigger append-only requis par contrat mais migration fournie est vide |
Vulnérabilités identifiées
| ID | Description | Gravité | Fichier |
| S-01 | IDOR / Broken Object Authorization: tout utilisateur authentifié peut lire incidents/snapshots/tentatives d'une archive arbitraire via UUID (GET /integrity/archives/:archiveId/incidents, GET /integrity/archives/:archiveId/latest-report). Aucun check owner/tenant/rôle sur ces endpoints. | MAJEUR | src/modules/integrity/controllers/integrity.controller.ts |
| S-02 | Action sensible sans autorisation forte: POST /integrity/runs accessible à tout JWT authentifié, sans rôle ops/admin ni scope dédié. Permet déclenchement d'opérations lourdes et création de bruit d'audit. | MAJEUR | src/modules/integrity/controllers/integrity.controller.ts |
| S-03 | Absence de rate limiting sur opérations critiques (contrat SEC-02): aucun ThrottlerGuard visible sur POST /integrity/runs (et aucun endpoint restore/reconciliation côté API montré avec throttling). Attaque: flood de requêtes authentifiées => saturation BullMQ/Redis/DB. | MAJEUR | src/modules/integrity/controllers/integrity.controller.ts, src/modules/integrity/integrity.module.ts |
| S-04 | Contrôle append-only DB non prouvé/déployé: migration de création du schéma intégrité vide. Sans trigger SQL anti UPDATE/DELETE sur integrity_journal_entries, l'invariant d'immutabilité probatoire peut être contourné si compte DB compromis. | MAJEUR | src/database/migrations/1740800000000-PD-251-CreateIntegritySchema.ts |
| S-05 | Violation contractuelle de séquencement journal/transition: transition d'état committée puis journalisation ensuite. Si échec journal (panne DB partielle, quota, table lock), transition sans trace append-only signée. | MAJEUR | src/modules/integrity/services/archive-state-machine.service.ts |
| S-06 | Exposition de données de preuve à large périmètre: endpoint incidents retourne expectedHashSha3, observedHashSha3, références d'artefacts et historique de restauration sans filtrage de rôle. Augmente surface d'énumération et intelligence d'attaque. | RESERVE | src/modules/integrity/controllers/integrity.controller.ts, src/modules/integrity/dto/incident-response.dto.ts |
| S-07 | Validation incomplète des bornes runtime: validateRunParams() ne borne pas timeoutSeconds contrairement au contrat global de bornes. Risque de run excessif si branché sur overrides API futurs. | MINEUR | src/modules/integrity/services/integrity-config-validator.service.ts |
Détails d'exploitation (vecteurs concrets)
- S-01 (IDOR):
- Précondition: JWT valide utilisateur A.
- Payload:
GET /integrity/archives/<uuid_archive_B>/incidents. - Impact: lecture de métadonnées d'incident d'un autre propriétaire (état, hashes de preuve, snapshots, tentatives).
- S-02/S-03 (abuse opérationnel):
- Précondition: JWT valide non privilégié.
- Payload: rafale
POST /integrity/runs (ex. 200 req/min). - Impact: files de jobs gonflées, contention Redis/DB, dégradation service; lock Redis empêche concurrence d'exécution, mais pas la pression de soumission.
- S-04 (tampering journal):
- Précondition: accès SQL applicatif compromis ou insider DB.
- Payload:
UPDATE vault_integrity.integrity_journal_entries SET payload='{}' ... / DELETE .... - Impact: altération effaçable de la traçabilité probatoire si triggers absents en base.
Recommandations
- Mettre un contrôle d'autorisation objet strict sur endpoints incidents/reports (owner match via RLS effective ou vérification explicite
archive.owner_id == user.sub; rôle investigateur/admin pour consultation transverse). - Restreindre
POST /integrity/runs à rôle dédié (INTEGRITY_INVESTIGATOR/ADMIN ou rôle ops distinct) et journaliser refus d'accès. - Ajouter rate limiting (
ThrottlerGuard) sur endpoints critiques selon contrat (scope userId+IP, bornes opsRateLimit). - Implémenter la migration SQL PD-251: schéma, tables, index, triggers anti UPDATE/DELETE sur journal, et tests d'intégration PostgreSQL réels prouvant l'immutabilité.
- Rendre la transition d'état atomique avec la trace (transaction unique avec insertion journal append-only préalable/inline, ou pattern outbox probatoire avec garantie de non-perte prouvée en test crash).
- Réduire la surface de fuite des DTO incidents (masquage hashes/références pour rôles non-investigation; réponse minimale pour owner standard).