Défense en profondeur
CORS, headers, secrets, moindre privilège, rate limiting.
Objectifs
À la fin de cette leçon, vous saurez :
- appliquer CORS strict et les en-têtes de sécurité ;
- gérer secrets, permissions et moindre privilège ;
- raisonner en couches plutôt qu'en rempart unique.
🔗 Pour vous rafraîchir la mémoire : sessions serveur et cookies · hachage des mots de passe (bcrypt) · DTO et ValidationPipe · dépôts distants (clone, push, pull)
Aucun mur unique : des couches
Le principe de défense en profondeur : chaque couche suppose que la précédente a échoué.
navigateur (CSP, SameSite)
↓ HTTPS
reverse proxy (rate limiting, headers)
↓
API NestJS (session, validation DTO, autorisation @Roles)
↓ requêtes paramétrées
PostgreSQL (contraintes, utilisateur aux droits limités)
↓ volume avec permissions
fichiers
CORS : contrôler qui peut appeler
app.enableCors({
origin: ['https://monsite.fr'], // liste blanche explicite
credentials: true, // autorise cookies/Authorization
});
CORS ne protège pas VOTRE serveur : il décide si le NAVIGATEUR d'un visiteur d'un autre site pourra lire vos réponses. origin: '*' avec credentials est une contradiction — Devmind configure l'origine web précise (WEB_ORIGIN).
Les en-têtes qui coûtent une ligne
X-Content-Type-Options: nosniff ← pas de devinette de type (Devmind l'envoie déjà)
Content-Security-Policy: default-src 'self' ← d'où peuvent venir scripts/styles
Strict-Transport-Security: max-age=31536000 ← HTTPS obligatoire désormais
X-Frame-Options: DENY ← pas d'encapsulation en iframe
Chacun ferme une classe entière d'attaques pour un en-tête : rapport efficacité/prix imbattable.
Secrets et moindre privilège
Secrets → .env hors Git, régénérés, jamais loggés ni commités
Compte applicatif → droits minimaux sur SA base seulement
Utilisateur API → rôle minimal pour ses besoins (STUDENT ≠ ADMIN)
Conteneur → pas root si possible, filesystem restreint
La question systématique : « si CETTE couche est compromise, que peut-on atteindre ? ». Chaque réponse trop large indique un privilège à réduire. Exemple concret du cursus : votre clé API .api-key est admin — elle ne doit JAMAIS sortir de la machine ; une clé d'intégration publique aurait été créée STUDENT avec périmètre réduit.
Rate limiting et journalisation
Rate limiting : 120 req/min par IP (Throttler de Devmind) → freiner le brute-force
Journalisation : qui a fait quoi quand → détecter, comprendre, prouver
Les actions administratives se journalisent spécialement : promotion de rôle, suppression, publication. Un système sans piste d'audit est un système dont on découvre les incidents par hasard.
Trois rappels qui viennent d'ailleurs
Ce chapitre suppose trois acquis — les resituer évite les trous dans la muraille :
- Validation des entrées (première ligne de défense contre injection SQL et XSS) : tout ce qui entre est typé, borné, nettoyé. Côté NestJS, c'est le travail des DTO et du ValidationPipe — chapitre 35, leçon « DTO et validation automatique ».
- HTTPS : il protège le transport (personne ne lit ni ne modifie vos flux en route — chapitres 12 et 48), mais il ne protège PAS l'application : une injection SQL fonctionne aussi bien en HTTPS. Cadena ≠ application sûre.
- Hachage des mots de passe (chapitre 39) : bcrypt + sel unique. Si malgré tout une injection révèle la table
users, les mots de passe doivent rester inexploitables — c'est la raison d'être du hash lent.
La défense en profondeur, c'est précisément cela : chaque couche couvre la panne de la suivante.
Exercice
- Listez les couches de protection de Devmind, de haut en bas.
- Une faille XSS survient : quelles couches limitent les dégâts ?
- Pourquoi un compte applicatif PostgreSQL dédié plutôt que superuser ?
Résumé
- Couches indépendantes : navigateur, transport, API, base, fichiers.
- En-têtes gratuits, CORS blanc, privilèges minimaux, logs partout.
Correction disponibleCherchez d’abord par vous-même.Voir la correction
Correction
Réponses détaillées
Question 2. HttpOnly protège les cookies de session (pas de vol) ; CSP bloque l'exfiltration vers des domaines tiers ; SameSite limite les requêtes forgées ; rate limiting freine l'exploitation massive. La victime subit le script mais rien de décisif ne passe.
Question 3. Avec superuser, toute injection SQL réussie détruit tout (DROP DATABASE). Avec un compte limité à sa base en lecture/écriture, le pire scénario est borné au périmètre applicatif.