Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

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 :

PostureQuestionPourquoi
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é

TermeDéfinitionExemple AppliFrais
Vulnérabilitéune faiblesse dans le systèmeune route qui ne vérifie pas le rôle
Exploitla technique qui profite de la faiblesseappeler cette route en tant que visiteur
Menacel'acteur/événement qui pourrait nuireun 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.

GarantieCe qu'on protègeExemple de violation sur AppliFrais
Disponibilitéle service répond quand on en a besoinsaturer l'API pour bloquer les remboursements
Intégritéles données ne sont pas altérées en doucechanger le montant d'une fiche déjà validée
Confidentialitéseules les bonnes personnes voient les donnéeslire 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…

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 CVSSSévéritéCe que ça signifie concrètement
0,0AucunePas d'impact
0,1 – 3,9FaibleDifficile à exploiter, impact limité
4,0 – 6,9MoyenExploitable sous certaines conditions
7,0 – 8,9ÉlevéExploitable facilement, impact significatif
9,0 – 10,0CritiqueExploitable sans authentification, impact total

Pour les grandes familles OWASP, voici les scores CVSS typiques observés sur des CVE réelles :

FamilleCVSS typiqueExemple CVE notableImpact
A01 Broken Access Control7,5 – 9,8CVE-2023-4966 (Citrix Bleed)Lecture de sessions actives
A02 Cryptographic Failures5,9 – 9,1CVE-2014-0160 (Heartbleed)Fuite mémoire serveur (clés TLS)
A03 Injection SQL8,8 – 10,0CVE-2012-2122 (MySQL auth)Accès BDD sans mdp en quelques essais
A06 Vulnérable Components7,0 – 9,8CVE-2021-44228 (Log4Shell)RCE à distance, score 10,0
A07 Auth Failures7,5 – 9,8CVE-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.

0 sur 5 dans cette étape

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.

CodeFamilleEn une phraseCVSS typiqueFréquence*
A01Broken Access Controlaccéder à ce qui ne devrait pas t'être permis7,5–9,894 % des applis testées
A02Cryptographic Failuressecrets mal protégés (mots de passe, chiffrement, HTTPS)5,9–9,13e rang par occurrence
A03Injectioninjecter du code dans une requête (SQL, NoSQL, XSS…)8,8–10,0274 000 CVE mappées
A04Insecure Designune conception qui ignore la sécurité dès le départvariablenouveau 2021, en hausse
A05Security Misconfigurationconfig par défaut, headers manquants, CORS trop ouvert5,3–7,590 % des applis testées
A06Vulnerable Componentsune dépendance (npm/pip/maven) avec une faille connue7,0–9,8Log4Shell (CVSS 10,0)
A07Auth Failuresauthentification faible (mdp, sessions, JWT mal gérés)7,5–9,8ex-n°2, glissé à 7
A08Data Integrity Failurescode/données altérés sans détection (supply chain)7,4–9,8SolarWinds 2020
A09Logging Failurespas de logs → on ne détecte pas l'attaque4,0–6,0100 % en préparation E7
A10SSRFforcer le serveur à requêter une URL pour l'attaquant7,5–9,8Capital 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 ».

CodeContre-mesure génériqueDétail technique attendu en E7
A01middleware 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)
A02bcrypt/argon2 pour les mots de passe, TLS 1.2+ partoutCoû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)
A03valider le type, requêtes paramétrées, CSP pour XSSPour MongoDB : typeof val !== 'string' avant tout find() ; pour SQL : ? préparés, jamais de concaténation ; CSP header : script-src 'self'
A04modè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
A05helmet.js, CORS strict, désactiver les pages d'erreur détaillées8 en-têtes HTTP clés (voir section A05 ci-dessous) ; NODE_ENV=production pour masquer les stack traces
A06npm audit, Dependabot, vérifier les licencesnpm audit --audit-level=high dans le CI ; lockfile package-lock.json committé ; npm outdated régulièrement
A07bcrypt pour mdp, JWT signé RS256, rate limiting, MFAJWT : algorithme RS256 (asymétrique) préféré à HS256 ; expiry exp ≤ 15 min pour les tokens d'accès ; refresh token httpOnly cookie
A08vérifier les signatures (lockfile, checksums, SRI)SRI (Subresource Integrity) sur les CDN : <script integrity="sha384-..."> ; ne jamais npm install depuis une URL inconnue
A09journaliser login, accès admin, erreurs 4xx/5xxNe 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
A10liste blanche d'URLs autorisées côté serveurBloquer 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'arcCe que tu y feras
Cette séancenommer les 10 familles, cartographier AppliFrais (panorama)
Séances d'attaque/défensecasser PUIS réparer chaque famille phare en pratique (A03, A01, A02, A05, A07…)
Séances d'auditpasser 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.

0 sur 5 dans cette étape

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éeDonnée qui entreRisque potentiel
Loginemail + mot de passeinjection, brute force (A03, A07)
Recherche / filtresparamètres d'URLinjection NoSQL (A03)
Saisie d'une fichecorps JSON, libellésXSS stocké (A03)
Routes comptableid de fiche, tokencontrôle d'accès (A01)
Upload justificatiffichier imagefichier 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.

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é.

0 sur 5 dans cette étape

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 } }
Ce que tu dois voir
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);
Ce que tu dois voir
// 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 :

AlgorithmeConçu pourTemps sur CPU standardUsage correct
MD5Intégrité de fichiers (1991)~10 milliards/s sur GPUJamais pour les mots de passe — obsolète même pour l'intégrité (collisions connues)
SHA-256Intégrité, signatures numériques~3 milliards/s sur GPUJamais pour les mots de passe — trop rapide, pas de sel intégré
bcrypt (coût 10)Mots de passe~100 ms/hash CPUOui : ralentit le crack, sel aléatoire intégré dans le hash (60 car.)
bcrypt (coût 12)Mots de passe~400 ms/hash CPUOui (recommandé OWASP) : attaquant ne peut tester que ~2-3 mots de passe/s
argon2idMots 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 JWTRisqueCorrection
Secret HS256 trop court (secret123)Brute-forcé en quelques heures avec hashcatSecret ≥ 256 bits (32 octets aléatoires) : openssl rand -hex 32
Pas d'expiry (exp absent)Token volé = accès éternelexpiresIn: '15m' pour l'access token, refresh token séparé
Algorithme none acceptéN'importe qui forge un token valideForcer algorithms: ['RS256'] à la vérification, rejeter none
Token dans localStorageVolé par XSS (A03)Refresh token dans cookie HttpOnly; Secure; SameSite=Strict
Payload avec données sensiblesJWT est encodé (Base64), pas chiffré — tout le monde peut lireNe 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 HTTPValeur par défaut (helmet)Ce qu'il empêche
Content-Security-PolicyRestreint les sources de scriptsXSS (A03) : bloque l'exécution de scripts injectés non autorisés
X-Content-Type-OptionsnosniffMIME sniffing : le navigateur ne devine pas le type — évite l'exécution d'un fichier HTML déguisé en image
X-Frame-OptionsSAMEORIGINClickjacking : empêche l'intégration dans une <iframe> sur un autre domaine
Strict-Transport-Securitymax-age=15552000 (180 jours)Downgrade HTTP : force HTTPS pendant 180 jours — résiste aux attaques man-in-the-middle
X-Powered-BySuppriméFingerprinting : cache le framework utilisé (sinon l'attaquant sait cibler les CVE d'Express)
Referrer-Policyno-referrerFuite d'URL : l'URL de ta page ne part pas dans les requêtes vers des tiers (logs de CDN, analytics)
X-DNS-Prefetch-ControloffTiming attack : le navigateur ne pré-résout pas les domaines de la page (réduit les fuites DNS)
Permissions-PolicyDésactive caméra, micro, géolocFeature 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.

powershell
npm audit --audit-level=high
Ce que tu dois voir
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
powershell
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 Unixtoken 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), montantdonné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.

0 sur 5 dans cette étape

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.

  1. reprends les 10 familles OWASP ;
  2. pour chacune, écris où elle pourrait frapper dans AppliFrais (quel point d'entrée, quelle fonctionnalité) ;
  3. note pour chacune si tu penses ton AppliFrais exposé ou protégé (à ce stade, une intuition suffit) ;
  4. 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 OWASPDonnées exposéesArticle RGPD déclenchéRisque amende CNIL
A01 Broken Access Controlfiches de frais d'autres visiteurs, emails, adressesArt. 5(1)(f) — sécurité et intégrité ; Art. 32 — mesures techniquesJusqu'à 10 M€ ou 2 % CA mondial
A02 Crypto Failures (mdp en clair)mots de passe de tous les utilisateursArt. 32 — obligation de chiffrement/hachage adaptéJusqu'à 10 M€ ; aggravé si > 500 personnes
A03 Injection → fuite BDDtoute la table users / visiteursArt. 33 — notification CNIL sous 72 h ; Art. 34 — communication aux personnesManquement à la notification : jusqu'à 10 M€
A09 Logging Failuresimpossibilité de prouver qui a accédé à quoiArt. 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.

0 sur 5 dans cette étape

Pour finir

Ce que tu emportes

AcquisCe que tu sais
les 10 famillesnommer et reconnaître A01 à A10
posture doublepenser attaquant ET défenseur
surface d'attaquerepérer les points d'entrée d'une appli
règle d'orne jamais faire confiance au client

Vérifie tes acquis — quiz corrigé

Exercice 4 sur 4 Réussi À revoir

  1. Que veut dire OWASP, et qu'est-ce que le Top 10 ?
  2. Différence entre vulnérabilité, exploit et menace ?
  3. Quelle est la règle d'or de la sécurité applicative ?
  4. Qu'est-ce qu'une « surface d'attaque » ?
  5. Quelle est la seule règle légale pour s'entraîner — et quelle peine risque-t-on à ne pas la respecter ?
  6. Cite 3 familles OWASP, leur principe et leur contre-mesure technique précise.
  7. Pourquoi ne pas stocker les mots de passe avec SHA-256 ? Quel algorithme utiliser et quel paramètre choisir ?
  8. Quel en-tête HTTP empêche le clickjacking ? Quelle librairie Node.js l'ajoute automatiquement ?
  9. Tu lances npm audit --audit-level=high et tu trouves une dépendance Critical. Que fais-tu dans les prochaines heures ? Que fais-tu si npm audit fix ne corrige pas la faille ?
  10. Dans tes logs, tu vois 80 entrées LOGIN_FAIL avec la même IP en 2 minutes. Quelle famille OWASP est en cours ? Quelle contre-mesure aurais-tu dû mettre en place ?
  11. 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

MotDéfinition
OWASPfondation produisant des ressources libres de sécurité applicative
Top 10classement des 10 catégories de failles web les plus critiques
Vulnérabilitéune faiblesse exploitable d'un système
Exploitla technique qui tire parti d'une vulnérabilité
Menacel'acteur ou l'événement qui pourrait nuire
Surface d'attaquel'ensemble des points d'entrée d'une application
D-I-CDisponibilité, Intégrité, Confidentialité : les 3 garanties à protéger
Hachagetransformation irréversible d'une donnée en empreinte (bcrypt, argon2)
Middlewarefonction Express qui s'exécute avant la route (ex. vérifier le rôle)
DAST/SASTaudit de sécurité dynamique (app lancée) / statique (code)
IDORInsecure Direct Object Reference — accès à une ressource via son id sans vérifier qu'elle appartient à l'utilisateur (sous-cas d'A01)
CVECommon Vulnerabilities and Exposures — identifiant unique d'une faille connue (ex. CVE-2021-44228 = Log4Shell)
Pentesttest de pénétration : audit de sécurité où un expert simule une attaque réelle, avec accord de l'organisation
Rate limitinglimite 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 attackattaque via une dépendance tierce compromise (ex. un paquet npm malveillant) — cœur de A06 et A08

Panorama terminé ?

Coche chaque livrable quand tu l'as : c'est la preuve que l'étape est acquise.

livrables
–
quiz réussis
–
de série
–
Passer à l'étape suivante : Injection NoSQL (MongoDB)Voir toutes les étapes du TP