Jour 21 Day 21 · vendredi 28 août 2026 Friday 28 August 2026 Sécurité Intermédiaire
OWASP Top 10 & les injections OWASP Top 10 & injections
Le Top 10 OWASP, l'injection SQL et le réflexe « ne jamais faire confiance à l'entrée utilisateur » : le minimum sécurité qu'un recruteur attend de tout candidat développeur, stage compris. The OWASP Top 10, SQL injection and the "never trust user input" reflex: the security baseline every recruiter expects from any developer candidate, interns included.
L’essentiel
L’OWASP (Open Worldwide Application Security Project) publie le Top 10 : le classement de référence des risques de sécurité des applications web. La version 2021, en une ligne chacun :
- A01 Broken Access Control — l’utilisateur accède à ce qui ne lui appartient pas (le n°1, ex-aequo avec le plus fréquent).
- A02 Cryptographic Failures — données sensibles mal chiffrées, en clair, ou avec des algos obsolètes (MD5, SHA1 pour les mots de passe).
- A03 Injection — des données utilisateur interprétées comme du code : SQL, commandes shell, et désormais XSS y est rattaché.
- A04 Insecure Design — la faille est dans la conception même (pas de limite d’essais, logique métier contournable), pas dans le code.
- A05 Security Misconfiguration — défauts de config : credentials par défaut, stack traces exposées, ports ouverts, headers absents.
- A06 Vulnerable Components — dépendances vulnérables non mises à jour (le
npm auditqu’on ignore). - A07 Identification & Authentication Failures — sessions et authentification cassées : brute force possible, mots de passe faibles acceptés.
- A08 Software & Data Integrity Failures — confiance aveugle dans des données ou du code non vérifiés (CI/CD compromise, désérialisation).
- A09 Logging & Monitoring Failures — l’attaque réussit et personne ne le voit, faute de logs et d’alertes.
- A10 SSRF — le serveur est manipulé pour faire des requêtes vers des cibles internes qu’il est seul à atteindre.
Le fil conducteur de presque tout le Top 10 tient en une règle : ne jamais faire confiance à l’entrée utilisateur. Toute donnée qui vient du client — paramètre d’URL, corps de requête, header, cookie — est potentiellement hostile, et la validation doit se faire côté serveur, toujours.
Comment ça marche
Une injection exploite toujours la même confusion : l’application construit une chaîne (requête SQL, commande shell, HTML) en y concaténant des données utilisateur, et l’interpréteur en face ne sait pas distinguer données et code.
Entrée : ' OR '1'='1' --
│
▼ concaténation naïve
SELECT * FROM users
WHERE email = '' OR '1'='1' --' AND pw = '…'
│
▼ l'interpréteur SQL exécute TOUT
→ la condition est toujours vraie
→ authentification contournée
La parade n’est pas d’échapper les quotes à la main, c’est de séparer structurellement code et données : les requêtes préparées. La requête (le code) part d’abord, les valeurs (les données) sont transmises à part et ne seront jamais interprétées.
// ❌ VULNÉRABLE : l'entrée utilisateur devient du code SQL
const rows = await db.query(
`SELECT * FROM users WHERE email = '${req.body.email}'`
);
// email = "' OR '1'='1' --" → toute la table est renvoyée
// ✅ REQUÊTE PRÉPARÉE : la valeur reste une valeur, quoi qu'elle contienne
const rows = await db.query(
"SELECT * FROM users WHERE email = $1", // le code, figé
[req.body.email] // la donnée, jamais interprétée
);
// Les ORM (Prisma, Sequelize…) le font par défaut — sauf si vous
// utilisez leurs méthodes "raw" avec de la concaténation.
Même famille, autres interpréteurs :
- Command injection —
exec("ping " + userInput)avecuserInput = "8.8.8.8; rm -rf /". Parade : ne pas passer par un shell (execFileavec arguments séparés), allowlist stricte. - XSS (Cross-Site Scripting) — l’injection côté client : du HTML/JS injecté dans la page et exécuté chez les autres utilisateurs (vol de session, actions à leur insu). Parade : échapper à l’affichage (les frameworks modernes le font par défaut — ne jamais contourner avec
dangerouslySetInnerHTML/innerHTMLsur de la donnée utilisateur), et une Content Security Policy en défense en profondeur.
⚠️ La validation front n’est pas de la sécurité — un
required, un pattern regex ou un bouton désactivé côté client, c’est de l’UX. N’importe qui contourne le front aveccurlou en modifiant le DOM. La seule validation qui compte pour la sécurité est celle du serveur ; celle du front n’est qu’un confort pour l’utilisateur honnête.
Concepts clés à maîtriser
Le Top 10 côté pratique — chaque risque et sa parade principale :
| Risque | Parade principale |
|---|---|
| A01 Access control (IDOR) | Vérifier l’autorisation côté serveur à chaque requête |
| A02 Crypto failures | TLS partout ; mots de passe en bcrypt/argon2, jamais MD5 |
| A03 Injection (SQL/XSS) | Requêtes préparées ; échappement à l’affichage ; CSP |
| A04 Insecure design | Threat modeling, limites (rate limit, quotas) dès la conception |
| A05 Misconfiguration | Durcir les défauts, fermer les ports, headers de sécurité |
| A06 Composants vulnérables | npm audit, Dependabot, mises à jour régulières |
| A07 Authentification | MFA, rate limiting, sessions invalidées au logout |
| A08 Intégrité | Signer/vérifier ; ne jamais désérialiser de l’inconnu |
| A09 Logging | Logger les échecs d’auth et accès sensibles, alerter |
| A10 SSRF | Allowlist d’URLs sortantes, bloquer IPs privées et métadonnées cloud |
- IDOR (Insecure Direct Object Reference), le cas d’école du broken access control :
GET /api/invoices/1042→ l’utilisateur essaie1043et lit la facture d’un autre. Le serveur vérifiait l’authentification (qui vous êtes) mais pas l’autorisation (ce à quoi vous avez droit). Parade : à chaque requête, vérifier que la ressource appartient bien à l’utilisateur courant. - Broken authentication : autoriser le brute force (pas de rate limiting), accepter
123456, stocker les mots de passe en clair ou en MD5, ne pas invalider les sessions. Parade : bcrypt/argon2 (lents par conception), rate limiting, MFA. - SSRF (Server-Side Request Forgery) : une fonctionnalité « télécharger depuis une URL » détournée vers
http://169.254.169.254/(métadonnées cloud, credentials AWS) ou un service interne. Le serveur a des accès réseau que l’attaquant n’a pas — il le transforme en proxy. Parade : allowlist de destinations, blocage des plages IP privées. - Security misconfiguration, la plus banale : mot de passe par défaut sur une console d’admin, page de debug en prod, stack traces détaillées renvoyées au client, S3 bucket public, CORS
*avec credentials.
💡 Réflexe transversal — en entretien, chaque parade peut se reformuler avec la même grille : où est la frontière de confiance, qu’est-ce qui la traverse, est-ce validé côté serveur ? Montrer cette grille vaut mieux que réciter dix noms.
En entretien
« C’est quoi une injection SQL et comment s’en protéger ? » — L’entrée utilisateur concaténée dans une requête est interprétée comme du SQL (' OR '1'='1' -- court-circuite un login). Protection : requêtes préparées — code et données transmis séparément, la valeur n’est jamais interprétée. Les ORM le font par défaut. L’échappement manuel n’est pas une défense fiable.
« Différence entre authentification et autorisation ? » — Authentification : prouver qui vous êtes (login, session, token). Autorisation : vérifier ce à quoi vous avez droit. L’IDOR est l’exemple parfait de la deuxième oubliée : connecté, donc « légitime », mais sur la ressource d’un autre.
« C’est quoi une faille XSS ? » — De l’injection côté client : du contenu utilisateur rendu comme HTML/JS et exécuté dans le navigateur des autres (vol de cookies de session, actions en leur nom). Parade : échappement à l’affichage (par défaut dans React/Vue), pas d’innerHTML sur de la donnée utilisateur, CSP en filet de sécurité.
« La validation JavaScript côté client suffit-elle ? » — Non, jamais : le client est sous le contrôle de l’attaquant (curl, proxy, DevTools). La validation front améliore l’UX ; la sécurité se joue exclusivement côté serveur. Réponse à donner sans hésitation — c’est une question éliminatoire.
« C’est quoi une SSRF ? » — Faire faire au serveur une requête qu’il est le seul à pouvoir faire : services internes, localhost, métadonnées cloud (169.254.169.254). Classique dès qu’une feature accepte une URL. Parade : allowlist et blocage des IP privées.
Pièges & idées reçues
🎤 En entretien — ne récitez pas le Top 10 comme une liste de courses. Choisissez-en deux ou trois (injection, IDOR, XSS), expliquez l’attaque et la parade avec un mini-exemple. Un candidat qui montre le mécanisme sur un cas vaut dix candidats qui énumèrent des sigles.
- « Mon ORM me protège de tout » — des injections SQL, oui, par défaut… sauf les méthodes
rawavec concaténation. Et l’ORM ne protège ni de l’IDOR, ni du XSS, ni de la misconfiguration. - « HTTPS sécurise mon site » — TLS chiffre le transport. Une injection SQL passe très bien dans un tunnel chiffré. HTTPS est nécessaire, pas suffisant.
- « Échapper les caractères dangereux suffit contre l’injection SQL » — l’échappement manuel est fragile (encodages, cas limites) ; les requêtes préparées règlent le problème structurellement. C’est la réponse attendue.
- « La sécurité, c’est pour la prod, on verra plus tard » — les credentials commités dans Git, le bucket public et le port de debug exposé arrivent justement « en attendant ». Le Top 10 s’applique dès le premier commit.
- Hasher ≠ chiffrer : un mot de passe se hashe (bcrypt/argon2, irréversible, lent par conception), il ne se chiffre pas et ne se « décrypte » pas. Confondre les deux en entretien fait très mauvais effet.
Pour aller plus loin
- OWASP Top 10 (2021) : la référence, avec exemples et parades pour chaque catégorie
- OWASP Cheat Sheet Series : fiches pratiques par sujet (SQL Injection Prevention, XSS Prevention, Authentication…)
- PortSwigger Web Security Academy : labos gratuits et interactifs pour pratiquer chaque attaque — la meilleure préparation possible
- Exercice : reprendre un de vos projets et auditer trois points — requêtes SQL paramétrées ? autorisation vérifiée sur chaque endpoint ? secrets hors du repo Git ?
The essentials
OWASP (Open Worldwide Application Security Project) publishes the Top 10: the reference ranking of web application security risks. The 2021 edition, one line each:
- A01 Broken Access Control — users access what isn’t theirs (number one, and the most frequently found).
- A02 Cryptographic Failures — sensitive data poorly encrypted, in cleartext, or using obsolete algorithms (MD5, SHA1 for passwords).
- A03 Injection — user data interpreted as code: SQL, shell commands, and XSS now belongs here too.
- A04 Insecure Design — the flaw is in the design itself (no attempt limits, bypassable business logic), not in the code.
- A05 Security Misconfiguration — configuration defects: default credentials, exposed stack traces, open ports, missing headers.
- A06 Vulnerable Components — outdated vulnerable dependencies (the
npm auditeveryone ignores). - A07 Identification & Authentication Failures — broken sessions and authentication: brute force possible, weak passwords accepted.
- A08 Software & Data Integrity Failures — blind trust in unverified data or code (compromised CI/CD, deserialization).
- A09 Logging & Monitoring Failures — the attack succeeds and nobody sees it, for lack of logs and alerts.
- A10 SSRF — the server is manipulated into making requests to internal targets only it can reach.
The common thread through almost the entire Top 10 fits in one rule: never trust user input. Any data coming from the client — URL parameter, request body, header, cookie — is potentially hostile, and validation must happen server-side, always.
How it works
An injection always exploits the same confusion: the application builds a string (SQL query, shell command, HTML) by concatenating user data into it, and the interpreter on the other side cannot tell data from code.
Input : ' OR '1'='1' --
│
▼ naive concatenation
SELECT * FROM users
WHERE email = '' OR '1'='1' --' AND pw = '…'
│
▼ the SQL interpreter runs ALL of it
→ the condition is always true
→ authentication bypassed
The defense is not escaping quotes by hand, it’s structurally separating code from data: prepared statements. The query (the code) is sent first; the values (the data) travel separately and are never interpreted.
// ❌ VULNERABLE: user input becomes SQL code
const rows = await db.query(
`SELECT * FROM users WHERE email = '${req.body.email}'`
);
// email = "' OR '1'='1' --" → the whole table comes back
// ✅ PREPARED STATEMENT: the value stays a value, whatever it contains
const rows = await db.query(
"SELECT * FROM users WHERE email = $1", // the code, frozen
[req.body.email] // the data, never interpreted
);
// ORMs (Prisma, Sequelize…) do this by default — unless you use
// their "raw" methods with string concatenation.
Same family, other interpreters:
- Command injection —
exec("ping " + userInput)withuserInput = "8.8.8.8; rm -rf /". Defense: don’t go through a shell (execFilewith separate arguments), strict allowlist. - XSS (Cross-Site Scripting) — client-side injection: HTML/JS injected into the page and executed in other users’ browsers (session theft, actions on their behalf). Defense: escape on output (modern frameworks do it by default — never bypass with
dangerouslySetInnerHTML/innerHTMLon user data), plus a Content Security Policy as defense in depth.
⚠️ Front-end validation is not security — a
requiredattribute, a regex pattern or a disabled button on the client side is UX. Anyone bypasses the front-end withcurlor by editing the DOM. The only validation that counts for security is the server’s; the front-end’s is just comfort for the honest user.
Key concepts to master
The Top 10 in practice — each risk and its main countermeasure:
| Risk | Main countermeasure |
|---|---|
| A01 Access control (IDOR) | Check authorization server-side on every request |
| A02 Crypto failures | TLS everywhere; passwords in bcrypt/argon2, never MD5 |
| A03 Injection (SQL/XSS) | Prepared statements; output escaping; CSP |
| A04 Insecure design | Threat modeling, limits (rate limit, quotas) from day one |
| A05 Misconfiguration | Harden defaults, close ports, security headers |
| A06 Vulnerable components | npm audit, Dependabot, regular updates |
| A07 Authentication | MFA, rate limiting, sessions invalidated on logout |
| A08 Integrity | Sign/verify; never deserialize the unknown |
| A09 Logging | Log auth failures and sensitive access, alert |
| A10 SSRF | Allowlist outbound URLs, block private IPs and cloud metadata |
- IDOR (Insecure Direct Object Reference), the textbook case of broken access control:
GET /api/invoices/1042→ the user tries1043and reads someone else’s invoice. The server checked authentication (who you are) but not authorization (what you’re entitled to). Defense: on every request, verify the resource belongs to the current user. - Broken authentication: allowing brute force (no rate limiting), accepting
123456, storing passwords in cleartext or MD5, not invalidating sessions. Defense: bcrypt/argon2 (slow by design), rate limiting, MFA. - SSRF (Server-Side Request Forgery): a “download from URL” feature redirected to
http://169.254.169.254/(cloud metadata, AWS credentials) or an internal service. The server has network access the attacker doesn’t — they turn it into a proxy. Defense: destination allowlist, blocking private IP ranges. - Security misconfiguration, the most mundane: default password on an admin console, debug page in production, detailed stack traces returned to the client, public S3 bucket, CORS
*with credentials.
💡 Cross-cutting reflex — in an interview, every countermeasure can be rephrased through the same grid: where is the trust boundary, what crosses it, is it validated server-side? Showing that grid beats reciting ten names.
In an interview
“What is SQL injection and how do you protect against it?” — User input concatenated into a query gets interpreted as SQL (' OR '1'='1' -- short-circuits a login). Protection: prepared statements — code and data sent separately, the value is never interpreted. ORMs do it by default. Manual escaping is not a reliable defense.
“Difference between authentication and authorization?” — Authentication: proving who you are (login, session, token). Authorization: checking what you’re entitled to. IDOR is the perfect example of the second one forgotten: logged in, therefore “legitimate”, but on someone else’s resource.
“What is an XSS flaw?” — Client-side injection: user content rendered as HTML/JS and executed in other users’ browsers (session cookie theft, actions in their name). Defense: output escaping (default in React/Vue), no innerHTML on user data, CSP as a safety net.
“Is client-side JavaScript validation enough?” — No, never: the client is under the attacker’s control (curl, proxy, DevTools). Front-end validation improves UX; security happens exclusively server-side. Answer without hesitation — this one is eliminatory.
“What is SSRF?” — Making the server issue a request only it can make: internal services, localhost, cloud metadata (169.254.169.254). Classic as soon as a feature accepts a URL. Defense: allowlist and blocking private IPs.
Pitfalls & misconceptions
🎤 In an interview — don’t recite the Top 10 like a shopping list. Pick two or three (injection, IDOR, XSS), explain the attack and the defense with a mini-example. One candidate who shows the mechanism on a case is worth ten who enumerate acronyms.
- “My ORM protects me from everything” — from SQL injection, yes, by default… except the
rawmethods with concatenation. And the ORM protects neither from IDOR, nor XSS, nor misconfiguration. - “HTTPS secures my site” — TLS encrypts the transport. A SQL injection travels perfectly well through an encrypted tunnel. HTTPS is necessary, not sufficient.
- “Escaping dangerous characters is enough against SQL injection” — manual escaping is fragile (encodings, edge cases); prepared statements solve the problem structurally. That’s the expected answer.
- “Security is for production, we’ll see later” — credentials committed to Git, the public bucket and the exposed debug port happen precisely “in the meantime”. The Top 10 applies from the first commit.
- Hashing ≠ encrypting: a password is hashed (bcrypt/argon2, irreversible, slow by design), it is not encrypted and cannot be “decrypted”. Confusing the two in an interview leaves a very bad impression.
Going further
- OWASP Top 10 (2021): the reference, with examples and countermeasures for each category
- OWASP Cheat Sheet Series: practical sheets by topic (SQL Injection Prevention, XSS Prevention, Authentication…)
- PortSwigger Web Security Academy: free interactive labs to practice each attack — the best possible preparation
- Exercise: take one of your projects and audit three points — parameterized SQL queries? authorization checked on every endpoint? secrets out of the Git repo?