Panorama5 livrables4 quiz corrigés
Panorama OWASP Top 10
Avant de casser et de réparer, il faut connaître la carte des dangers. L'OWASP Top 10, c'est la liste de référence des 10 familles de failles web les plus critiques. Aujourd'hui on les survole toutes, sur ton terrain : AppliFrais. C'est la boussole de tout l'arc cybersécurité — et le cœur de l'épreuve E7.
Par Josselyn C., prof de BTS SIO. Publié le , mis à jour le .
- Objectif
- découvrir les 10 familles de failles OWASP et les reconnaître sur une application réelle
- On manipule
- AppliFrais (version d'entraînement), la pensée attaquant/défenseur
- Pré-requis
- connaître AppliFrais (API Express, MongoDB, React, JWT)
Cadre légal : on n'attaque QUE des applications qu'on a le droit de tester (ici, ton AppliFrais). Jamais un site tiers.
Avant de commencer
Pourquoi cette séance
Tu sais construire une application. Il est temps d'apprendre à la défendre — et pour ça, à penser comme un attaquant. L'OWASP Top 10 est la référence mondiale : une liste, mise à jour régulièrement par la communauté sécurité, des 10 catégories de vulnérabilités les plus graves et les plus fréquentes sur le web. C'est le socle de l'épreuve E7 (écrit 4h, Bloc 3) et de tout cet arc cyber. Aujourd'hui, vue d'ensemble : on nomme chaque famille, on voit à quoi elle ressemble sur AppliFrais, et on pose le vocabulaire. Les séances suivantes attaqueront chacune en détail.
Penser en attaquant ET en défenseur
Pour chaque faille, tu vas apprendre les deux côtés. C'est ça, la sécurité applicative :
| Posture | Question | Pourquoi |
|---|---|---|
| Attaquant (offensive) | « comment je casse ça ? » | pour trouver la faille avant le pirate |
| Défenseur (defensive) | « comment j'empêche ça ? » | pour corriger et durcir |
0. C'est quoi, l'OWASP ?
OWASP = Open Worldwide Application Security Project. Une fondation à but non lucratif qui produit des ressources libres sur la sécurité applicative. Son document le plus célèbre : le Top 10.
La différence faille / exploit / vulnérabilité
| Terme | Définition | Exemple AppliFrais |
|---|---|---|
| Vulnérabilité | une faiblesse dans le système | une route qui ne vérifie pas le rôle |
| Exploit | la technique qui profite de la faiblesse | appeler cette route en tant que visiteur |
| Menace | l'acteur/événement qui pourrait nuire | un visiteur malveillant |
Que cherche un attaquant ? Le triangle D-I-C
Une attaque vise toujours à casser au moins une des trois garanties qu'un service doit à ses utilisateurs. On les retrouve derrière chaque famille OWASP, et c'est un repère central de l'E7.
| Garantie | Ce qu'on protège | Exemple de violation sur AppliFrais |
|---|---|---|
| Disponibilité | le service répond quand on en a besoin | saturer l'API pour bloquer les remboursements |
| Intégrité | les données ne sont pas altérées en douce | changer le montant d'une fiche déjà validée |
| Confidentialité | seules les bonnes personnes voient les données | lire les fiches d'un autre visiteur |
Le cycle de vie d'une attaque — où frappent les familles OWASP ?
Une attaque réelle se déroule en phases successives. Chaque famille OWASP frappe à une phase précise : comprendre ce schéma te donne la grille de lecture de tous les rapports de pentest et des sujets E7 — quand on te demande « comment se protéger ? », la réponse dépend de quand l'attaque frappe.
Cycle de vie d'une attaque. Les familles les plus critiques (A01, A02, A03) frappent à l'Exploitation. A04 (mauvaise conception) crée les failles qui permettent l'Exploitation. A09 (absence de logs) est la raison pour laquelle la zone Défense reste aveugle. C'est la grille de lecture de tout rapport de pentest.
Comment mesure-t-on la gravité d'une faille ? Le score CVSS
Quand on lit des CVE (Common Vulnerabilities and Exposures) ou des rapports de pentest, une faille est toujours accompagnée d'un score CVSS (Common Vulnerability Scoring System, version 3.1). C'est une note de 0 à 10 qui résume la dangerosité.
| Score CVSS | Sévérité | Ce que ça signifie concrètement |
|---|---|---|
| 0,0 | Aucune | Pas d'impact |
| 0,1 – 3,9 | Faible | Difficile à exploiter, impact limité |
| 4,0 – 6,9 | Moyen | Exploitable sous certaines conditions |
| 7,0 – 8,9 | Élevé | Exploitable facilement, impact significatif |
| 9,0 – 10,0 | Critique | Exploitable sans authentification, impact total |
Pour les grandes familles OWASP, voici les scores CVSS typiques observés sur des CVE réelles :
| Famille | CVSS typique | Exemple CVE notable | Impact |
|---|---|---|---|
| A01 Broken Access Control | 7,5 – 9,8 | CVE-2023-4966 (Citrix Bleed) | Lecture de sessions actives |
| A02 Cryptographic Failures | 5,9 – 9,1 | CVE-2014-0160 (Heartbleed) | Fuite mémoire serveur (clés TLS) |
| A03 Injection SQL | 8,8 – 10,0 | CVE-2012-2122 (MySQL auth) | Accès BDD sans mdp en quelques essais |
| A06 Vulnérable Components | 7,0 – 9,8 | CVE-2021-44228 (Log4Shell) | RCE à distance, score 10,0 |
| A07 Auth Failures | 7,5 – 9,8 | CVE-2022-35914 (GLPI) | RCE sans authentification |
Flag D1
Investigation documentaire
Va sur le site officiel de l'OWASP, trouve la page du Top 10 le plus récent. Rends : l'année de la version en vigueur + le nom exact (anglais) des catégories A01 et A03. Bonus : cherche le CVE de Log4Shell et retrouve son score CVSS officiel.
1. Les 10 familles, en un coup d'œil
Voici la carte complète. Garde-la sous les yeux : c'est ta table des matières pour tout l'arc cyber.
| Code | Famille | En une phrase | CVSS typique | Fréquence* |
|---|---|---|---|---|
| A01 | Broken Access Control | accéder à ce qui ne devrait pas t'être permis | 7,5–9,8 | 94 % des applis testées |
| A02 | Cryptographic Failures | secrets mal protégés (mots de passe, chiffrement, HTTPS) | 5,9–9,1 | 3e rang par occurrence |
| A03 | Injection | injecter du code dans une requête (SQL, NoSQL, XSS…) | 8,8–10,0 | 274 000 CVE mappées |
| A04 | Insecure Design | une conception qui ignore la sécurité dès le départ | variable | nouveau 2021, en hausse |
| A05 | Security Misconfiguration | config par défaut, headers manquants, CORS trop ouvert | 5,3–7,5 | 90 % des applis testées |
| A06 | Vulnerable Components | une dépendance (npm/pip/maven) avec une faille connue | 7,0–9,8 | Log4Shell (CVSS 10,0) |
| A07 | Auth Failures | authentification faible (mdp, sessions, JWT mal gérés) | 7,5–9,8 | ex-n°2, glissé à 7 |
| A08 | Data Integrity Failures | code/données altérés sans détection (supply chain) | 7,4–9,8 | SolarWinds 2020 |
| A09 | Logging Failures | pas de logs → on ne détecte pas l'attaque | 4,0–6,0 | 100 % en préparation E7 |
| A10 | SSRF | forcer le serveur à requêter une URL pour l'attaquant | 7,5–9,8 | Capital One 2019 (AWS) |
* Sources : rapport OWASP Top 10 2021, NVD (National Vulnerability Database). Fréquence = proportion d'applis présentant la faille lors d'audits réels.
Famille → contre-mesure générique
Chaque famille a une parade « réflexe ». Tu l'approfondiras dans sa séance dédiée ; garde ce tableau comme aide-mémoire pour l'E7 (on te demandera souvent : « comment corriger ? »). Les détails techniques concrets sont ce que l'E7 attend — pas seulement « sécuriser le code ».
| Code | Contre-mesure générique | Détail technique attendu en E7 |
|---|---|---|
| A01 | middleware de contrôle rôle + propriété | Vérifier req.user.role === 'comptable' ET fiche.visiteurId === req.user.id — les deux, pas l'un ou l'autre (IDOR si on vérifie seulement le rôle) |
| A02 | bcrypt/argon2 pour les mots de passe, TLS 1.2+ partout | Coût bcrypt ≥ 10 (soit ~100 ms/hash) ; jamais SHA-256 ni MD5 pour les mots de passe ; stocker le sel dans le hash lui-même (bcrypt le fait automatiquement) |
| A03 | valider le type, requêtes paramétrées, CSP pour XSS | Pour MongoDB : typeof val !== 'string' avant tout find() ; pour SQL : ? préparés, jamais de concaténation ; CSP header : script-src 'self' |
| A04 | modèle de menace dès la conception (threat modeling) | Méthode STRIDE (Spoofing / Tampering / Repudiation / Info Disclosure / DoS / Elevation) ; aucun correctif ne remplace une mauvaise conception |
| A05 | helmet.js, CORS strict, désactiver les pages d'erreur détaillées | 8 en-têtes HTTP clés (voir section A05 ci-dessous) ; NODE_ENV=production pour masquer les stack traces |
| A06 | npm audit, Dependabot, vérifier les licences | npm audit --audit-level=high dans le CI ; lockfile package-lock.json committé ; npm outdated régulièrement |
| A07 | bcrypt pour mdp, JWT signé RS256, rate limiting, MFA | JWT : algorithme RS256 (asymétrique) préféré à HS256 ; expiry exp ≤ 15 min pour les tokens d'accès ; refresh token httpOnly cookie |
| A08 | vérifier les signatures (lockfile, checksums, SRI) | SRI (Subresource Integrity) sur les CDN : <script integrity="sha384-..."> ; ne jamais npm install depuis une URL inconnue |
| A09 | journaliser login, accès admin, erreurs 4xx/5xx | Ne jamais logger les mots de passe/tokens dans les logs ; conserver 90 jours minimum (obligation ANSSI pour les OIV) ; format structuré JSON pour parser avec ELK/Splunk |
| A10 | liste blanche d'URLs autorisées côté serveur | Bloquer les plages IP privées (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 pour les metadata cloud AWS/GCP) |
La feuille de route de l'arc cyber
Ce panorama est la boussole. Voici comment l'arc s'enchaîne ensuite — garde-la pour savoir où tu vas.
| Étape de l'arc | Ce que tu y feras |
|---|---|
| Cette séance | nommer les 10 familles, cartographier AppliFrais (panorama) |
| Séances d'attaque/défense | casser PUIS réparer chaque famille phare en pratique (A03, A01, A02, A05, A07…) |
| Séances d'audit | passer AppliFrais au crible (outils SAST/DAST, npm audit) |
| Épreuve E7 | écrit 4h : identifier une faille, expliquer le risque, proposer la correction |
Flag B1
Production
Pour chaque famille A01 à A10, écris en tes mots (une phrase) ce qu'elle signifie, sans recopier le tableau. Rends : ta liste reformulée — c'est ta fiche de révision E7.
2. AppliFrais, ton terrain d'entraînement
Pour apprendre, on a besoin d'une application qu'on a le droit de casser. Ce sera AppliFrais — la tienne, montée en local, dans une version qu'on rendra volontairement vulnérable pour l'exercice.
La surface d'attaque d'AppliFrais
| Point d'entrée | Donnée qui entre | Risque potentiel |
|---|---|---|
| Login | email + mot de passe | injection, brute force (A03, A07) |
| Recherche / filtres | paramètres d'URL | injection NoSQL (A03) |
| Saisie d'une fiche | corps JSON, libellés | XSS stocké (A03) |
| Routes comptable | id de fiche, token | contrôle d'accès (A01) |
| Upload justificatif | fichier image | fichier malveillant, SSRF (A10) |
Surface d'attaque d'AppliFrais : tout ce qui vient du client (rouge) est NON fiable. Chaque entrée doit passer la « porte » de validation/autorisation (vert) avant d'atteindre le serveur, la base et le stockage.
Flag B2
Production
Complète la surface d'attaque d'AppliFrais : trouve 3 points d'entrée supplémentaires (où une donnée du client arrive au serveur) et associe à chacun une famille OWASP. Rends : ton tableau complété.
3. Les failles phares, en avant-goût
Trois familles que tu rencontreras le plus souvent — juste de quoi sentir le mécanisme (le détail viendra dans leurs séances dédiées).
A03 — Injection (le plus parlant — deux variantes)
Le principe : une donnée du client est interprétée comme du code au lieu d'être traitée comme une simple valeur. Il en existe plusieurs formes — en connaître deux te donne la logique générale.
Variante 1 — Injection NoSQL (MongoDB, ton stack AppliFrais)
// VULNERABLE : la saisie de l'utilisateur entre directement dans la requete
db.collection('users').find({ email: req.body.email });
// si req.body.email vaut { "$ne": null }, la requete renvoie TOUS les users
POST /api/login
Content-Type: application/json
{ "email": { "$ne": null }, "password": { "$ne": null } }
HTTP/1.1 200 OK
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "role": "comptable" }
// SUR : on impose que email soit bien une chaine avant de l'utiliser
if (typeof req.body.email !== 'string') return res.sendStatus(400);
if (typeof req.body.password !== 'string') return res.sendStatus(400);
db.collection('users').find({ email: req.body.email });
Variante 2 — Injection SQL (contexte GSB Ordonnances 1A, MySQL)
// VULNERABLE (C# / MySQL) : concatenation directe dans la requete
string query = "SELECT * FROM medecin WHERE login='" + login + "' AND mdp='" + mdp + "'";
MySqlCommand cmd = new MySqlCommand(query, conn);
// Sortie cote serveur : la requete envoyee a MySQL est :
SELECT * FROM medecin WHERE login='admin' --' AND mdp='nimportequoi'
// Le commentaire -- neutralise tout ce qui suit -> login reussi
// SUR (C# / MySQL) : requete parametree (AddWithValue)
string query = "SELECT * FROM medecin WHERE login=@login AND mdp=@mdp";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@login", login);
cmd.Parameters.AddWithValue("@mdp", mdp);
A01 — Broken Access Control
// VULNERABLE : la route ne verifie pas QUI demande
router.patch('/api/fiches/:id/valider', valider);
// un visiteur peut valider sa propre fiche -> il s'auto-rembourse
// SUR : un middleware verifie le role AVANT d'executer l'action
router.patch('/api/fiches/:id/valider', requireRole('comptable'), valider);
A02 — Cryptographic Failures
// VULNERABLE : mot de passe stocke en clair
await User.create({ email, password: req.body.password });
// si la base fuite, tous les mots de passe sont lisibles
// SUR : on hache le mot de passe avant de le stocker
const hash = await bcrypt.hash(req.body.password, 12);
await User.create({ email, password: hash });
Pourquoi bcrypt et pas SHA-256 ?
C'est la question que tout développeur se pose au moins une fois. Voici la vraie réponse :
| Algorithme | Conçu pour | Temps sur CPU standard | Usage correct |
|---|---|---|---|
| MD5 | Intégrité de fichiers (1991) | ~10 milliards/s sur GPU | Jamais pour les mots de passe — obsolète même pour l'intégrité (collisions connues) |
| SHA-256 | Intégrité, signatures numériques | ~3 milliards/s sur GPU | Jamais pour les mots de passe — trop rapide, pas de sel intégré |
| bcrypt (coût 10) | Mots de passe | ~100 ms/hash CPU | Oui : ralentit le crack, sel aléatoire intégré dans le hash (60 car.) |
| bcrypt (coût 12) | Mots de passe | ~400 ms/hash CPU | Oui (recommandé OWASP) : attaquant ne peut tester que ~2-3 mots de passe/s |
| argon2id | Mots de passe (2015, champion PHC) | ~300 ms/hash (paramétrable) | Meilleur choix aujourd'hui : résistant aux GPU ET FPGA ; recommandé NIST 2024 |
Et les tokens JWT ? Le vrai risque
JWT (JSON Web Token) n'est pas un système d'authentification — c'est un format de token signé. Les erreurs classiques :
| Erreur JWT | Risque | Correction |
|---|---|---|
Secret HS256 trop court (secret123) | Brute-forcé en quelques heures avec hashcat | Secret ≥ 256 bits (32 octets aléatoires) : openssl rand -hex 32 |
Pas d'expiry (exp absent) | Token volé = accès éternel | expiresIn: '15m' pour l'access token, refresh token séparé |
Algorithme none accepté | N'importe qui forge un token valide | Forcer algorithms: ['RS256'] à la vérification, rejeter none |
Token dans localStorage | Volé par XSS (A03) | Refresh token dans cookie HttpOnly; Secure; SameSite=Strict |
| Payload avec données sensibles | JWT est encodé (Base64), pas chiffré — tout le monde peut lire | Ne mettre que userId, role, exp — jamais de mdp ni de DCP sensibles |
A05 — Security Misconfiguration : les en-têtes que tout le monde oublie
La plupart des frameworks ne configurent pas de sécurité par défaut. Une app Express fraîche répond avec 0 en-tête de sécurité. helmet.js en ajoute 8 d'un coup.
// Sans helmet (ce qu'Express retourne par defaut)
HTTP/1.1 200 OK
X-Powered-By: Express // divulgue le framework — retirer en premier
Content-Type: application/json
// Avec helmet (une ligne dans app.js)
const helmet = require('helmet');
app.use(helmet()); // active les 8 en-tetes suivants automatiquement
| En-tête HTTP | Valeur par défaut (helmet) | Ce qu'il empêche |
|---|---|---|
Content-Security-Policy | Restreint les sources de scripts | XSS (A03) : bloque l'exécution de scripts injectés non autorisés |
X-Content-Type-Options | nosniff | MIME sniffing : le navigateur ne devine pas le type — évite l'exécution d'un fichier HTML déguisé en image |
X-Frame-Options | SAMEORIGIN | Clickjacking : empêche l'intégration dans une <iframe> sur un autre domaine |
Strict-Transport-Security | max-age=15552000 (180 jours) | Downgrade HTTP : force HTTPS pendant 180 jours — résiste aux attaques man-in-the-middle |
X-Powered-By | Supprimé | Fingerprinting : cache le framework utilisé (sinon l'attaquant sait cibler les CVE d'Express) |
Referrer-Policy | no-referrer | Fuite d'URL : l'URL de ta page ne part pas dans les requêtes vers des tiers (logs de CDN, analytics) |
X-DNS-Prefetch-Control | off | Timing attack : le navigateur ne pré-résout pas les domaines de la page (réduit les fuites DNS) |
Permissions-Policy | Désactive caméra, micro, géoloc | Feature abuse : un script ne peut pas accéder aux capteurs sans permission explicite |
A06 — Composants vulnérables : npm audit pas à pas
86 % des applications web utilisent des dépendances open source. Une seule d'entre elles peut contenir une faille connue (comme Log4Shell, CVSS 10,0 — dans une bibliothèque Java utilisée par des millions de serveurs). npm audit est ton scanner de dépendances : il compare ton package-lock.json avec la base NVD (National Vulnerability Database) et te liste les CVE connues. C'est la commande à lancer avant chaque déploiement.
npm audit --audit-level=high
found 2 vulnerabilities (1 high, 1 critical)
critical GHSA-c2qf-rxjj-qqgw — express 4.17.1
Package express
Severity critical
Title Open Redirect via malformed URL
URL https://github.com/advisories/GHSA-c2qf-rxjj-qqgw
Fix Available Yes -- run: npm audit fix
high GHSA-rv95-896h-c2vc — axios >=0.8.1 <1.6.0
Package axios
Severity high
Title Regular Expression Denial of Service (ReDoS)
URL https://github.com/advisories/GHSA-rv95-896h-c2vc
Fix Available Yes -- run: npm audit fix
Run `npm audit fix` to fix 2 of 2 issues.
npm audit fix
npm audit fix # corrige en montant de version mineure (safe, respecte semver)
npm audit fix --force # force les mises a jour majeures (peut casser l'API — relancer les tests)
A09 — Logging Failures : que journaliser — et que ne jamais journaliser
Sans logs, une attaque passée en phase Exploitation reste invisible en moyenne 207 jours (IBM Cost of a Data Breach, 2023). Les logs sont la mémoire de l'application — sans eux, tu es aveugle. Mais mal configurés, les logs deviennent eux-mêmes une faille (mots de passe en clair dans les fichiers de log).
// CE QU'ON DOIT LOGGER — exemples avec winston ou console structuree
logger.info('LOGIN_SUCCESS', { userId, role, ip: req.ip, ts: Date.now() });
logger.warn('LOGIN_FAIL', { email: req.body.email, ip: req.ip, ts: Date.now() });
logger.error('ACCESS_DENIED',{ userId, route: req.path, method: req.method, ts: Date.now() });
logger.info('FICHE_VALIDEE', { ficheId, comptableId, montant, ts: Date.now() });
// CE QU'ON NE DOIT JAMAIS LOGGER
logger.info('USER_DATA', { password: req.body.password }); // JAMAIS le mot de passe
logger.debug('JWT_TOKEN', { token }); // JAMAIS le token complet
logger.info('SEARCH', { query: req.body }); // si body contient un mdp/token
| À LOGGER (traçabilité) | À NE JAMAIS LOGGER (confidentialité) |
|---|---|
| userId (ou son hash si RGPD l'exige) | mot de passe, même haché |
| IP, User-Agent, timestamp Unix | token JWT complet (permet de rejouer la session) |
| Route, méthode HTTP, code HTTP retourné | numéro de carte bancaire, IBAN, numéro de sécu |
| ficheId, état (CR→CL→VA), montant | données de santé, numéro de sécu |
| Message d'erreur métier tronqué | Stack trace complète en prod (révèle l'archi interne) |
Flag D2
Investigation (sur ton code)
Ouvre ton AppliFrais. Trouve UN endroit où une donnée du client est utilisée, et demande-toi : est-elle validée ? À quelle famille OWASP cela touche-t-il ? Rends : l'extrait + ton analyse (la donnée est-elle digne de confiance ?). Bonus : vérifie si helmet est installé dans ton package.json et si app.use(helmet()) est présent dans app.js.
Exercice de lecture de code — identifie la famille OWASP
Trois extraits de code tirés d'une version vulnérable d'AppliFrais. Pour chacun : identifie la ou les familles OWASP concernées, explique le risque, propose la correction. Essaie d'abord par toi-même, puis ouvre le corrigé juste en-dessous. C'est exactement ce que l'E7 te demande.
Extrait 1 — Route de suppression
Exercice 1 sur 4 Réussi À revoir
// routes/fiches.js
router.delete('/api/fiches/:id', async (req, res) => {
const fiche = await Fiche.findByIdAndDelete(req.params.id);
res.json({ deleted: fiche._id });
});
Voir le corrigéMasquer le corrigé de l'exercice 1
Famille OWASP : A01 — Broken Access Control (+ A07 si aucune authentification avant la route).
Risque : n'importe qui connaissant un _id MongoDB peut supprimer n'importe quelle fiche — c'est un IDOR (Insecure Direct Object Reference). L'id MongoDB (64f3a1...) n'est pas secret : il est souvent visible dans l'URL ou les réponses API. Il n'y a aucune vérification de rôle, aucune vérification que la fiche appartient à l'utilisateur connecté.
Correction en deux couches obligatoires : (1) router.delete('/api/fiches/:id', requireAuth, requireRole('comptable'), ... pour le rôle, ET (2) dans le handler, vérifier fiche.visiteurId.equals(req.user.id) si c'est un visiteur qui supprime sa propre fiche. Les deux vérifications sont nécessaires — une seule ne suffit pas (IDOR possible si on vérifie seulement le rôle sans l'appartenance).
Tu avais trouvé ?
Extrait 2 — Recherche de visiteurs
Exercice 2 sur 4 Réussi À revoir
// routes/visiteurs.js
router.get('/api/visiteurs', async (req, res) => {
const visiteurs = await Visiteur.find({ nom: req.query.nom });
res.json(visiteurs);
});
Voir le corrigéMasquer le corrigé de l'exercice 2
Familles OWASP : A03 — Injection NoSQL + A01 — Broken Access Control.
Risque injection : si l'attaquant envoie /api/visiteurs?nom[$ne]=x, Express parse l'URL et crée req.query.nom = { $ne: "x" } (un objet, pas une chaîne). MongoDB interprète { $ne: "x" } et retourne tous les visiteurs dont le nom n'est pas "x" — soit toute la collection. C'est une fuite massive de données personnelles.
Risque accès : même sans injection, lister tous les visiteurs sans vérifier le rôle expose les DCP à n'importe qui.
Correction : if (typeof req.query.nom !== 'string') return res.sendStatus(400); + requireRole('comptable') sur la route.
Tu avais trouvé ?
Extrait 3 — Middleware d'authentification
Exercice 3 sur 4 Réussi À revoir
// middleware/auth.js
function authenticate(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.sendStatus(401);
const payload = jwt.verify(token, process.env.JWT_SECRET);
req.user = payload;
next();
}
Voir le corrigéMasquer le corrigé de l'exercice 3
Familles OWASP : A07 — Auth Failures + A05 — Security Misconfiguration.
Risque 1 — crash serveur : jwt.verify() lève une exception (JsonWebTokenError ou TokenExpiredError) si le token est invalide ou expiré. Sans try/catch, l'exception non gérée fait planter le processus Express ou retourne une stack trace complète au client (fuite d'information, A05). En prod, une stack trace révèle les chemins de fichiers, les versions de bibliothèques, l'archi interne.
Risque 2 — algorithme non forcé : sans { algorithms: ['HS256'] }, certaines versions de jsonwebtoken acceptaient des tokens signés avec l'algorithme none (CVE-2022-23529). N'importe qui pouvait forger un token valide.
Correction :
function authenticate(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.sendStatus(401);
try {
const payload = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'] });
req.user = payload;
next();
} catch (err) {
return res.sendStatus(401); // ne PAS retourner err.message : divulgue l'archi
}
}
Tu avais trouvé ?
4. Mini-projet : cartographier AppliFrais
La mission
Tu vas produire la carte de menace d'AppliFrais : un document de référence que tu enrichiras à chaque séance de l'arc cyber.
- reprends les 10 familles OWASP ;
- pour chacune, écris où elle pourrait frapper dans AppliFrais (quel point d'entrée, quelle fonctionnalité) ;
- note pour chacune si tu penses ton AppliFrais exposé ou protégé (à ce stade, une intuition suffit) ;
- classe les 3 que tu juges les plus risquées pour ton appli.
OWASP et le RGPD : la double peine
Certaines failles OWASP, si elles provoquent une fuite de données personnelles, déclenchent en plus une obligation RGPD. En France, la CNIL peut sanctionner indépendamment de toute sanction pénale. Voici les croisements à connaître pour l'E7 :
| Famille OWASP | Données exposées | Article RGPD déclenché | Risque amende CNIL |
|---|---|---|---|
| A01 Broken Access Control | fiches de frais d'autres visiteurs, emails, adresses | Art. 5(1)(f) — sécurité et intégrité ; Art. 32 — mesures techniques | Jusqu'à 10 M€ ou 2 % CA mondial |
| A02 Crypto Failures (mdp en clair) | mots de passe de tous les utilisateurs | Art. 32 — obligation de chiffrement/hachage adapté | Jusqu'à 10 M€ ; aggravé si > 500 personnes |
| A03 Injection → fuite BDD | toute la table users / visiteurs | Art. 33 — notification CNIL sous 72 h ; Art. 34 — communication aux personnes | Manquement à la notification : jusqu'à 10 M€ |
| A09 Logging Failures | impossibilité de prouver qui a accédé à quoi | Art. 5(2) — principe d'accountability (responsabilité) | Amende pour absence de registre de traitements |
Flag B3
Mini-projet (livrable)
Livre ta carte de menace AppliFrais (les 10 familles × où ça frappe × exposé/protégé + ton top 3). Pour chaque famille de ton top 3, indique également si une fuite déclencherait une obligation RGPD et laquelle. Rends : ta carte. Tu la mettras à jour à chaque séance — à la fin de l'arc, ce sera ton audit de sécurité complet. Savoir où on est vulnérable, c'est déjà la moitié de la défense.
Pour finir
Ce que tu emportes
| Acquis | Ce que tu sais |
|---|---|
| les 10 familles | nommer et reconnaître A01 à A10 |
| posture double | penser attaquant ET défenseur |
| surface d'attaque | repérer les points d'entrée d'une appli |
| règle d'or | ne jamais faire confiance au client |
Vérifie tes acquis — quiz corrigé
Exercice 4 sur 4 Réussi À revoir
- Que veut dire OWASP, et qu'est-ce que le Top 10 ?
- Différence entre vulnérabilité, exploit et menace ?
- Quelle est la règle d'or de la sécurité applicative ?
- Qu'est-ce qu'une « surface d'attaque » ?
- Quelle est la seule règle légale pour s'entraîner — et quelle peine risque-t-on à ne pas la respecter ?
- Cite 3 familles OWASP, leur principe et leur contre-mesure technique précise.
- Pourquoi ne pas stocker les mots de passe avec SHA-256 ? Quel algorithme utiliser et quel paramètre choisir ?
- Quel en-tête HTTP empêche le clickjacking ? Quelle librairie Node.js l'ajoute automatiquement ?
- Tu lances
npm audit --audit-level=highet tu trouves une dépendance Critical. Que fais-tu dans les prochaines heures ? Que fais-tu sinpm audit fixne corrige pas la faille ? - Dans tes logs, tu vois 80 entrées
LOGIN_FAILavec la même IP en 2 minutes. Quelle famille OWASP est en cours ? Quelle contre-mesure aurais-tu dû mettre en place ? - Qu'est-ce qu'un IDOR ? Donne un exemple concret sur AppliFrais et explique les deux vérifications côté serveur à faire pour s'en protéger.
Voir le corrigéMasquer le corrigé de l'exercice 4
1. OWASP = Open Worldwide Application Security Project, fondation à but non lucratif. Le Top 10 = classement des 10 catégories de vulnérabilités web les plus fréquentes et critiques, établi sur des données réelles d'audits (version 2021 en vigueur). Codes A01 à A10.
2. Vulnérabilité = faiblesse du système (ex. route sans vérification de rôle). Exploit = la technique qui en profite (ex. appeler la route en tant que visiteur). Menace = l'acteur qui pourrait agir (ex. visiteur malveillant). Les trois sont distincts : une vulnérabilité existe sans qu'il y ait exploit actif.
3. « Ne jamais faire confiance à une donnée qui vient du client. » Tout ce qui entre (body, params, query, headers) doit être validé, typé, autorisé côté serveur.
4. L'ensemble des points d'entrée d'une application où des données extérieures peuvent entrer (formulaires, URL, en-têtes, fichiers uploadés, tokens…). Chaque entrée est une porte à vérifier.
5. On n'attaque QUE des systèmes qu'on a le droit de tester (son propre AppliFrais local ou des labos prévus pour). Art. 323-1 du Code pénal : jusqu'à 3 ans & 100 000 € pour accès frauduleux ; art. 323-2 : jusqu'à 5 ans & 150 000 € pour entrave.
6. Exemple : A01 Broken Access Control (accès sans autorisation → middleware requireRole) / A03 Injection (donnée interprétée comme code → valider les types, requêtes paramétrées) / A02 Crypto Failures (secrets mal protégés → bcrypt coût ≥ 10 pour les mots de passe, TLS 1.2+ pour le transit).
7. SHA-256 hash ~3 milliards de mots de passe/s sur GPU → dictionnaire de 10 milliards craqué en secondes. bcrypt avec coût 12 = ~400 ms/hash → ~2-3 essais/s seulement, soit 100 ans pour le même dictionnaire. Utiliser bcrypt (coût 10-12) ou argon2id ; jamais MD5 ni SHA-*. Le sel est intégré automatiquement dans le hash bcrypt (22 premiers caractères de la chaîne de 60).
8. X-Frame-Options: SAMEORIGIN empêche le clickjacking (iframe d'un autre domaine). La librairie helmet.js (app.use(helmet())) l'ajoute avec 7 autres en-têtes de sécurité automatiquement.
9. Faille Critical : bloquer le déploiement immédiatement. Lancer npm audit fix : si ça corrige, retester (CI) et déployer le correctif. Si npm audit fix ne corrige pas (version patchée non compatible semver), recourir à npm audit fix --force en testant les régressions, ou mettre en place un contournement temporaire (désactiver la fonctionnalité vulnérable, isoler le service) en attendant la montée de version. Ne jamais laisser une Critical sans action documentée.
10. Famille A07 — Auth Failures (brute force). La contre-mesure : rate limiting sur la route de login. Exemple avec express-rate-limit : limiter à 5 tentatives par IP par fenêtre de 15 minutes, puis bloquer 15 min (code 429). Compléter avec un log BRUTE_FORCE_ALERT et, idéalement, un CAPTCHA après 3 échecs. Sans rate limiting, un attaquant peut tester des millions de mots de passe courants en quelques heures.
11. IDOR (Insecure Direct Object Reference) : accéder à une ressource via son id sans vérifier qu'elle appartient à l'utilisateur connecté. Exemple AppliFrais : GET /api/fiches/64f3a1... retourne la fiche d'un autre visiteur si la route ne vérifie que l'authentification mais pas l'appartenance. Deux vérifications obligatoires côté serveur : (1) vérifier le rôle (requireRole('visiteur')), ET (2) vérifier l'appartenance (if (!fiche.visiteurId.equals(req.user.id)) return res.sendStatus(403)). Les deux sont nécessaires — l'une sans l'autre laisse une porte ouverte.
Tu avais trouvé ?
Glossaire
| Mot | Définition |
|---|---|
| OWASP | fondation produisant des ressources libres de sécurité applicative |
| Top 10 | classement des 10 catégories de failles web les plus critiques |
| Vulnérabilité | une faiblesse exploitable d'un système |
| Exploit | la technique qui tire parti d'une vulnérabilité |
| Menace | l'acteur ou l'événement qui pourrait nuire |
| Surface d'attaque | l'ensemble des points d'entrée d'une application |
| D-I-C | Disponibilité, Intégrité, Confidentialité : les 3 garanties à protéger |
| Hachage | transformation irréversible d'une donnée en empreinte (bcrypt, argon2) |
| Middleware | fonction Express qui s'exécute avant la route (ex. vérifier le rôle) |
| DAST/SAST | audit de sécurité dynamique (app lancée) / statique (code) |
| IDOR | Insecure Direct Object Reference — accès à une ressource via son id sans vérifier qu'elle appartient à l'utilisateur (sous-cas d'A01) |
| CVE | Common Vulnerabilities and Exposures — identifiant unique d'une faille connue (ex. CVE-2021-44228 = Log4Shell) |
| Pentest | test de pénétration : audit de sécurité où un expert simule une attaque réelle, avec accord de l'organisation |
| Rate limiting | limite le nombre de requêtes qu'un client peut envoyer sur une période (ex. 5 tentatives de login par minute) — contre le brute force (A07) |
| Supply chain attack | attaque via une dépendance tierce compromise (ex. un paquet npm malveillant) — cœur de A06 et A08 |