security: corriger les vraies vulnérabilités détectées par l'audit

1. MIME spoofing (upload) — app/api/admin/upload/route.ts
   - Ajout de la validation par magic bytes : lit les premiers octets du
     fichier et vérifie la signature binaire réelle (JPEG FF D8 FF,
     PNG 89 50 4E 47, GIF 47 49 46 38, WebP RIFF+WEBP, AVIF ftyp box)
   - Extension dérivée exclusivement du MIME validé côté serveur
     (MIME_TO_EXT), jamais du nom de fichier fourni par le client
   - Un fichier .exe renommé en .jpg est désormais rejeté

2. Générateur de mot de passe non-cryptographique — stripe/webhook/route.ts
   - Remplace Math.random() (non-déterministe mais prévisible) par
     crypto.getRandomValues() (CSPRNG, conforme Web Crypto API)

3. Headers HTTP de sécurité manquants — middleware.ts (nouveau)
   - X-Content-Type-Options: nosniff (anti MIME-sniffing navigateur)
   - X-Frame-Options: SAMEORIGIN (anti clickjacking)
   - Referrer-Policy: strict-origin-when-cross-origin
   - Permissions-Policy: désactive camera, micro, geolocation
   - Content-Security-Policy: whitelist stricte par type de ressource
     (scripts, styles, images Unsplash/Supabase/Sanity, connect Supabase/Stripe,
     frames Stripe uniquement, object-src none, form-action self)

https://claude.ai/code/session_01PzA98VhLMmsHpzs7gnLHGs
This commit is contained in:
Claude
2026-02-21 09:01:21 +00:00
parent 22d3c0658e
commit 3843595e18
3 changed files with 173 additions and 17 deletions

View File

@@ -217,13 +217,14 @@ export async function POST(request: Request) {
}
}
// Générateur de mot de passe temporaire
// Générateur de mot de passe temporaire — crypto.getRandomValues() uniquement
// (cryptographiquement sûr, contrairement à Math.random())
function generatePassword(): string {
const chars =
"ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789!@#$%";
let password = "";
for (let i = 0; i < 12; i++) {
password += chars.charAt(Math.floor(Math.random() * chars.length));
}
return password;
const randomBytes = new Uint8Array(16);
crypto.getRandomValues(randomBytes);
return Array.from(randomBytes.slice(0, 12))
.map((b) => chars[b % chars.length])
.join("");
}