Les bonnes pratiques de sécurité pour les développeurs web : le guide essentiel

Une apostrophe mal filtrée a suffi à vider toute une base de données. Injection SQL, authentification fragile, secrets exposés : les failles qui font les gros titres sont presque toujours des oublis basiques. Voici les réflexes à intégrer.

Les bonnes pratiques de sécurité pour les développeurs web : le guide essentiel

Un jour, un client m'appelle, paniqué : sa boutique en ligne affiche une page de rançon. Trois semaines plus tôt, il m'avait demandé de « juste ajouter un formulaire de contact » sur un site qu'il gérait lui-même. Le formulaire envoyait les données directement dans une requête SQL concaténée. Il aura suffi d'un champ nom rempli avec une apostrophe et un UNION SELECT pour que la base entière soit aspirée. Le correctif a pris vingt minutes. La restauration des données, quatre jours.

Ce genre d'histoire, vous en entendrez d'autres. La sécurité web ne se joue presque jamais sur des exploits de génie. Elle se joue sur des oublis basiques répétés à l'échelle d'un projet. Et pour un développeur, la bonne nouvelle, c'est que la majorité des failles qui font les gros titres sont connues, documentées, et évitables avec quelques réflexes intégrés au bon moment du cycle de dev.

Voici ce que j'applique sur mes propres projets, ce qui a marché, ce qui m'a fait perdre du temps, et où je place encore mal mon curseur après des années à coder.

Points clés à retenir

  • La majorité des failles critiques en production viennent de trois familles : injection, mauvaise gestion de l'authentification, secrets exposés.
  • Valider une entrée côté client ne sert à rien pour la sécurité : tout contrôle doit être refait côté serveur.
  • Hacher les mots de passe avec bcrypt ou argon2, jamais MD5 ni SHA-1, même « salé ».
  • Les dépendances tierces représentent souvent la plus grosse surface d'attaque d'un projet moderne.
  • Intégrer les scans de sécurité dans la CI coûte moins cher que de tout rattraper avant une mise en production.
  • Le RGPD impose une approche « privacy by design » qui rejoint les bonnes pratiques techniques plutôt qu'elle ne s'y oppose.

Les failles qui reviennent toujours sur les sites web

Si vous ne devez retenir qu'une seule ressource pour prioriser votre travail, c'est le Top 10 de l'OWASP. Ce n'est pas une liste exotique : c'est le catalogue des erreurs que l'on retrouve dans à peu près toutes les applications web compromises.

Injection SQL et XSS : les deux vieilles dames qui refusent de partir

L'injection SQL fonctionne parce qu'un développeur a construit une requête en concaténant une chaîne avec une entrée utilisateur. Ça paraît naïf en 2026, et pourtant : les revues de code que je fais pour des clients montrent encore régulièrement des query("SELECT * FROM users WHERE id = " + id) dans des scripts oubliés, souvent écrits il y a cinq ou six ans et jamais retouchés.

La parade est simple et n'a pas changé : requêtes préparées, systématiquement, sans exception. Pas de « c'est un champ numérique donc pas besoin ». Une regex de validation sur un identifiant, ça casse. Un paramètre lié, ça ne casse pas.

Côté navigateur, le XSS est le cousin. Le navigateur fait confiance au JavaScript qu'on lui envoie ; si votre application réinjecte du contenu utilisateur sans échappement, vous offrez un porte-voix à l'attaquant. Deux réflexes : échapper en sortie selon le contexte (HTML, attribut, URL, JavaScript), et poser une politique de sécurité de contenu (CSP).

Sur un projet, j'ai mis six mois à déployer une CSP stricte. J'ai commencé par Content-Security-Policy: default-src 'self' en mode rapport seulement. J'ai vu passer les alertes pendant des semaines. Puis j'ai resserré progressivement. Le jour où je suis passé en mode blocage, plus rien ne cassait. Trois semaines de rodage, zéro incident.

Authentification et sessions : là où les fuites se produisent vraiment

Trois règles que je ne négocie plus :

  1. Les mots de passe sont hachés avec argon2id ou bcrypt, jamais stockés en clair, jamais « chiffrés » réversiblement.
  2. Les cookies de session sont marqués HttpOnly, Secure et SameSite=Lax (ou Strict selon le contexte).
  3. Le JWT ne contient aucune donnée sensible et sa signature est vérifiée à chaque requête, y compris alg pour éviter l'attaque par confusion d'algorithme.

J'ai longtemps cru que le JWT était plus « moderne » que les sessions serveur, et donc mieux. Franchement, non. Pour la plupart des applications web classiques, une session serveur avec un cookie opaque est plus simple à raisonner et à révoquer. Le JWT a sa place, mais si vous ne savez pas exactement pourquoi vous l'utilisez, vous vous compliquez la vie pour rien.

Valider les entrées, protéger les secrets, surveiller les dépendances

Un projet que j'ai repris l'an dernier avait un fichier .env versionné dans Git. Avec une clé Stripe en production. Et un accès S3. Le dépôt était public. Je ne sais pas combien de temps ça a duré avant que je le voie, et je préfère ne pas le savoir.

Valider les entrées, protéger les secrets, surveiller les dépendances

Validation des entrées : le serveur ne fait confiance à personne

La règle est brutale mais utile : tout ce qui vient de l'extérieur est hostile jusqu'à preuve du contraire. Le JavaScript côté client valide pour le confort de l'utilisateur. Le serveur valide pour la sécurité. Ce sont deux jobs différents, sur deux couches différentes.

En pratique, je valide par whitelist plutôt que par blacklist. Une liste de ce qui est autorisé est plus facile à maintenir qu'une liste de ce qui est interdit, parce que les attaquants inventent de nouvelles formes plus vite que je ne peux les bannir.

Gestion des secrets : sortir du fichier .env

Un secret dans un dépôt Git, c'est un secret compromis dès qu'il est poussé. Même si vous supprimez le commit dans les minutes qui suivent, il a déjà été aspiré par au moins un bot qui scanne les dépôts. Rotation immédiate, sans négocier.

  • Coffre de secrets (Vault, AWS Secrets Manager, ou équivalent managé) plutôt qu'un fichier texte.
  • Secrets injectés comme variables d'environnement au runtime, pas dans le code.
  • Détection automatique dans la CI, avec un hook pre-commit qui bloque le push.
  • Rotation planifiée, pas seulement en cas d'incident.

Dépendances tierces : votre vraie surface d'attaque

Un projet Node.js ou Python moderne embarque plusieurs centaines de paquets transitifs. Une seule vulnérabilité dans un sous-paquet utilisé six niveaux plus bas peut compromettre votre application.

Je scanne avec les outils natifs de l'écosystème (npm audit, pip-audit, équivalents pour chaque langage) et j'ai arrêté de me voiler la face sur les alertes. Une alerte « critical » sur une dépendance utilisée en production, ce n'est pas quelque chose qu'on met dans un backlog pour « plus tard ». J'ai fait cette erreur une fois. Une fois.

Intégrer la sécurité dans la chaîne CI/CD

La sécurité déplacée à la fin du cycle, c'est la sécurité qui n'existe pas. Le développeur reçoit une liste de bugs deux jours avant la mise en production, corrige ce qu'il peut, le reste est reporté. Et le reste, c'est souvent le plus grave.

Intégrer la sécurité dans la chaîne CI/CD

Les outils qui trouvent des choses utiles

Type d'outil Ce qu'il détecte Quand le lancer
SAST (analyse statique) Motifs dangereux dans le code source : concaténation SQL, désérialisation non sécurisée À chaque commit, dans la CI
SCA (analyse des dépendances) Vulnérabilités connues dans les librairies tierces À chaque build, et une fois par jour
DAST (analyse dynamique) Failles visibles depuis l'extérieur, sur une application qui tourne Sur un environnement de recette avant mise en prod
Linters de sécurité Erreurs de syntaxe et pièges connus du langage Dans l'éditeur, en local

Mon combo préféré : un linter qui tourne dans l'éditeur, un SAST qui bloque la CI si une règle critique remonte, et un DAST manuel une fois par sprint sur les branches qui touchent à l'authentification.

Prioriser les correctifs : le vrai casse-tête

Tous les résultats d'un scan ne se valent pas. Un critical sur une dépendance utilisée uniquement en dev, c'est un faux positif de priorité. Un medium sur le chemin d'authentification, c'est une urgence déguisée.

Ma grille, en trois questions : le composant est-il exposé en production ? La faille est-elle exploitable sans authentification ? Le correctif casse-t-il autre chose ? Si la réponse est oui, oui, non, ça part en haut de la pile, immédiatement.

Le lien avec le RGPD : la conformité n'est pas une couche séparée

On m'a souvent présenté le RGPD comme une contrainte juridique qui viendrait se superposer aux bonnes pratiques techniques. Après plusieurs mises en conformité, je pense l'inverse : les obligations du RGPD sont des bonnes pratiques de sécurité, formulées avec un vocabulaire juridique.

Chiffrer les données personnelles sensibles, minimiser ce qu'on collecte, journaliser les accès aux données, pouvoir restaurer après incident, tester la sécurité avant mise en production. Ce sont exactement les recommandations qu'on retrouve dans les guides de la CNIL pour les développeurs. Elles recoupent à 90 % ce que dirait un bon architecte sécurité, sans même parler de loi.

Un angle qui manque souvent dans les discussions : la privacy by design n'est pas une étape après la conception. C'est un choix qui se prend au moment de modéliser la base de données, au moment de décider où sont stockés les logs, au moment d'écrire la première migration. Rétro-fitter la minimisation des données sur un schéma existant coûte dix fois plus cher que de la penser dès le départ.

Ce que je fais encore mal, après tout ce temps

Une confession utile : je sous-estime systématiquement le temps de réponse à incident. J'ai passé des heures à préparer des défenses préventives alors que je n'avais jamais écrit de procédure de restauration testée. Le jour où j'ai eu besoin de restaurer une base en production sous pression, je ne savais pas précisément combien de temps ça prendrait, ni si la dernière sauvegarde était intègre.

C'est con à dire, mais la meilleure décision de sécurité que j'ai prise ces dernières années n'est pas technique. C'est d'avoir écrit une procédure d'incident d'une page, imprimée, scotchée près de mon écran. Qui appeler, dans quel ordre, ce qu'on coupe en premier, comment on restaure. Trente minutes d'écriture qui valent plus que n'importe quel scanner.

La sécurité web n'est pas un état qu'on atteint, ni une checklist qu'on coche une fois. C'est une série de petits choix qu'on refait à chaque commit, à chaque nouvelle dépendance, à chaque nouvelle fonctionnalité. Certains coûtent du confort. La plupart coûtent cinq minutes et évitent quatre jours de restauration.

Et si vous ne savez pas par où commencer, ouvrez le Top 10 de l'OWASP, prenez la première catégorie, et regardez votre code. Pas tout le code. Juste le prochain fichier que vous allez écrire.

Adeline Perrin

Adeline Perrin

Adeline Perrin est une spécialiste reconnue du développement web, de l'architecture logicielle et des pratiques DevOps. Elle accompagne des équipes techniques dans la conception de systèmes robustes et évolutifs, en mettant l'accent sur l'automatisation et la qualité logicielle. Pédagogue et passionnée, elle partage volontiers son expérience pour aider les développeurs à monter en compétences.

Voir tous les articles →

Articles similaires