SPB Git

Repository Public

threat-model.md 7.1 KB 65 lines markdown

1# SP Drive — modèle de menaces23Portée : l'application telle que déployée sur un nœud MacLustr derrière la passerelle (Caddy + WireGuard). Chaque4ligne renvoie au test qui prouve la défense (`services/api/test/…`) ou la marque « non testé ».56## Actifs78Contenu des fichiers ; métadonnées (noms, arborescence, déposants) ; clé maîtresse ; sessions ; jetons de liens et de9portails ; disponibilité (disque, CPU du nœud).1011## Acteurs1213| Acteur | Capacités |14|---|---|15| Anonyme sur Internet | Atteint toutes les routes publiques, peut deviner des jetons, envoyer des fichiers à un portail dont il a le lien |16| Détenteur d'un lien de partage | Lit ce que le lien couvre, tant qu'il est valide |17| Déposant d'un portail | Envoie des fichiers ; aucun droit de lecture |18| Utilisateur authentifié | Tout sur son propre espace ; rien sur celui des autres |19| Fichier hostile | Contenu conçu pour attaquer un convertisseur, l'antivirus, le navigateur d'un lecteur |20| Attaquant ayant une copie du disque ou d'une sauvegarde | Lit les fichiers bruts du nœud |2122Hors portée : un attaquant root sur le nœud en fonctionnement (il a la clé maîtresse en mémoire) ; la compromission23de la passerelle TLS ; le poste du propriétaire.2425## Menaces et parades2627| # | Menace | Parade | Preuve |28|---|---|---|---|29| 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) |30| 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 » |31| 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 » |32| 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 » |33| 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 » |34| 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 » |35| 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… » |36| 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… » |37| 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… » |38| 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 » |39| 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 » |40| 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` |41| 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 » |42| 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 » |43| 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… » |44| 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) |45| 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… » |46| 18 | Bombe de décompression | Contrôle du répertoire central avant ouverture ; inventaire sans extraction avec plafonds | `previews.test` « refuses archive bombs » |47| 19 | SSRF | Le serveur n'effectue aucune requête vers une adresse fournie par un utilisateur ; convertisseurs sans réseau | Par construction + test 17 |48| 20 | Injection SQL | Requêtes paramétrées uniquement ; motifs `LIKE` échappés | `files.test` « searches… » |49| 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` |50| 22 | Altération d'un objet stocké | Authentification par bloc liée à la position et à la taille | `files.test` « detects tampering » |51| 23 | Déduplication comme canal d'information entre comptes | Déduplication limitée au propriétaire | `files.test` « deduplicates within the account only » |5253## Risques résiduels acceptés ou à traiter5455- **Fichiers temporaires en clair** (téléversements en cours, quarantaine, conversions) sur le SSD du nœud, FileVault56  désactivé pour le redémarrage automatique : fenêtre courte, dossiers en mode 700. Accepté pour la V1.57- **Lien en lecture seule** : empêche le téléchargement de l'original, pas la copie de ce qui est affiché.58- **Limite mémoire des convertisseurs** : macOS n'offre pas de plafond RAM fiable par processus ; parade partielle par59  tailles maximales, délai, limite CPU et redémarrage PM2 du worker.60- **Un seul nœud** : la panne du SSD interrompt le service jusqu'à restauration ; la copie hors nœud est configurable61  (`SPD_BACKUP_REMOTE`) mais la destination est une décision du propriétaire.62- **Journaux d'accès de la passerelle** (Caddy sur BHS64) : hors de ce dépôt ; s'ils sont activés, ils contiennent les63  URL publiques avec jeton. À vérifier côté passerelle.64- **Fichiers > 4 000 Mo** du propriétaire : non analysés par l'antivirus (marqués comme tels).65
Files main
Menu

Theme