---
suivi: 1227
date: 2026-08-06
sujet: sécurisation dépôts — .htaccess public + MIME réel + plafond DCE
chantier: securite-depots
type: securite
statut: poussé
hash: 963e4910
fichiers:
  - storage/app/public/.htaccess
  - storage/app/public/.gitignore
  - app/Support/UploadDocumentAllowlist.php
  - app/Rules/AllowedDocumentUpload.php
  - app/Http/Controllers/GedController.php
  - app/Http/Controllers/MarcheController.php
  - app/Http/Controllers/ContactController.php
  - app/Http/Controllers/ReservationController.php
  - app/Http/Requests/Juridique/StoreDemandeJuridiqueRequest.php
  - app/Http/Requests/Juridique/StorePieceJointeDemandeJuridiqueRequest.php
  - app/Services/AoDocumentService.php
  - resources/js/Components/AppelsOffres/AoDocumentsSection.vue
  - .user.ini
  - docs/deploy/ovh-php-config.md
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - public/build/
  - docs/suivi/SUIVI_1227_securisation_depots.md
---

# SUIVI #1227 — Sécurisation des dépôts

## PROMPT ENVOYÉ

Interdire l'exécution PHP sur le disque `public` (`.htaccess` commité, pas de
`php_flag`). Validation MIME réelle (liste blanche unique) sur GED, marché,
avenant, contact, réservation, juridique. Corriger limites annoncées > plafond
PHP (DCE 500 → ≤120 Mo). Ne pas déplacer `marches/` (#1228). Pas de migration /
pas de `filesystems.php`.

## FICHES LUES

- `#1226` LEÇON : disque public exposé (symlink) ; plusieurs écrans size-only ;
  DCE 500 Mo vs PHP 128M/130M ; dépôt factures = référence MIME.
- `#1108` : erreurs de dépôt doivent être visibles (pas de silence).
- `#1115` : plafond PHP prod documenté.

## SYNTHÈSE

### OBJET 1 — `.htaccess` disque public

Fichier `storage/app/public/.htaccess` (suivi git ; `.gitignore` amende
`!.htaccess`). Syntaxe Apache **2.4** (`Require all denied` via
`mod_authz_core`) + fallback 2.2 (`Order`/`Deny`). Pas de `php_flag` /
`php_value` (PHP-FPM OVH → 500). `Options -Indexes` + `RemoveHandler` /
`RemoveType`.

**Retrait d'urgence** si 500 sur `/storage/…` :
`rm storage/app/public/.htaccess`

### OBJET 2 — Liste blanche unique

**Point de vérité** : `App\Support\UploadDocumentAllowlist` (+ règle
`App\Rules\AllowedDocumentUpload`).

Mécanisme : `mimetypes:` (type réel Laravel/finfo) + règle custom (extensions
interdites, sniff `<?php`/`#!/`/`MZ`, MIME interdits, SVG sans script, PDF
déclaré ⇒ magic `%PDF-`).

**SVG** : MIME `image/svg+xml` autorisé ; rejeté si `<script`, `javascript:`,
`onload=`, `onerror=` dans le contenu.

### OBJET 3 — Limites

| Écran | Avant | Après | Fichier:ligne |
|-------|-------|-------|---------------|
| AO DCE (service) | 500 Mo / 512000 Ko | 120 Mo / 120000 Ko | `AoDocumentService.php:46-47` |
| AO DCE (UI fallback) | `?? 500` | `?? 120` | `AoDocumentsSection.vue:33` |
| `.user.ini` | 512M / 520M | 128M / 130M | `.user.ini` |
| GED / marché / avenant / juridique | 20 Mo | 20 Mo (inchangé) | — |
| Réservation | 50 Mo | 50 Mo (inchangé) | — |
| Contact | 5 Mo | 5 Mo (inchangé) | — |
| Estimatif MOE | 50 Mo | 50 Mo (inchangé) | — |

Plafond partagé : `UploadDocumentAllowlist::PHP_SAFE_MAX_KB = 120000`.

### Écrans touchés / laissés

**Touchés** : GED, marché (création + document), avenant (fichiers), contact,
réservation, juridique (création + PJ), AO DCE (taille seule).

**Laissés** : dépôt factures, `entity_documents` foncier, tâches, imports
(MIME déjà OK ou hors périmètre). Pas de déplacement disque (#1228).

## DÉPLOIEMENT / TEST

```bash
git pull origin main
php artisan optimize:clear
php artisan view:clear
php artisan journal:sync
```

Tests prod (ordre) : PDF marché OK → logo OK → pas de listage → PDF OK →
txt→pdf refusé message → docx/xlsx/zip/png OK → >limite message →
`git ls-files storage/app/public/.htaccess` → dépôt/foncier/tâches inchangés.

## LEÇON

Sur OVH PHP-FPM, un `.htaccess` avec `php_flag` casse tout `/storage/`. Le
fichier doit être **commité** malgré `storage/app/public/.gitignore` (`!`).
Toute limite UI/docs > `upload_max_filesize` réel est un piège utilisateur
(échec muet). Un seul allowlist (`UploadDocumentAllowlist`) évite six copies
divergentes.
