WeLoveDevs.com

OWASP Top 10 : 10 erreurs que les développeurs web font tous les jours (et comment les éviter)

L’OWASP Top 10, c’est un outil pour les développeurs web. Et pourtant, il est largement sous-utilisé.

Déjà, il faut dire que c’est un peu abstrait : dix grandes familles de vulnérabilités, rédigées dans un langage de cyber analyste. Tu vois le genre : pantalon cargo, capuche noire, ambiance Mr Robot.

Et surtout, on ne te le présente jamais comme un guide pour t’aider à faire mieux. Non, on te le ressort quand tu as déjà fait l’erreur.
“Bah c’était dans l’OWASP TOP 10, tu l’as pas lu ou quoi ?”

Alors aujourd’hui, on va reprendre la main.

Voici un guide pratique de l’OWASP Top 10, pensé pour les développeurs web.
Dix familles, dix erreurs qu’on commet tous sans s’en rendre compte, et des exemples concrets pour les éviter dès le code.

A01 Broken Access Control : C’est le devis d’un autre client, ça ?

Le dev a livré une “petite feature” entre deux réunions. “Il faudrait que les clients puissent voir leurs devis directement sur le portail”.
Auth ok, session ok, une page qui liste les devis, et un lien qui ouvre /devis/142.
Tout semble sécurisé.

Un client remplace 142 par 143.
Il tombe sur le devis d’un autre. Même page, même format.
Pire, il voit une remise de 10 % accordée au concurrent. Négociation immédiate. Le commercial passe pour un clown et il comprend bien que le client a perdu la confiance.

C’est un IDOR. La session est valide, mais la page /devis/:id ne vérifie pas que la ressource appartient bien à l’utilisateur. Le code a fait confiance au contexte précédent. 

Hardening : comment éviter IDOR ?

  • L’autorisation se fait au point d’accès. Le serveur qui donne la page /devis/:id, doit vérifier. Même s’il y a un middleware avant. On ne fait pas confiance à un autre tiers.
  • La sécurité peut se faire au niveau du SGBD. Un document qui ne t’appartient pas ? Tu ne peux même pas le sortir. Si dispo, activer des règles de lignes côté SGBD (RLS Supabase, règles Firebase) pour empêcher les fuites silencieuses.
  • Les identifiants incrémentaux c’est non. Utiliser des UUID et/ou un slug et résoudre côté serveur le bon enregistrement à partir de la session.

A02 Cryptographic Failures : C’est le mot de passe de l’utilisateur, ça ?

J’interviens pour la première fois sur une appli en TMA.
Le backend est propre : bcrypt pour hasher et saler les mots de passe, HTTPS activé, rien à signaler côté serveur.
Côté client, la page de login a été pénible à faire : le serveur n’est pas standard, ça ressemble à OAuth mais ce n’est pas carré.

Dans la console, je lis :

Login attempt - identifiant: marcel@welovedevs.com / password: actualpasswordenclair

Le dev est encore sur le plateau. Je prends mon MacBook et je vais lui montrer.
“Mais normalement les logs ne sont pas activés en prod.” 😱
Sauf que si. Ils le sont. Et on ne doit jamais faire confiance à un présupposé. On supprime le log, on nettoie la config, et il ne le refera plus.

C’est exactement A02 – Cryptographic Failures : un secret AWS qui fuite sur GitHub,  un mot de passe qui transite ou s’affiche en clair, ou un chiffrement absent là où il devait être.

Pas de hardening magique, juste de l’hygiène au quotidien.

A03 Injection : j’arrive plus à accéder à mon profil !

Sur les premières versions de WeLoveDevs, pas de panique côté SQL, on tournait NoSQL. Les injections NoSQL ça n’avait pas encore été inventé.

Mais très vite, les premiers devs se sont amusés à injecter du CSS dans leurs profils. C’était pas très malin, surtout pour défacer son propre profil. Surtout quand le dev vient me demander ensuite d’aller chercher dans les sauvegardes de la bdd pour restaurer son profil.

Mais surtout il aurait pu faire pire.
Imagine : un script injecté qui lit le localStorage du recruteur de passage, récupère une info sensible et la poste vers un service tiers. Simple, silencieux, efficace.

C’est bien l’esprit d’OWASP Top 10 “A03”, pas seulement le SQL, mais toute exécution de contenu contrôlé par l’utilisateur. HTML, CSS, Markdown, tout peut devenir vecteur.

On a appris vite : chaque champ utilisateur qui est rendu doit être nettoyé.
Hardening express

  • Sanitize systématiquement le HTML et le Markdown avec une librairie reconnue, par exemple DOMPurify.
  • Échapper tout texte avant affichage, ne pas utiliser d’inserts bruts.
  • Utilise un ORM moderne qui s’occupe de protéger toutes les requêtes pour toi.

A04 Insecure Design : 2000 leads par heure ?

On a fait un formulaire vite fait dans WordPress. Les clients peuvent joindre un fichier avec leur brief, c’est un champ standard, facile à ajouter.
Avant même le premier prospect, des robots arrosent le formulaire d’injection et d’uploads fantaisistes. Le soir, des scripts kiddies jouent à défacer les sites webs et ils connaissent bien notre plugin de formulaire.

Le système de fichier upload est bien isolé mais il prend 13 Go de fichiers dans la nuit. La BDD faisait 20mo hier, elle fait 2Go ce matin. Mais surtout on avait des notifs emails.
Les commerciaux ont tous 2000 emails par heure. Et l’inquiètude d’un vrai prospect coincé sous la pile.

Le code n’a pas “buggé”. Il a fait exactement ce qu’on lui a demandé. Le défaut est dans le design: un flux sans garde-fous. C’est précisément A04 Insecure Design.

Hardening express

  • Mettre un captcha sur tous les formulaires publics
  • Rate-limiting par défaut sur toutes les routes. Et sur les notifications par email.

A05 Security Misconfiguration : il se passe quoi si on met alg “none” dans ton JWT ?

J’ai un petit jeu avec les devs Java Spring. Je leur demande : “Que se passe-t-il si on met alg: « none » dans la signature du JWT ?”

Souvent, ils ne me croient pas, mais ils essaient tout de suite. Dans plusieurs configs Spring Security par défaut, la librairie ne bloque pas automatiquement ce cas-limite. La doc explique qu’il faut implémenter correctement le truc. Sauf que si tu le fais pas, ça compile quand même. Et l’appli passe en recette etc… 

Ici c’est pas le dev qui a fait une faille d’auth. C’est la config par défaut qui est permissive. C’est exactement A05, Security Misconfiguration : le framework, la librairie ou le serveur a un réglage par défaut trop laxiste, et on hérite de la vulnérabilité sans s’en apercevoir.

Hardening express

  • Ne faites jamais confiance à un framework auth / sécu.
  • Utiliser un SAST pour détecter les mauvaises configuration (souvent une option sur votre CI/CD Github Advanced Security par exemple)
  • Scanner les dépendances et les garder à jour. Ce qui m’amène au point 06.

A06 Vulnerable and Outdated Component : c’est quoi la version d’Ubuntu sur ce Docker ?

Cette famille de vulnérabilités regorge d’exemples célèbres. Log4J, pour les devs Java, c’était le ragnarok. Côté NPM, on voit régulièrement passer une dépendance qui installe un cryptominer ou un voleur de secrets.

Mais le plus souvent, c’est plus discret que ça.
Les SRE ont bien mis à disposition une belle infrastructure à jour. Sauf que les devs ont encapsulé leur app dans un Docker random. L’image n’est pas renforcée. Le Dockerfile charge un Ubuntu quelconque, et personne n’y prête attention. Trois ans plus tard, cette base a 33 CVE référencées.

Il n’y a pas de quick win magique ici. C’est une question d’hygiène logicielle.
C’est là qu’entre en jeu le SBOM – Software Bill of Materials.
Imaginez un document qui liste toutes les dépendances de votre projet : package.json, pom.xml, Dockerfile, tout en même temps. Quand une faille sort, le SBOM te dit immédiatement si tu es concerné. Il y a des éditeurs qui proposent des outils pour les construire et les surveiller automatiquement.

A07 Identification and Authentication Failures : elle sert à quoi l’API_KEY ?

Aujourd’hui, les frameworks modernes gèrent très bien l’authentification entre le client et le serveur.
Mais avant, c’était plus artisanal. Imagine : un serveur en PHP vanilla, un front en Backbone.js.
Synchroniser des sessions entre deux applis, c’était galère.

Alors, pour “protéger un peu”, le dev ajoute une clé magique :

const API_KEY = « lsqldklqsd »;

Elle est utilisée côté client et vérifiée côté serveur, histoire d’être sûr que “seul le bon front appelle l’API”.

Sauf qu’un secret côté client n’est pas un secret.
Que ce soit une appli web dont le code est lisible, ou un client lourd qu’on peut désassembler, tout le monde peut récupérer la clé et se faire passer pour le front.

Ce n’est pas une A01 Broken Access : ici, c’est l’authentification elle-même qui est cassée.
OWASP Top 10 “A07”, c’est aussi les tokens JWT qui n’expirent jamais, les cookies valides sur plusieurs applis, et les sessions qui survivent au logout ou au changement de mot de passe.

Hygiène minimum : utiliser des frameworks modernes qui gèrent ça out-of-the-box. OAuth, OpenID Connect, PKCE… des standards ouverts, documentés et sécurisés. On ne s’en passe plus.

A08 Software and Data Integrity Failures : la dépendance qu’on a hardlinkée “juste pour que ça marche”.

J’ai voulu toucher un vieux projet encore en prod. Le build ne passe plus. Une dépendance n’est plus disponible.
Sur un projet iOS, ça peut être un Cocoapod disparu. En Ruby, une gem retirée du registre. En JavaScript, un package npm décommissionné.

Sur Stack Overflow, quelqu’un propose une astuce : un miroir GitHub à hardlinker. Un autre lien redirige vers un repo “temporaire”, hébergé par un inconnu.

Parfois, c’est même un bon plan qu’un collègue te glisse à la pause-café :

“Tu veux pas payer la licence du plugin WordPress ? J’ai une copie ici, tire-la depuis mon repo.” Super sympa, le copain.

Mais ces sources peuvent être empoisonnées ou corrompues.
C’est exactement A08 – Software and Data Integrity Failures : ton projet fait confiance à du code que tu n’as pas vérifié.

Le SBOM aide à garder une trace claire de toutes les dépendances, mais l’hygiène va plus loin.
Vérifie les signatures, les checksums des artefacts de build et les sources de téléchargement avant chaque exécution.

A09 Security Logging and Monitoring Failures : qui a lu les logs ?

Les attaquants se sont adaptés. On imagine souvent un braquage en plein jour, façon film de casse.
Mais la réalité, c’est l’APT : Advanced Persistent Threat.
Un attaquant silencieux, patient, qui exfiltre les données doucement, sans se faire remarquer.
Il sort les informations personnelles une à une, envoie les fichiers clients vers ses serveurs d’extorsion.

Le jour où la rançon tombe, c’est la panique. Le firewall est saturé de logs… mais ils ne couvrent que les 14 derniers jours. Impossible de savoir quand l’attaque a commencé ni ce qui a été volé. 

Une APT est généralement détectée sous 8 à 13 jours (Sophos Active Adversary 24/25).
Mais si personne ne regarde les logs, vous le découvrirez avec un peu de chance en revenant des vacances de Noël.

Le problème ?
Personne ne lit les logs.
Parce qu’ils ne sont pas centralisés, ou parce qu’ils ne servent à rien.

En tant que développeur, ton rôle est simple :

  • Produire des logs utiles et précis : erreurs, accès, actions critiques.
  • Les stocker au bon endroit, de façon centralisée, pour qu’ils soient lisibles et exploitables.

Comment savoir que c’est bien fait ?
Chaque ticket support doit pouvoir s’appuyer sur un log pertinent.
Et chaque accès à une donnée sensible doit être tracé.

L’étape d’après, c’est le SIEM : un centre de contrôle qui agrège tous les événements des serveurs, agents et applications.
Il permet de détecter les incidents avant qu’il ne soit trop tard. C’est le principal outil d’une équipe de sécurité opérationnelle également appelée SOC.

A10 SSRF : le champ URL qui te fait requêter des choses illicites.

Sur un site comme le nôtre, c’est très courant de demander des URLs. C’est un annuaire. On va demander l’URL du site carrière, l’URL du compte instagram ou autre.

Sauf que ce champ est particulièrement sensible à l’injection. Parce que notre serveur va ensuite faire des requêtes basées sur cet URL. Par exemple, on peut aller chercher le logo de l’entreprise sur le site web ou via un service tiers.

On peut se retrouver assez rapidement à spammer un autre site web. Le lendemain on reçoit un mail de plainte parce qu’un site web à l’autre du monde a reçu des centaines de requêtes provoquées par un utilisateur chez nous. Mais le pire c’est l’exfiltration.

Sur AWS, le Server Side Request Forgery peut faire exfiltrer ton IAM. L’exploitant pourra retourner ton infrastructure ou provisionner des ressources dont il a besoin, à tes frais.

Hardening express

  • Autoriser seulement http/https et canonicaliser l’URL.
  • Refuser IP privées/link-local après résolution DNS.
  • Whitelist/regex par champ (LinkedIn only, etc.).
  • En dernier recours : ouvrir le lien dans un environnement sécurisé “Sandbox”

Conclusion – On en apprend tous les jours avec Owasp Top 10 ?

Je tiens à mettre l’emphase sur une hygiène quotidienne en matière de sécurité. 

C’est comme le RGPD, ça concerne tout le monde dans l’équipe. Si c’est juste un développeur ou une développeuse qui a la maîtrise complète du sujet c’est pas efficace. Il faut que tout le monde se sente concerné et cherche à en apprendre tous les jours. 

Et OWASP Top 10 est un référentiel, une base de connaissance sur le sujet. C’est un outil qui nous permet d’en apprendre plus chaque jour.
J’espère que cet article vous aura mis le pied à l’étrier pour y retourner. 👌

Damien Cavaillès

Recent Posts

On accueille le nouveau CTO 🎉

Un nouveau capitaine technique débarque à la barre de WeLoveDevs ! Après le rachat par…

6 jours ago

AI Act for Developers : comprendre les 5 niveaux de risques

L’AI Act pour les développeurs, c’est la première loi vraiment impactante depuis le RGPD. Et…

2 semaines ago

Angular, mais en mode « easy » : interview avec Gaetan Redin.

"Venez, faites le module 1 et on en reparle." C’est le défi lancé par Gaetan…

3 semaines ago

RGPD pour les développeurs : coder la confiance avant tout.

Dans cet article, on va parler du RGPD pour les développeurs. C’est un sujet que…

1 mois ago

Monolithe vs Microservices : comment choisir la bonne architecture pour votre application ?

En 2025, le débat monolithe vs microservices n’est toujours pas tranché. Faut-il garder une architecture…

1 mois ago

Déminer l’objection « tu sais pas coder sans IA » en entretien.

"Tu sais pas coder sans IA." C’est devenu la nouvelle phrase passive-agressive des entretiens tech.…

2 mois ago