
# Sécurité des téléversements

Le téléversement de fichiers est le point faible classique d'une application de données : il accepte des octets choisis par l'attaquant, un nom choisi par l'attaquant et un type de contenu choisi par l'attaquant, puis restitue les trois à un navigateur. La réponse de Sovrium est que chacun des trois est validé côté serveur, dans un ordre fixe, avant toute écriture.

## Avant tout stockage

La validation s'exécute dans cette séquence. Chaque étape est totale — rien n'est « assaini puis accepté ».

| Étape | Vérification                                                              | Rejet |
| ----- | ------------------------------------------------------------------------- | ----- |
| 1     | Le nom de fichier contient `..`, `/` ou `\` — traversée de chemin.        | `400` |
| 2     | Le nom de fichier contient un octet nul.                                  | `400` |
| 3     | La taille dépasse le `maxFileSize` du bucket, ou `STORAGE_MAX_FILE_SIZE`. | `413` |
| 4     | Le type MIME n'est pas dans le `allowedMimeTypes` du bucket.              | `400` |
| 5     | Le bucket est privé et la requête n'a pas de session.                     | `401` |
| 6     | Stocker le fichier ferait dépasser `STORAGE_MAX_TOTAL_SIZE`.              | `507` |

Les étapes 1 à 4 s'exécutent **avant** la vérification d'authentification. Cet ordre est intentionnel : un téléversement trop lourd ou malformé est rejeté sur ses propres mérites, si bien qu'un client non authentifié ne peut pas se servir de la frontière d'authentification pour apprendre si sa charge utile aurait autrement été acceptée.

Un champ `path` explicite suit un jeu de règles légèrement différent — `/` est autorisé, puisque les préfixes de chemin en sont tout l'objet, mais un `/` initial, une valeur vide, `..`, `\` et les octets nuls sont tous rejetés.

## Listes MIME autorisées

`allowedMimeTypes` est la déclaration du bucket sur ce qui a le droit d'y figurer. Les entrées correspondent exactement, ou par joker de préfixe `type/*` :

```yaml
buckets:
  - name: avatars
    allowedMimeTypes: [image/*] # image/png ✓  image/svg+xml ✓  application/pdf ✗

  - name: invoices
    allowedMimeTypes: [application/pdf] # correspondance exacte uniquement
```

Omettre la propriété accepte tout. C'est acceptable pour un bucket interne et imprudent pour un bucket où tout utilisateur authentifié peut écrire — une liste d'autorisation est le contrôle le moins coûteux de cette page, et le seul qui exprime une intention plutôt que de simplement bloquer une attaque.

:::callout
**Le type MIME est une affirmation du client, pas un fait.** Il provient de l'en-tête de la partie multipart du navigateur, et rien ne le redéduit des octets. Une liste `.pdf` arrête un téléversement accidentel et un attaquant paresseux ; elle n'arrête pas un attaquant déterminé qui étiquette des octets arbitraires en `application/pdf`. Associez la liste aux en-têtes de réponse ci-dessous : ce sont eux qui neutralisent réellement un fichier mal étiqueté.
:::

## Ce que porte un fichier servi

Les téléchargements — directs ou via une [URL signée](/fr/docs/signed-urls) — sont servis avec trois en-têtes dont le rôle combiné est de rendre inerte un fichier stocké dans un navigateur :

| En-tête                   | Valeur                                       | Pourquoi                                                             |
| ------------------------- | -------------------------------------------- | -------------------------------------------------------------------- |
| `X-Content-Type-Options`  | `nosniff`                                    | Empêche le navigateur de redeviner le type et d'exécuter les octets. |
| `Content-Security-Policy` | `default-src 'none'`                         | Même rendu, aucun script, style ni accès réseau n'est autorisé.      |
| `Content-Disposition`     | `attachment` (ou `inline` — voir ci-dessous) | Télécharge plutôt que d'afficher, là où cela compte.                 |

`Content-Disposition` est celui qui demande de la nuance. Seules les images **matricielles** — PNG, JPEG, GIF, WebP — sont un jour servies en `inline`, et uniquement via la route de téléchargement signé où l'affichage direct est justement l'objectif. Tout le reste est forcé en `attachment`, et `image/svg+xml` est explicitement exclu de l'ensemble « inline » : un SVG est un document qui peut porter du `<script>`, donc le servir en ligne sur votre propre origine, c'est du XSS stocké. Les noms de fichiers non ASCII sont émis en RFC 5987 `filename*=UTF-8''…` afin qu'un en-tête ne casse jamais sur un nom multi-octets.

## Ce qui n'est pas couvert

Deux choses que la plateforme ne fera pas à votre place :

- **Aucune analyse antivirus.** Les octets sont stockés tels qu'ils arrivent. Si votre modèle de menace inclut la diffusion de logiciels malveillants, placez un analyseur devant le point de terminaison ou derrière une [automatisation](/fr/docs/automations-overview).
- **Aucune détection de type par le contenu.** Voir l'encadré ci-dessus — les types déclarés sont crus pour la décision d'autorisation.

## Pages associées

- [Opérations sur les fichiers](/fr/docs/file-operations) — les points de terminaison protégés par ces règles.
- [Permissions de bucket](/fr/docs/buckets-permissions) — qui peut les atteindre en premier lieu.
- [Cycle de vie et quotas](/fr/docs/file-lifecycle) — les plafonds de taille évoqués ci-dessus.
- [URL signées](/fr/docs/signed-urls) — l'accès sans session, et ses propres en-têtes.
- [Présentation des buckets](/fr/docs/buckets-overview) — où `allowedMimeTypes` est déclaré.
