SP Drive — modèle de menaces
Portée : l'application telle que déployée sur un nœud MacLustr derrière la passerelle (Caddy + WireGuard). Chaque
ligne renvoie au test qui prouve la défense (services/api/test/…) ou la marque « non testé ».
Actifs
Contenu des fichiers ; métadonnées (noms, arborescence, déposants) ; clé maîtresse ; sessions ; jetons de liens et de portails ; disponibilité (disque, CPU du nœud).
Acteurs
| Acteur | Capacités |
|---|---|
| Anonyme sur Internet | Atteint toutes les routes publiques, peut deviner des jetons, envoyer des fichiers à un portail dont il a le lien |
| Détenteur d'un lien de partage | Lit ce que le lien couvre, tant qu'il est valide |
| Déposant d'un portail | Envoie des fichiers ; aucun droit de lecture |
| Utilisateur authentifié | Tout sur son propre espace ; rien sur celui des autres |
| Fichier hostile | Contenu conçu pour attaquer un convertisseur, l'antivirus, le navigateur d'un lecteur |
| Attaquant ayant une copie du disque ou d'une sauvegarde | Lit les fichiers bruts du nœud |
Hors portée : un attaquant root sur le nœud en fonctionnement (il a la clé maîtresse en mémoire) ; la compromission de la passerelle TLS ; le poste du propriétaire.
Menaces et parades
| # | Menace | Parade | Preuve |
|---|---|---|---|
| 1 | IDOR : lire ou modifier l'élément d'un autre compte par son identifiant | Chaque requête filtre par owner_id de la session ; 404 indistinct |
files.test « isolation between accounts » (32 routes × compte tiers × anonyme) |
| 2 | Sortir d'un dossier partagé (identifiant d'un parent, d'un fichier voisin, ZIP) | Vérification serveur « descendant vivant du dossier partagé » à chaque accès | shares.test « confines a folder link » |
| 3 | Lien révoqué ou expiré encore utilisable | Le partage est relu en base à chaque requête ; le cookie d'accès ne remplace jamais ce contrôle | shares.test « revocation is immediate », « expires » |
| 4 | Dépassement des compteurs par requêtes simultanées | Incrément et test de limite dans une seule instruction SQL | shares.test « counts views and downloads atomically » |
| 5 | Deviner un jeton ou un mot de passe de lien | Jetons 256 bits hachés ; scrypt ; verrou après 20 échecs / 15 min par lien ; limite par adresse | shares.test, requests.test « stops guessing » |
| 6 | Fuite de jetons par les journaux ou le Referer | URL publiques expurgées avant journalisation ; Referrer-Policy: no-referrer ; aucun jeton en base |
shares.test « stores only a hash », « does not log tokens » |
| 7 | Déposant qui liste, lit, remplace ou supprime | Jeton de soumission limité à ses propres envois et à son état ; placement par renommage, jamais par écrasement | requests.test « a depositor can never… » |
| 8 | Fichier malveillant déposé | Quarantaine → signature → ClamAV → placement ; exécutables et scripts toujours refusés ; échec fermé si l'antivirus est arrêté | requests.test « quarantines, scans… », « keeps deposits in quarantine… » |
| 9 | Portail utilisé après expiration, pause ou révocation, y compris transfert en cours | Politique réévaluée à chaque bloc et à la finalisation | requests.test « applies expiry, pause and revocation… » |
| 10 | Saturation du disque par dépôts anonymes | Tailles déclarées et réservées à l'admission ; plafonds par fichier, par dépôt, par portail, par heure et par adresse ; quota du propriétaire ; ménage des dépôts abandonnés | requests.test « enforces every limit », « rotates, deletes and cleans up » |
| 11 | Noms de fichiers dangereux (traversée, caractères de contrôle, noms réservés, RTL) | sanitizeName unique ; les noms ne deviennent jamais des chemins disque (objets adressés par UUID) |
names.test, requests.test « neutralises dangerous file names » |
| 12 | XSS par contenu de fichier (SVG, HTML, Markdown) | Tout contenu utilisateur servi avec Content-Security-Policy: sandbox, nosniff, pièce jointe hors types sûrs ; SVG en <img> ; Markdown assaini |
En-têtes : files.test ; exécution dans le navigateur : tests/e2e/preview.spec.ts |
| 13 | CSRF | SameSite=Lax + en-tête X-SPD-CSRF obligatoire + contrôle d'origine ; aucun CORS |
auth.test « requires the CSRF header and origin » |
| 14 | Vol ou rejeu de session | Jeton haché en base, cookie __Host- HttpOnly Secure, rotation quotidienne, révocation par appareil |
auth.test « rotates the session token », « lists and revokes sessions » |
| 15 | Hameçonnage de passkey, rejeu de défi | Origine et RP ID vérifiés ; défis à usage unique | auth.test « refuses a forged origin, a replayed challenge… » |
| 16 | Prise de contrôle par la récupération | Codes à usage unique, TOTP exigé si activé, verrou par compte, session limitée à l'enrôlement, notification | auth.test (4 tests de récupération) |
| 17 | Convertisseur compromis par un document | sandbox-exec : pas de réseau, pas d'accès au dossier personnel, à la clé, aux objets ni au socket PostgreSQL ; écriture limitée au dossier du travail ; délai et limite CPU |
previews.test « runs converters without network… » |
| 18 | Bombe de décompression | Contrôle du répertoire central avant ouverture ; inventaire sans extraction avec plafonds | previews.test « refuses archive bombs » |
| 19 | SSRF | Le serveur n'effectue aucune requête vers une adresse fournie par un utilisateur ; convertisseurs sans réseau | Par construction + test 17 |
| 20 | Injection SQL | Requêtes paramétrées uniquement ; motifs LIKE échappés |
files.test « searches… » |
| 21 | Vol du disque ou d'une sauvegarde | Objets et aperçus chiffrés (AES-256-GCM par blocs), dump chiffré ; clé maîtresse hors sauvegarde | files.test « never writes plaintext », previews.test |
| 22 | Altération d'un objet stocké | Authentification par bloc liée à la position et à la taille | files.test « detects tampering » |
| 23 | Déduplication comme canal d'information entre comptes | Déduplication limitée au propriétaire | files.test « deduplicates within the account only » |
Risques résiduels acceptés ou à traiter
- Fichiers temporaires en clair (téléversements en cours, quarantaine, conversions) sur le SSD du nœud, FileVault désactivé pour le redémarrage automatique : fenêtre courte, dossiers en mode 700. Accepté pour la V1.
- Lien en lecture seule : empêche le téléchargement de l'original, pas la copie de ce qui est affiché.
- Limite mémoire des convertisseurs : macOS n'offre pas de plafond RAM fiable par processus ; parade partielle par tailles maximales, délai, limite CPU et redémarrage PM2 du worker.
- Un seul nœud : la panne du SSD interrompt le service jusqu'à restauration ; la copie hors nœud est configurable
(
SPD_BACKUP_REMOTE) mais la destination est une décision du propriétaire. - Journaux d'accès de la passerelle (Caddy sur BHS64) : hors de ce dépôt ; s'ils sont activés, ils contiennent les URL publiques avec jeton. À vérifier côté passerelle.
- Fichiers > 4 000 Mo du propriétaire : non analysés par l'antivirus (marqués comme tels).