Zum Hauptinhalt springen

OWASP Top 10 en pratique : cinq erreurs qui compromettent une application web

· 4 Minuten Lesezeit
Haythem Rehouma
Formateur en cybersécurité offensive

Le OWASP Top 10 est utile parce qu'il classe les erreurs, pas parce qu'il les invente. Voici les cinq erreurs qui reviennent dans presque toutes les missions de pentest web que nous menons — avec des requêtes réelles et le code qui les corrige. Aucune n'est neuve. Toutes sont encore là.

1. Le contrôle d'accès repose sur le front-end (A01)

Le cas typique : une application cache un bouton « supprimer utilisateur » aux comptes non-admin, mais l'API accepte la requête si vous la rejouez à la main. La règle du front-end n'a jamais protégé personne.

Requête d'attaque :

POST /api/users/42/delete HTTP/1.1
Cookie: session=<un cookie standard, non-admin>

Réponse : 204 No Content. Compte supprimé. Aucun contrôle serveur.

Correction — Node/Express :

app.post('/api/users/:id/delete', requireAuth, requireRole('admin'), async (req, res) => {
await userService.delete(req.params.id, { by: req.user.id });
res.status(204).end();
});

Le contrôle doit être dans requireRole côté serveur. Le front peut cacher le bouton pour l'ergonomie, jamais pour la sécurité.

2. La requête SQL est construite par concaténation (A03)

Elle a disparu des cours il y a quinze ans, elle est encore dans le code hérité. Un exemple qu'on voit régulièrement :

$id = $_GET['id'];
$sql = "SELECT * FROM produits WHERE id = " . $id;
$result = mysqli_query($conn, $sql);

Requête d'attaque :

GET /produits?id=1%20UNION%20SELECT%20null,current_database(),null--

Correction — PHP / PDO :

$stmt = $pdo->prepare('SELECT * FROM produits WHERE id = :id');
$stmt->execute(['id' => $_GET['id']]);
$produit = $stmt->fetch();

La parade n'est pas « filtrer les caractères ». C'est le requêtage paramétré, dans tout langage, tout ORM, sans exception.

3. Les entrées sont assainies mais le contexte est ignoré (A03)

Une XSS moderne ne vient plus d'un alert(1) naïf, elle vient d'une donnée injectée dans un mauvais contexte — attribut, URL, JavaScript inline.

Ceci est vulnérable, même si vous appliquez htmlspecialchars :

<a href="{{ url_utilisateur }}">Voir</a>

Un attaquant met javascript:alert(1) : le HTML est propre, le contexte URL ne l'est pas.

Correction — filtrer selon le contexte :

function estUrlHttpSecuritaire(v) {
try {
const u = new URL(v);
return u.protocol === 'https:' || u.protocol === 'http:';
} catch { return false; }
}

Pour aller plus loin : une Content Security Policy stricte qui interdit l'inline JavaScript est la meilleure protection systémique.

4. Le SSRF est encore trivial dans les intégrations tierces (A10)

Application qui accepte une URL fournie par l'utilisateur pour aller chercher une image, un webhook, un fichier. La requête sort du serveur, souvent avec des privilèges internes.

Requête d'attaque, contre AWS EC2 :

POST /import HTTP/1.1
Content-Type: application/json

{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}

Le service de métadonnées d'instance renvoie des identifiants temporaires. En moins d'une minute, l'attaquant s'authentifie en AWS avec le rôle de la machine.

Correction :

  • Interdire les IP privées et de bouclage côté serveur, avant toute requête sortante.
  • Passer par un proxy sortant contrôlé (par exemple smokescreen).
  • Utiliser IMDSv2 en AWS (sinon considérez que vos rôles sont exposés).

5. Les mots de passe sont stockés « chiffrés », pas hachés (A02)

Un rappel qui devrait être inutile mais ne l'est pas : un mot de passe n'est pas chiffré, il est haché avec un algorithme conçu pour ça. AES sur un mot de passe est une erreur, sha256 aussi, md5 est un crime.

Ce qu'il faut :

from argon2 import PasswordHasher

ph = PasswordHasher()
empreinte = ph.hash(mot_de_passe) # à stocker en base
ph.verify(empreinte, mot_de_passe) # à la connexion

Argon2id est le standard actuel (2026). bcrypt reste acceptable. scrypt aussi. Tout ce qui n'est pas dans cette liste doit être remplacé, y compris les hachages « avec sel » basés sur SHA-256.

Le fil rouge

Les cinq erreurs se ressemblent : l'application fait confiance à un endroit qu'elle ne devrait pas — front-end, chaîne construite, URL brute, contexte, algorithme. Chaque contrôle doit être posé au bon niveau, celui que l'attaquant ne peut pas contourner.


Le OWASP Top 10 en pratique : c'est la semaine 7 de notre cours gratuit Tests d'intrusion. On y exploite chaque erreur ci-dessus, on écrit la remédiation, et on rédige les constats comme un rapport professionnel.