Skip to content

Securite des documents

Objectif

Le modele de securite des documents separe volontairement :

  • l'ID technique interne : documents.id, reserve aux relations base de donnees ;
  • l'identifiant public : documents.uuid, expose dans les URLs front et API ;
  • la regle d'acces : centralisee dans DocumentAccessPolicy.

Le uuid permet de retrouver une ressource, mais ne donne jamais acces au fichier a lui seul.

Flux d'acces actuel

mermaid
sequenceDiagram
    autonumber
    participant U as 👤 Utilisateur
    participant F as 🖥️ Front
    participant API as 🧠 DocumentController
    participant Guard as 🔐 AuthGuard
    participant Policy as 🛡️ DocumentAccessPolicy
    participant DB as 🗄️ prisma.tool
    participant S3 as ☁️ S3 privé

    U->>F: Ouvre /files/:documentUuid ou clique Télécharger
    F->>API: GET /documents/:uuid/access-url ou /download
    API->>Guard: Vérifie JWT + user + app/env
    API->>Policy: findReadableDocumentForUser(userId, uuid)
    Policy->>DB: uuid + users_documents.user_id
    DB-->>Policy: document autorisé
    API->>S3: Génère une URL signée temporaire
    API-->>F: url + filename

Regles implementees

UUID obligatoire

documents.uuid est un identifiant public obligatoire et unique :

prisma
model documents {
  id   Int    @id @default(autoincrement())
  uuid String @unique(map: "documents_uuid_unique")
}

La migration sql/tool_02_documents_uuid_not_null.sql :

  • backfill les documents existants sans UUID ;
  • applique DEFAULT gen_random_uuid() ;
  • applique NOT NULL.

Autorisation centralisee

DocumentAccessPolicy porte les requetes d'autorisation :

  • findReadableDocumentsForUser(userId) pour la liste ;
  • findReadableDocumentForUser(userId, documentUuid) pour l'ouverture de lien ;
  • findDownloadableDocumentForUser(userId, documentUuid) pour le telechargement.

La regle actuelle est :

ts
where: {
  uuid: documentUuid,
  users_documents: { some: { user_id: userId } },
}

Si le document n'existe pas ou n'est pas rattache a l'utilisateur, l'API repond avec une erreur generique File not found.. Le backend ne revele pas si le UUID existe chez un autre utilisateur.

Ce que le lien ne contient pas

Le lien applicatif /files/:documentUuid ne contient pas :

  • de token d'authentification ;
  • d'URL S3 pre-signee ;
  • de bucket ;
  • de chemin de stockage ;
  • d'ID numerique interne.

Roadmap securite

Les prochaines evolutions prevues sont :

  • DocumentAccessAuditService pour tracer list, download, open_link, denied ;
  • DOCUMENT_SIGNED_URL_TTL_SECONDS pour reduire/configurer la duree de vie des URLs signees ;
  • document_access_grants si un futur ticket demande un vrai partage entre plusieurs comptes.