Sécurité web : bonnes pratiques couche par couche (2026)

Point clé

La sécurité web se construit par couches : verrouillez le domaine et le DNS (registrar lock, DNSSEC, CAA), imposez un TLS moderne avec HSTS, envoyez un ensemble strict d'en-têtes de sécurité HTTP, hachez les mots de passe avec Argon2id derrière la MFA et la limitation de débit, validez les entrées et appliquez le contrôle d'accès côté serveur, épinglez et auditez les dépendances, fermez chaque port que vous n'utilisez pas et journalisez suffisamment pour repérer une intrusion. Chaque pratique ci-dessous est accompagnée de la configuration exacte et d'un moyen gratuit de vérifier qu'elle est réellement en place, car un contrôle que vous n'avez pas testé est un contrôle que vous n'avez pas.

Vérifiez maintenant

Sécurité web en six couches : domaine et DNS, TLS, en-têtes HTTP, application, dépendances et serveur
Sécurité web en six couches : domaine et DNS, TLS, en-têtes HTTP, application, dépendances et serveur
Commencer la lecture
  1. Ce que recouvre vraiment la sécurité web
  2. La pile de sécurité web : six couches à protéger
  3. Couche 1 : verrouiller le domaine et le DNS
  4. Couche 2 : HTTPS et TLS bien configurés
  5. Couche 3 : en-têtes de sécurité HTTP
  6. Couche 4 : une authentification qui résiste au credential stuffing
  7. Sessions, cookies et CSRF
  8. Injection et XSS : valider les entrées, encoder les sorties
  9. Broken Access Control : le risque numéro un
  10. Couche 5 : dépendances et chaîne d'approvisionnement logicielle
  11. Couche 6 : durcissement du serveur (ports, correctifs, secrets, sauvegardes)
  12. Authentification des e-mails : SPF, DKIM et DMARC
  13. Journaliser, surveiller et anticiper l'intrusion
  14. Tester : scanners, tests d'intrusion et contrôles continus
  15. La checklist de sécurité web
  16. Correspondance avec l'OWASP Top 10:2025
  17. FAQ sur la sécurité web

Ce que recouvre vraiment la sécurité web

Les bonnes pratiques de sécurité web désignent l'ensemble des contrôles qui empêchent un site ou une application web d'être piraté, défiguré, utilisé pour attaquer ses propres visiteurs ou discrètement vidé de ses données. Il ne s'agit ni d'un produit unique ni d'un simple réglage, mais d'une pile de décisions qui commence chez le registrar du domaine et traverse le DNS, le TLS, les en-têtes HTTP envoyés par votre serveur, le code qui gère les connexions et les entrées utilisateur, les paquets tiers sur lesquels vous bâtissez, le serveur lui-même et, pour finir, les journaux qui vous signalent qu'un problème est survenu.

La raison de penser en couches : les attaquants le font. Le 2026 Data Breach Investigations Report de Verizon, qui couvre plus de 22 000 violations de novembre 2024 à octobre 2025, a constaté que 31 % des violations ont commencé par l'exploitation d'une vulnérabilité logicielle, contre 20 % un an plus tôt et, pour la première fois, devant les identifiants volés (13 %), le phishing restant stable à 16 %. Un rançongiciel était présent dans 48 % des violations, contre 44 %. Un seul correctif manquant, une clé d'API qui fuite ou une page d'administration sans limitation de débit suffit. Aucune des mesures de ce guide n'est exotique ; les sites piratés sont généralement ceux qui ont négligé les bases sur une couche tout en peaufinant une autre.

Ce guide est organisé de l'extérieur vers l'intérieur. Chaque pratique vous dit pourquoi elle compte, quoi configurer exactement et comment la vérifier avec une commande ou un outil gratuit comme le Vérificateur d'en-têtes HTTP ou le Vérificateur SSL, car un réglage que vous croyez actif sans l'avoir jamais confirmé ne protège rien.

Check a site's security headers

La pile de sécurité web : six couches à protéger

Toute attaque contre un site web vise l'une de ces six couches. Le tableau ci-dessous sert de carte pour la suite du guide : ce que contient chaque couche, comment elle est généralement attaquée et quelle vérification gratuite confirme que votre défense est bien en place.

CoucheCe que font les attaquantsPratiques essentiellesVérifier avec
1. Domaine et DNSDétourner le domaine, modifier les serveurs de noms, s'emparer de sous-domaines orphelins, obtenir des certificats frauduleuxRegistrar lock, MFA, DNSSEC, CAA, audit des enregistrements obsolètesRecherche WHOIS, Test de santé DNS, Recherche de Sous-domaines
2. Transport (TLS)Rétrograder vers HTTP, retirer le chiffrement, exploiter d'anciennes suites de chiffrement, profiter de certificats expirésTLS 1.2+, HSTS (préchargement facultatif), renouvellement automatiséVérification du Certificat SSL
3. En-têtes HTTPInjecter des scripts (XSS), piéger le site dans un cadre (clickjacking), exploiter le MIME sniffing, faire fuiter le référentCSP, frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyVérification des En-têtes HTTP
4. ApplicationCredential stuffing, injection, contrôle d'accès défaillant, CSRF, uploads non sécurisésArgon2id + MFA + limitation de débit, requêtes paramétrées, autorisation côté serveur, cookies SameSiteRevue de code, ZAP, Test de Force de Mot de Passe
5. DépendancesPaquets empoisonnés, CVE connues dans les bibliothèques, pipelines CI compromisLockfiles, audits, versions épinglées, SBOM, jetons à privilèges minimauxnpm audit, Dependabot, Trivy
6. Serveur et exploitationPorts ouverts, identifiants par défaut, correctifs manquants, aucune sauvegarde, aucun journalPare-feu, SSH par clé uniquement, correctifs, sauvegardes 3-2-1, journalisation centraliséeVérificateur de Ports, Vérification de Liste Noire IP

Procédez de haut en bas. Les couches 1 à 3 relèvent de la configuration : vous pouvez les boucler en un après-midi, et elles protègent toutes les pages d'un coup. Les couches 4 à 6 sont des habitudes permanentes qui doivent s'inscrire dans votre revue de code et votre processus de déploiement.

Couche 1 : verrouiller le domaine et le DNS

Tout le reste de ce guide suppose que vous contrôlez toujours votre domaine. Si un attaquant peut se connecter à votre compte chez le registrar ou modifier vos serveurs de noms, il peut rediriger votre trafic où il veut, obtenir un certificat valide pour votre nom et lire chaque e-mail qui vous est adressé, sans que votre code applicatif ne s'exécute jamais. La sécurité du domaine et du DNS est donc la première bonne pratique de sécurité web, et elle relève presque entièrement de la configuration.

Commencez par une recherche WHOIS sur votre propre domaine et vérifiez trois choses : les codes de statut incluent clientTransferProhibited, la date d'expiration est à plus d'un an et le registrar est bien un registrar chez qui vous avez réellement un compte. Il est étonnamment fréquent qu'un domaine d'entreprise se trouve dans le compte registrar d'un ancien prestataire. Notre guide de la recherche WHOIS explique chaque code de statut que vous rencontrerez.

Registrar lock, MFA et alertes d'expiration

Activez le registrar lock (aussi appelé verrou de transfert) afin que le domaine ne puisse pas être transféré vers un autre registrar sans que vous le déverrouilliez explicitement, et activez l'authentification multifacteur sur le compte registrar lui-même. Les comptes registrar sont une cible de phishing privilégiée précisément parce qu'un seul identifiant contrôle tout ce qui en dépend. Utilisez une clé matérielle ou une application d'authentification plutôt que le SMS dès que le registrar le permet.

Activez le renouvellement automatique avec un moyen de paiement qui n'expirera pas, et ajoutez tout de même une alerte au calendrier 60 jours avant la date d'expiration. Un domaine expiré n'est pas perdu le jour de son expiration, mais une fois les périodes de grâce et de rédemption écoulées (jusqu'à environ 80 jours pour .com), il est supprimé, et les services de drop-catch l'enregistrent en quelques secondes après sa libération. L'acheteur hérite de votre messagerie, de votre trafic et de toutes les connexions OAuth qui font confiance à votre domaine.

  • Le registry lock (un verrou manuel, hors bande, au niveau du registre) vaut le surcoût pour un domaine dont dépend une entreprise : il empêche même un compte registrar compromis de modifier les serveurs de noms.
  • Séparez les rôles. La personne qui paie le domaine, le compte qui le détient et le fournisseur DNS doivent chacun être documentés et ne pas dépendre de la boîte mail d'un seul employé.
  • Activez la confidentialité WHOIS pour que vos coordonnées ne servent pas de carte aux campagnes de phishing, et gardez sur le compte une adresse de rôle surveillée comme domains@.

Signer la zone avec DNSSEC

DNSSEC signe votre zone DNS pour qu'un résolveur puisse détecter les réponses falsifiées. Sans lui, un attaquant capable d'empoisonner le cache d'un résolveur peut envoyer vos visiteurs vers un faux serveur alors que leur navigateur affiche toujours votre nom de domaine. La plupart des fournisseurs DNS gérés (Cloudflare, Route 53, Google Cloud DNS et de nombreux registrars) l'activent d'un seul bouton ; la seule étape manuelle est la publication de l'enregistrement DS chez votre registrar. Vérifiez-le avec dig ou avec le Test de santé DNS, qui contrôle l'enregistrement DS et les signatures :

bash
dig +dnssec +short yourdomain.com A
# A signed zone returns the record AND an RRSIG line:
# 203.0.113.10
# A 13 2 3600 20270115000000 20261225000000 34505 yourdomain.com. Kx3f...==

dig +short yourdomain.com DS
# A DS record at the parent zone proves the chain of trust is complete
# 2371 13 2 6A1B...C9

Restreindre l'émission de certificats avec CAA

Un enregistrement CAA (RFC 8659) indique aux autorités de certification lesquelles d'entre elles peuvent émettre des certificats pour votre domaine. Toute AC publique est tenue de le vérifier avant d'émettre, si bien qu'un enregistrement CAA ferme la porte à un attaquant qui aurait trompé la validation de domaine d'une autre AC. Trois enregistrements couvrent les cas courants : qui peut émettre, qui peut émettre des certificats wildcard et où signaler une demande refusée :

dns
yourdomain.com.  CAA 0 issue "letsencrypt.org"
yourdomain.com.  CAA 0 issuewild ";"
yourdomain.com.  CAA 0 iodef "mailto:security@yourdomain.com"

Auditer les enregistrements obsolètes : subdomain takeover

Une prise de contrôle de sous-domaine survient lorsqu'un enregistrement DNS pointe encore vers un service que vous n'utilisez plus : un CNAME vers un site GitHub Pages supprimé, une application Azure, un bucket S3 ou le nom d'hôte d'un éditeur SaaS. N'importe qui peut enregistrer la cible abandonnée, puis servir du contenu sur old-app.yourdomain.com en votre nom, avec un certificat valide. C'est une trouvaille régulière des programmes de bug bounty, car personne ne se souvient que l'enregistrement existe.

Passez votre domaine dans la Recherche de Sous-domaines : elle interroge deux services de journaux de transparence des certificats, Cert Spotter (certificats actuels) et crt.sh (tous les certificats depuis 2013), essaie 1 000 noms courants, résout chaque nom en direct, signale les CNAME orphelins et indique quel hébergeur ou CDN fait tourner chacun. Supprimez tout enregistrement dont la cible renvoie NXDOMAIN ou une page « no such app » du fournisseur ; une recherche DNS confirme un nom isolé. Répétez chaque trimestre et faites de la suppression de l'enregistrement DNS une étape du démantèlement de tout service.

La Certificate Transparency est aussi votre système d'alerte précoce : Cert Spotter et la surveillance CT de Cloudflare peuvent vous envoyer un e-mail dès qu'une AC émet un certificat pour votre domaine. Un certificat inattendu est souvent le premier signe visible d'une compromission du DNS ou du compte registrar.

Couche 2 : HTTPS et TLS bien configurés

HTTPS n'est plus une bonne pratique, c'est la base, et les navigateurs marquent les pages HTTP simples comme « Non sécurisé ». Google a aussi annoncé qu'à partir de Chrome 154 (octobre 2026), le navigateur demande confirmation avant d'ouvrir un site public en HTTP simple (Google). Ce qui sépare encore un site sûr d'un site simplement chiffré, ce sont les versions de TLS acceptées, la possibilité ou non de vous joindre en HTTP, et un renouvellement assez automatisé pour survivre aux réductions de durée de vie des certificats commencées en mars 2026.

TLS 1.2 au minimum, TLS 1.3 de préférence

TLS 1.0 et 1.1 ont été officiellement dépréciés par la RFC 8996 en 2021, et aucun navigateur actuel ne les négocie. Désactivez-les sur le serveur, privilégiez TLS 1.3 (qui supprime toutes les suites de chiffrement réputées faibles et termine la négociation en un seul aller-retour) et ne conservez TLS 1.2 qu'avec des suites AEAD comme ECDHE-ECDSA-AES128-GCM-SHA256 ou ECDHE-RSA-CHACHA20-POLY1305.

Deux lignes comptent quand vous testez de l'extérieur : le protocole négocié, et Verify return code: 0, qui signifie que toute la chaîne de certificats a été validée. Un certificat intermédiaire manquant est une cause fréquente des signalements « ça marche dans Chrome, mais pas avec curl ni sur Android » ; notre guide sur la chaîne de certificats SSL montre comment le corriger, et le Vérificateur SSL signale directement une chaîne incomplète. Voici la vérification exécutée contre dnsrobot.net le 27 octobre 2026, puis un test pour savoir si le serveur refuse TLS 1.1 :

bash
echo | openssl s_client -connect dnsrobot.net:443 -servername dnsrobot.net 2>/dev/null \
  | grep -E 'Protocol|Cipher|Verify return'

# New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
# Protocol: TLSv1.3
# Verify return code: 0 (ok)

# Is TLS 1.1 refused? SECLEVEL=0 lets OpenSSL 3 and later offer it at all
openssl s_client -connect example.com:443 -servername example.com -tls1_1 \
  -cipher 'DEFAULT:@SECLEVEL=0' </dev/null 2>&1 | grep -E 'alert|Cipher is'

# Refused, as it should be:  ...tlsv1 alert protocol version...
#                            New, (NONE), Cipher is (NONE)
# Still accepted (fix it):   New, TLSv1.0, Cipher is ECDHE-ECDSA-AES128-SHA
#   (TLSv1.0 is the cipher's version; the handshake was TLS 1.1)

C'est dans les listes de suites de chiffrement que les configurations copiées-collées vieillissent le plus vite. Au lieu de les écrire à la main, générez le bloc serveur actuellement recommandé pour nginx, Apache, Caddy ou HAProxy avec le Mozilla SSL Configuration Generator et choisissez le profil « Intermediate », sauf si vous devez prendre en charge des clients très anciens.

HSTS : ne plus jamais laisser un navigateur utiliser HTTP

Rediriger HTTP vers HTTPS ne suffit pas à lui seul. La toute première requête d'un visiteur vers http://yourdomain.com circule toujours en clair, et un attaquant présent sur le même réseau peut y répondre avant votre redirection. HTTP Strict Transport Security (RFC 6797) règle ce problème : dès qu'un navigateur a vu l'en-tête, il réécrit chaque future URL http:// de votre domaine en https:// avant d'envoyer quoi que ce soit.

Utilisez un max-age d'au moins un an (31536000 secondes) et ajoutez includeSubDomains une fois que chaque sous-domaine sert HTTPS. Le préchargement sur hstspreload.org, qui inscrit le domaine en dur dans Chrome, Firefox, Safari et Edge, est facultatif : les mainteneurs de la liste eux-mêmes disent désormais que HSTS est recommandé mais pas le préchargement, car Chrome et Safari passent déjà les navigations en HTTPS et quitter la liste prend des mois. Vérifiez l'en-tête avec la Vérification des En-têtes HTTP, qui note HSTS avec les tests de Mozilla HTTP Observatory.

http
Strict-Transport-Security: max-age=31536000; includeSubDomains

Certificats de 47 jours : automatisez le renouvellement dès maintenant

Le vote SC-081 du CA/Browser Forum réduit par étapes la durée de vie maximale de tout certificat TLS public. La première réduction est entrée en vigueur le 15 mars 2026 : tout certificat acheté ou renouvelé aujourd'hui est donc déjà limité à 200 jours, et d'ici 2029 il faudra remplacer un certificat environ toutes les six semaines :

Date d'entrée en vigueurValidité maximale du certificatRéutilisation de la validation de domaine
Avant le 15 mars 2026398 jours398 jours
15 mars 2026200 jours200 jours
15 mars 2027100 jours100 jours
15 mars 202947 jours10 jours

Un renouvellement manuel ne tient pas face à ce calendrier. La bonne pratique consiste à automatiser entièrement l'émission via ACME : Let's Encrypt ou Google Trust Services avec certbot, acme.sh ou Caddy, ou encore les certificats automatiques intégrés à Cloudflare, Vercel, Netlify et à la plupart des panneaux d'hébergement. Testez la procédure de renouvellement avant d'en avoir besoin (certbot renew --dry-run pour certbot) ; l'échec à surveiller est un enregistrement CAA ou une règle de pare-feu ajoutés depuis le dernier renouvellement et qui bloquent désormais la validation. Quelle que soit votre solution, surveillez aussi la date d'expiration depuis l'extérieur : la Vérification du Certificat SSL affiche le nombre de jours restants, et un certificat expiré transforme chaque visite en avertissement plein écran du navigateur.

Couche 3 : en-têtes de sécurité HTTP

Les en-têtes de sécurité sont des instructions que votre serveur donne au navigateur sur ce qu'il peut ou non faire de vos pages : quels scripts peuvent s'exécuter, si la page peut être placée dans un cadre, si le navigateur peut deviner les types de contenu, et ce qu'il doit dire aux autres sites sur la provenance d'un visiteur. Ils ne coûtent rien, s'appliquent à toutes les pages à la fois et bloquent des classes entières d'attaques. C'est aussi la couche que la plupart des sites configurent en partie de travers, ce qui explique que le Vérificateur d'en-têtes HTTP les note avec les tests de Mozilla HTTP Observatory. Voici ce que github.com a envoyé le 27 octobre 2026, réduit aux en-têtes de sécurité (son script-src nomme un hôte de ressources et un hachage de script, sans 'unsafe-inline') :

bash
curl -sI https://github.com/ | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy'

strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
content-security-policy: default-src 'none'; base-uri 'self'; ... frame-ancestors 'none'; ... script-src github.githubassets.com 'sha256-6AKuI+cDd1MoUL1u4eqrA9PXmnPAkOB4h7421hPUUm0='; ...

Les sept en-têtes que tout site devrait envoyer

Voici les valeurs à viser sur un site classique. Dans la notation de Mozilla HTTP Observatory, que notre Vérificateur d'en-têtes HTTP utilise, l'absence de CSP coûte 25 points, l'absence de HSTS ou de protection contre l'inclusion en cadre 20 chacune, et l'absence de nosniff 5 ; Referrer-Policy et COOP ajoutent des points bonus tant que le score reste à 90 ou plus. Permissions-Policy n'est pas notée (seuls les navigateurs Chromium la lisent), mais elle vaut quand même d'être définie.

En-têteValeur recommandéeCe qu'il empêche
Strict-Transport-Securitymax-age=31536000; includeSubDomainsRétrogradation de protocole, vol de cookies via HTTP
Content-Security-Policyscript-src à base de nonce avec 'strict-dynamic' ; object-src 'none' ; base-uri 'none' ; frame-ancestors 'none'Cross-site scripting (XSS), injection de données, clickjacking
X-Content-Type-OptionsnosniffLe MIME sniffing qui transforme un fichier uploadé en script exécutable
Referrer-Policystrict-origin-when-cross-originFuite d'URL complètes (jetons, termes de recherche) vers des tiers
Permissions-Policycamera=(), microphone=(), geolocation=(), payment=()Scripts tiers qui utilisent en silence des API puissantes du navigateur
X-Frame-OptionsDENY (repli historique pour frame-ancestors)Clickjacking dans les navigateurs sans CSP Level 2
Cross-Origin-Opener-Policysame-originAttaques inter-fenêtres via window.opener

Content Security Policy sans casser le site

Une Content Security Policy est la défense la plus efficace contre le XSS, car elle empêche les scripts injectés de s'exécuter même lorsqu'une faille d'injection existe. Le revers : une politique stricte casse tout script inline ou toute balise tierce que vous auriez oubliés. L'approche moderne, recommandée par Google et documentée sur MDN, est une politique à base de nonce : le serveur génère un nonce aléatoire pour chaque réponse, le place sur chaque balise script qu'il affiche volontairement, et le navigateur refuse tout le reste.

C'est 'strict-dynamic' qui rend la politique utilisable en pratique : un script doté d'un nonce peut charger d'autres scripts (analytics, gestionnaires de balises, widgets) sans que chacun doive figurer sur une liste d'autorisation, tandis que les jetons https: et 'unsafe-inline' sont ignorés par les navigateurs modernes et ne servent que de repli pour les anciens. Déployez d'abord avec Content-Security-Policy-Report-Only, surveillez les rapports de violation pendant une semaine, puis passez en mode bloquant. Des frameworks comme Next.js, Rails et Django prennent en charge les nonces nativement ; les sites statiques peuvent utiliser à la place un script-src à base de hash.

http
Content-Security-Policy:
  script-src 'nonce-r4nd0m1z3dV4lu3' 'strict-dynamic' https: 'unsafe-inline';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';
  form-action 'self';
  report-to csp-endpoint

<!-- Only scripts carrying the nonce run; strict-dynamic lets them load their own dependencies -->
<script nonce="r4nd0m1z3dV4lu3" src="/app.js"></script>

Une politique à liste d'autorisation comme script-src 'self' https://cdn.example.com vaut mieux que rien, mais n'importe quel endpoint JSONP ou ancienne bibliothèque hébergés sur un domaine autorisé peut servir à la contourner. Si vous ne pouvez pas encore utiliser de nonces, définissez au moins object-src 'none' et base-uri 'none', qui ferment immédiatement deux contournements courants.

Clickjacking : frame-ancestors et X-Frame-Options

Le clickjacking charge votre site de façon invisible dans la page d'un attaquant et pousse le visiteur à cliquer sur un bouton qu'il ne voit pas. frame-ancestors 'none' dans la CSP (ou 'self' si vous intégrez vos propres pages) l'empêche dans tous les navigateurs actuels, et X-Frame-Options: DENY couvre les plus anciens. Si vous proposez volontairement un widget intégrable, n'exemptez que ce chemin et uniquement pour les origines qui en ont besoin ; notre guide X-Frame-Options détaille les règles serveur exactes et les erreurs « refused to connect » que vous rencontrerez pendant vos tests.

nosniff, Referrer-Policy, Permissions-Policy et COOP

X-Content-Type-Options: nosniff empêche le navigateur de remettre en cause un Content-Type, ce qui est précisément ce qui transforme une « image » contenant du HTML, uploadée par un utilisateur, en page exécutable. Referrer-Policy: strict-origin-when-cross-origin (le comportement par défaut des navigateurs actuels, mais définissez-le explicitement) n'envoie que votre origine aux autres sites, si bien que les jetons de réinitialisation de mot de passe et les requêtes de recherche présents dans les URL restent privés. Permissions-Policy désactive les fonctionnalités du navigateur que vous n'utilisez pas, pour qu'un script tiers compromis ne puisse ni ouvrir la caméra ni lire la localisation. Cross-Origin-Opener-Policy: same-origin coupe le lien window.opener vers les pages que vous ouvrez, ce qui bloque toute une catégorie d'attaques inter-fenêtres.

Les en-têtes à supprimer comptent aussi : Server et X-Powered-By annoncent aux scanners de vulnérabilités les versions exactes de vos logiciels, et X-XSS-Protection est obsolète et peut introduire des bogues dans les anciens navigateurs, alors mettez-le à 0 ou retirez-le. Le Détecteur de CMS montre ce que n'importe qui peut apprendre sur votre pile et ses versions à partir de la page elle-même.

Définissez les en-têtes une seule fois en périphérie (CDN, reverse proxy ou middleware du framework) plutôt que page par page. Dans Next.js, c'est le fichier proxy ou middleware ; dans nginx, un bloc add_header dans le contexte server ; dans Apache, Header always set. Relancez ensuite la Vérification des En-têtes HTTP après chaque déploiement, car une nouvelle version du framework ou un réglage du CDN peut en supprimer un sans prévenir.

Couche 4 : une authentification qui résiste au credential stuffing

Les attaquants devinent rarement les mots de passe un par un. Ils rejouent des milliards de couples e-mail/mot de passe divulgués par d'autres sites (credential stuffing) et obtiennent le reste par phishing. Les bonnes pratiques d'authentification comportent donc trois volets : stocker les mots de passe de sorte qu'une fuite de base de données ne soit pas une fuite de mots de passe, rendre un mot de passe volé inutilisable à lui seul, et rendre la force brute trop lente pour être efficace. L'OWASP classe les Authentication Failures (défaillances d'authentification) en A07 dans l'OWASP Top 10:2025.

Hacher les mots de passe avec Argon2id ou bcrypt

Ne stockez jamais un mot de passe, ni même un hash rapide de celui-ci. MD5, SHA-1 et même SHA-256 sont conçus pour être rapides : une table divulguée de ces hashs peut être testée à raison de milliards de tentatives par seconde sur un seul GPU. Utilisez une fonction de hachage de mots de passe lente et gourmande en mémoire avec un sel unique par mot de passe. L'OWASP Password Storage Cheat Sheet recommande, dans l'ordre :

  • Argon2id avec au moins 19 Mio de mémoire, 2 itérations et un degré de parallélisme de 1 (ou 46 Mio avec 1 itération).
  • scrypt avec N = 2^17, r = 8, p = 1 lorsque Argon2 n'est pas disponible.
  • bcrypt avec un facteur de coût de 10 ou plus (attention à sa limite d'entrée de 72 octets ; le pré-hachage des mots de passe plus longs demande des précautions).
  • PBKDF2-HMAC-SHA256 avec 600 000 itérations, uniquement lorsque la conformité FIPS l'impose.
javascript
// Node.js with the argon2 package
import argon2 from "argon2";

const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 19456, // KiB = 19 MiB
  timeCost: 2,
  parallelism: 1,
});

// Later, on login:
const ok = await argon2.verify(hash, submittedPassword);

Réglez le coût pour qu'un hachage prenne environ 100 à 250 ms sur votre serveur de connexion. C'est invisible pour un vrai utilisateur, mais cela limite chaque cœur de processeur à une poignée d'essais par seconde, et même une carte graphique haut de gamme à quelques milliers au lieu de milliards. Re-hachez à chaque connexion réussie lorsque vous augmentez les paramètres, pour que les anciens hachages se mettent à niveau d'eux-mêmes.

Des règles de mot de passe vraiment utiles (NIST SP 800-63B)

Les règles de composition que la plupart des sites imposent encore (une majuscule, un symbole, un changement tous les 90 jours) produisent des mots de passe prévisibles comme Summer2026! et poussent les gens à les réutiliser. Les recommandations actuelles du NIST SP 800-63B les remplacent par des règles qui mesurent ce qui compte vraiment :

  • Au minimum 8 caractères lorsque la MFA est également exigée, et au moins 15 caractères pour un mot de passe utilisé seul ; autorisez-en au moins 64.
  • Aucune règle de composition et aucune rotation périodique forcée ; n'exigez un changement qu'en cas de preuve de compromission.
  • Vérifiez chaque nouveau mot de passe dans une liste de fuites (l'API par plage de Have I Been Pwned permet de le faire sans envoyer le mot de passe) et refusez ceux qui ont déjà fuité.
  • Autorisez le collage et les gestionnaires de mots de passe, acceptez les espaces et l'Unicode, et donnez des conseils qui aident à choisir un mot de passe robuste, surtout juste après en avoir refusé un.

Notre Test de Force de Mot de Passe montre en quoi ces mesures diffèrent des anciennes règles : il estime le temps nécessaire pour casser un mot de passe face à 8 attaques nommées, montre les motifs qui l'affaiblissent et le compare aux données de fuite sans envoyer le mot de passe, ce qui est un retour bien plus utile qu'un message rouge « symbole requis ».

MFA et passkeys

L'authentification multifacteur transforme un mot de passe volé en impasse. Proposez-la à tout le monde et exigez-la pour les rôles d'administration, de finance et de support. Classez les options selon leur résistance au phishing : les passkeys et clés de sécurité FIDO2 ne peuvent pas être hameçonnées, car l'identifiant est lié à votre véritable origine ; les applications d'authentification (TOTP) sont une bonne option ; les codes SMS valent mieux que rien, mais peuvent être interceptés par SIM swapping. Les passkeys sont prises en charge par tous les navigateurs et systèmes d'exploitation actuels et suppriment complètement le mot de passe, ce qui élimine du même coup toute la catégorie du credential stuffing.

Protégez la procédure de récupération avec autant de soin que la connexion : codes de récupération stockés sous forme hachée, réinitialisations par e-mail avec des jetons à usage unique qui expirent en 15 minutes, et aucune question de sécurité.

Limitation de débit, verrouillage et défense anti-bots

Appliquez une limitation de débit aux endpoints de connexion, d'inscription, de réinitialisation de mot de passe et de MFA, par IP et par compte, et renvoyez 429 Too Many Requests avec un en-tête Retry-After une fois la limite atteinte (notre guide sur l'erreur HTTP 429 explique comment les clients doivent réagir). Combinez-la avec un délai croissant ou un verrouillage temporaire après des échecs répétés sur un même compte, et avec un CAPTCHA ou un défi proof-of-work pour les endpoints visés par des attaques distribuées. Journalisez chaque échec de connexion avec l'IP source, afin que le schéma d'une campagne de credential stuffing soit visible en quelques minutes plutôt qu'en quelques mois.

nginx
# nginx: 5 login attempts at once, then 1 every 12 seconds, per client IP
# (limit_req sends no Retry-After header; add one on your 429 page if clients need it)
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

location = /api/login {
    limit_req zone=login burst=4 nodelay;
    limit_req_status 429;
    proxy_pass http://app;
}

Gardez des messages d'erreur identiques pour « utilisateur inconnu » et « mot de passe incorrect », et un temps de réponse identique dans les deux cas (hachez un mot de passe factice lorsque l'utilisateur n'existe pas). Sinon, le formulaire de connexion sert aussi d'API d'énumération des utilisateurs.

Sessions, cookies et CSRF

Après la connexion, le cookie de session est l'utilisateur ; il mérite donc la même protection que le mot de passe. Trois attributs de cookie et un préfixe de nom font l'essentiel du travail :

  • Secure signifie que le cookie n'est jamais envoyé en HTTP simple ; il ne peut donc pas être intercepté sur un Wi-Fi public.
  • HttpOnly le rend invisible pour JavaScript, si bien qu'une faille XSS ne peut pas le lire.
  • SameSite=Lax (ou Strict pour les panneaux d'administration) l'exclut des requêtes POST intersites, ce qui neutralise la plupart des attaques CSRF.
  • Le préfixe __Host- amène le navigateur à refuser le cookie s'il n'est pas Secure, s'il n'a pas Path=/ ou s'il possède un attribut Domain, si bien qu'un sous-domaine ne peut pas l'écraser.
http
Set-Cookie: __Host-session=9f1c7e2a...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800

Les actions qui modifient un état ne doivent jamais être accessibles en GET. Un lien comme /account/delete?id=42 peut être déclenché par une balise <img> sur n'importe quelle page visitée par l'utilisateur, aussi bons que soient les attributs de vos cookies.

CSRF : une seconde ligne de défense derrière SameSite

Le cross-site request forgery (CSRF) pousse un navigateur connecté à envoyer à votre site, depuis une autre page, une requête qui modifie un état. Les cookies SameSite bloquent le cas courant, mais conservez une seconde défense sur chaque requête non-GET : un jeton anti-CSRF par session dans un champ caché ou un en-tête personnalisé, ou une vérification que l'en-tête Origin (ou Sec-Fetch-Site) correspond bien à votre propre origine. La plupart des frameworks (Django, Rails, Laravel, les server actions de Next.js) le font par défaut ; l'erreur consiste à désactiver cette protection pour un endpoint d'API, puis à appeler cet endpoint depuis un navigateur.

ID de session, rotation et JWT

Générez des identifiants de session avec au moins 128 bits d'aléa, changez l'identifiant à la connexion et à chaque changement de privilèges pour déjouer la fixation de session, faites expirer les sessions après une période d'inactivité et offrez aux utilisateurs un bouton « se déconnecter partout » qui les invalide côté serveur. Pour les JWT, gardez-les de courte durée (quelques minutes, avec un refresh token révocable), ne les stockez jamais dans localStorage où n'importe quel script peut les lire, et traitez la fuite d'une clé de signature comme une compromission totale, car chaque jeton qu'elle a signé devient falsifiable.

Injection et XSS : valider les entrées, encoder les sorties

L'injection (A05:2025) et le cross-site scripting sont la même erreur commise à des endroits différents : des données fournies par un utilisateur sont transmises à un interpréteur (SQL, le shell, une requête LDAP, une page HTML) comme s'il s'agissait de code. La correction est partout la même : séparer les données du code et ne jamais construire une commande par concaténation de chaînes.

Des requêtes paramétrées, pas de concaténation

Pour SQL, utilisez des requêtes préparées ou un ORM qui les génère : la base de données traite alors l'entrée comme une valeur qui ne peut jamais modifier la structure de la requête. La même règle s'applique aux commandes shell (passez un tableau d'arguments, jamais une chaîne), aux filtres NoSQL (rejetez les objets opérateurs comme {"$gt": ""} dans les entrées utilisateur) et aux chemins de fichiers (résolvez le chemin et vérifiez qu'il reste sous le répertoire prévu).

javascript
// Vulnerable: the input becomes part of the query text
const rows = await db.query(`SELECT * FROM users WHERE email = '${email}'`);

// Safe: the driver sends the value separately from the query
const rows = await db.query("SELECT * FROM users WHERE email = $1", [email]);

// Python / psycopg: same idea
cur.execute("SELECT * FROM users WHERE email = %s", (email,))

L'encodage des sorties arrête le XSS

Le cross-site scripting se produit lorsqu'un texte contrôlé par l'utilisateur est écrit dans une page sans être encodé pour le contexte où il atterrit. Les moteurs de templates modernes (React et JSX, Vue, Jinja2, Blade, ERB) encodent par défaut ; aujourd'hui, le XSS vient généralement des échappatoires : dangerouslySetInnerHTML, v-html, |safe, innerHTML, et la construction d'URL ou de gestionnaires d'événements inline à partir de données utilisateur. Encodez pour le contexte exact et nettoyez le HTML riche avec une bibliothèque dédiée comme DOMPurify plutôt qu'avec une regex.

Où arrivent les donnéesEncoder enExemple
Corps HTMLEntités HTML< devient &lt;, " devient &quot;
Attribut HTMLEntités pour attributs entre guillemetsMettez toujours l'attribut entre guillemets ; encodez " et '
JavaScriptN'injectez rien dans le texte du script ; transmettez les données via des attributs data- ou un bloc JSON <script type="application/json"></script> dans une chaîne devient \u003c/script\u003e
Paramètre d'URLEncodage-pourcent (percent-encoding)encodeURIComponent(value)
Valeur CSSÀ éviter totalement ; choisissez les noms de classes dans une liste d'autorisationN'interpolez jamais d'entrée utilisateur dans style

SSRF, uploads de fichiers et désérialisation

Server-side request forgery (SSRF) : si votre serveur récupère une URL fournie par un utilisateur (webhooks, proxys d'images, aperçus de liens), un attaquant peut la faire pointer vers des services internes ou vers l'endpoint de métadonnées cloud 169.254.169.254 et y lire des identifiants. Résolvez d'abord le nom d'hôte, rejetez les plages privées et link-local, désactivez les redirections et placez les composants chargés de ces requêtes sur un segment réseau qui ne peut rien atteindre en interne.

Uploads de fichiers : validez le type en inspectant le contenu, et non l'extension ou le Content-Type envoyé par le client ; imposez une limite de taille ; stockez les fichiers hors de la racine web ou dans un stockage objet, sous un nom aléatoire que vous générez ; et servez-les depuis une origine distincte avec nosniff et Content-Disposition: attachment lorsque c'est possible. Ne laissez jamais un upload atterrir à un endroit où le serveur web l'exécutera.

Désérialisation et mass assignment : ne désérialisez jamais de données non fiables avec un format capable d'instancier des classes arbitraires (sérialisation native Java, pickle en Python, unserialize en PHP, YAML avec des tags personnalisés) ; utilisez du JSON avec un schéma. Liez les corps de requête à une liste explicite de champs autorisés, afin qu'un utilisateur ne puisse pas envoyer "role": "admin" par POST dans un modèle qui possède justement cette colonne.

Broken Access Control : le risque numéro un

Le Broken Access Control (contrôle d'accès défaillant) occupe la première place de l'OWASP Top 10 depuis 2021 et la conserve en A01:2025. Ce n'est pas un bug isolé mais une habitude : vérifier qui est quelqu'un (authentification) et oublier de vérifier ce qu'il a le droit de toucher (autorisation) à chaque requête. La forme classique est l'insecure direct object reference (référence directe non sécurisée à un objet) : GET /api/invoices/1042 fonctionne pour le propriétaire de la facture, mais aussi pour quiconque modifie le numéro.

  • Refusez par défaut. Chaque route exige une règle explicite accordant l'accès ; une règle manquante signifie 403, pas 200.
  • Contrôlez côté serveur, objet par objet. Masquer un bouton dans l'interface n'est pas du contrôle d'accès. Chaque lecture et chaque écriture doit confirmer que l'utilisateur courant possède l'enregistrement concerné ou y est autorisé, y compris dans les endpoints groupés, les exports et les tâches en arrière-plan.
  • Utilisez des identifiants impossibles à deviner quand c'est utile (UUID), mais ne comptez jamais dessus : l'obscurité n'est pas une autorisation.
  • Verrouillez CORS. Access-Control-Allow-Origin: * avec des identifiants, ou le renvoi de n'importe quel Origin envoyé par la requête, livre votre API à tout site web visité par l'utilisateur.
  • Désactivez le listing des répertoires, bloquez .git, .env, les fichiers de sauvegarde et de configuration au niveau du serveur web, et gardez les panneaux d'administration hors de l'internet public ou derrière la MFA et des listes d'IP autorisées.
  • Limitez le débit et journalisez les échecs d'autorisation. Une rafale de 403 depuis une même session, c'est une attaque par énumération en cours.
javascript
// Express: ownership check on every object access
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
  const invoice = await Invoice.findById(req.params.id);
  if (!invoice || invoice.ownerId !== req.user.id) {
    return res.status(404).end(); // 404, not 403: don't confirm the record exists
  }
  res.json(invoice);
});

Couche 5 : dépendances et chaîne d'approvisionnement logicielle

L'essentiel du code d'une application web typique est du code téléchargé, pas du code que vous avez écrit. C'est pourquoi les défaillances de la chaîne d'approvisionnement logicielle font leur entrée en A03 dans l'OWASP Top 10 2025, et pourquoi l'exploitation de vulnérabilités a dépassé le phishing et les identifiants volés dans le DBIR 2026. En septembre 2025, un seul mainteneur hameçonné a introduit un logiciel malveillant voleur de cryptomonnaies dans chalk, debug et 16 autres paquets npm qui totalisent plus de deux milliards de téléchargements par semaine ; chaque projet qui a installé une version non épinglée pendant cette fenêtre l'a récupéré automatiquement.

  • Commitez un lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, go.sum) et installez avec npm ci en CI, pour que les builds soient reproductibles et qu'une nouvelle version publiée en amont ne puisse pas s'infiltrer sans relecture.
  • Analysez en continu : npm audit, pip-audit, bundler-audit, GitHub Dependabot ou Renovate pour les mises à jour, et un scanner de conteneurs comme Trivy ou Grype pour la couche système.
  • Retardez de quelques jours les mises à jour non liées à la sécurité (minimumReleaseAge de Renovate), pour qu'une version empoisonnée soit généralement retirée avant que vous ne l'adoptiez, mais appliquez immédiatement les correctifs de sécurité.
  • Épinglez les actions et scripts tiers sur un SHA de commit en CI, et utilisez Subresource Integrity (integrity="sha384-...") pour tout script chargé depuis un CDN public.
  • Accordez à la CI le moindre privilège : jetons en lecture seule lorsque c'est possible, identifiants OIDC de courte durée plutôt que des secrets à longue durée de vie, et droits de publication réservés à un job de release.
  • Générez un SBOM (CycloneDX ou SPDX) au moment du build, pour pouvoir répondre en quelques minutes à la question « sommes-nous concernés ? » quand tombera la prochaine CVE du calibre de Log4Shell.
bash
# Reproducible install + audit in CI
npm ci --ignore-scripts
npm audit --audit-level=high

# Pin a GitHub Action to a commit, not a floating tag
# uses: actions/checkout@v4                 <- can change underneath you
# uses: actions/checkout@<full-commit-sha>  # v4.2.2

# Subresource Integrity for a CDN script (hash from: openssl dgst -sha384 -binary lib.min.js | openssl base64 -A)
<script src="https://cdn.example.com/lib.min.js"
        integrity="sha384-<base64-hash>"
        crossorigin="anonymous"></script>

npm ci --ignore-scripts bloque les scripts d'installation dont se servent la plupart des malwares npm pour s'exécuter ; réactivez ensuite les scripts uniquement pour la poignée de paquets qui ont réellement besoin d'une étape de build.

Si vous utilisez WordPress ou un autre CMS, les mêmes règles s'appliquent aux plugins et aux thèmes, par lesquels commencent la plupart des compromissions de CMS. Maintenez le cœur et chaque plugin à jour, supprimez ceux que vous n'utilisez pas et vérifiez ce qu'un scanner peut apprendre de vos versions avec le Détecteur de CMS.

Couche 6 : durcissement du serveur (ports, correctifs, secrets, sauvegardes)

La couche applicative ne sert à rien si le serveur sous-jacent accepte les connexions SSH par mot de passe, expose une base de données sur un port public ou n'a pas été mis à jour depuis son installation. Les bonnes pratiques côté serveur sont ennuyeuses, et c'est précisément par là que les ransomwares entrent.

Fermer chaque port que vous n'utilisez pas

Un serveur web public a besoin des ports 80 et 443 ouverts, et de SSH depuis votre propre plage d'IP. Les bases de données (3306, 5432, 27017), Redis (6379), Elasticsearch (9200), les panneaux d'administration et les endpoints de métriques doivent écouter uniquement sur localhost ou sur un réseau privé. Vérifiez depuis l'extérieur avec le Vérificateur de Ports après chaque modification, car c'est la vue dont dispose un attaquant, et les groupes de sécurité cloud sont faciles à mal interpréter.

bash
# Ubuntu: default-deny firewall, allow only web + SSH from your office range
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp
sudo ufw enable   # check your own IP is in that range first, or you lock yourself out

# SSH: keys only, no root password login, in a drop-in that sshd reads first
printf 'PasswordAuthentication no\nPermitRootLogin prohibit-password\n' \
  | sudo tee /etc/ssh/sshd_config.d/00-hardening.conf
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin) '   # what sshd will really use
sudo systemctl reload ssh

Sur Ubuntu et Debian, sshd lit les fichiers de /etc/ssh/sshd_config.d/ avant le reste de sshd_config, et pour chaque paramètre, la première valeur lue l'emporte. C'est pourquoi les commandes ci-dessus écrivent un fichier drop-in nommé 00-hardening.conf : une modification plus bas dans le fichier principal perd face au drop-in d'une image cloud qui indique PasswordAuthentication yes. Confirmez le résultat avec sudo sshd -T avant de vous déconnecter. Dans le Vérificateur de Ports, un port que votre pare-feu abandonne s'affiche comme filtered (aucune réponse), et un port sans service à l'écoute comme closed : les deux vont bien, c'est open qu'il faut corriger.

Corriger selon un calendrier, garder les secrets hors du code

Activez les mises à jour de sécurité automatiques du système d'exploitation, abonnez-vous aux listes de sécurité de votre runtime et de votre framework, et traitez une CVE critique sur tout composant exposé à internet comme une tâche à régler dans la journée. Exécutez les services sous des utilisateurs non privilégiés, dans des conteneurs ou avec le sandboxing de systemd, pour qu'un processus compromis ne puisse pas lire toute la machine.

Les secrets (mots de passe de base de données, clés d'API, clés de signature) n'ont leur place ni dans le dépôt, ni dans une couche d'image Docker, ni dans le JavaScript côté client. Chargez-les depuis des variables d'environnement injectées au déploiement ou depuis un gestionnaire de secrets, renouvelez-les lorsqu'une personne qui y avait accès s'en va, et analysez l'historique du dépôt avec un outil comme gitleaks, car une clé commitée une seule fois est compromise pour toujours, même après la suppression du commit.

Des sauvegardes qui résistent aux ransomwares, et un CDN en frontal

Appliquez la règle 3-2-1 : trois copies, sur deux supports différents, dont une hors site, et rendez au moins une copie immuable ou hors ligne, afin qu'un ransomware qui atteint le serveur ne puisse pas chiffrer aussi les sauvegardes. Chiffrez les sauvegardes, incluez la base de données et le répertoire des uploads et surtout, testez une restauration à intervalles réguliers. Une sauvegarde à partir de laquelle personne n'a jamais restauré est un espoir, pas un plan. C'est le temps de reprise qui détermine si un incident sera une simple panne ou un événement fatal pour l'entreprise.

Placez un CDN ou un WAF (Cloudflare, Fastly, AWS CloudFront avec WAF ou l'équivalent de votre hébergeur) devant l'origine. Il absorbe les DDoS volumétriques, applique des règles gérées contre les charges d'injection courantes et les mauvais robots, masque l'IP de votre origine et vous donne un endroit pour appliquer des limites de débit et des règles géographiques sans toucher à l'application. Restreignez ensuite le pare-feu de l'origine pour que seules les plages d'IP du CDN puissent atteindre directement le port 443 ; sinon, les attaquants le contournent simplement. Le Vérificateur d'hébergement montre quel CDN se trouve devant un site et ce que disent les preuves publiques sur l'hébergeur qui se cache derrière.

Authentification des e-mails : SPF, DKIM et DMARC

La sécurité web inclut le courriel qui transporte vos réinitialisations de mot de passe, vos factures et vos réponses du support. Sans SPF, DKIM et DMARC, n'importe qui peut envoyer du courrier en tant que billing@yourdomain.com, et depuis février 2024 Google et Yahoo exigent les trois des expéditeurs en masse, Microsoft faisant de même pour Outlook.com depuis mai 2025. L'ensemble complet tient en trois enregistrements TXT DNS :

dns
yourdomain.com.                    TXT  "v=spf1 include:_spf.google.com -all"
google._domainkey.yourdomain.com.  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
_dmarc.yourdomain.com.             TXT  "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s"

DMARC p=reject est aussi un outil de protection de la marque : c'est la seule chose qui empêche une campagne de phishing d'afficher votre domaine exact dans le champ « De ». Les rapports agrégés (rua=) vous montrent qui essaie.

Démarrez DMARC à p=none pour collecter des rapports, passez à p=quarantine puis à p=reject une fois que chaque expéditeur légitime (plateforme marketing, helpdesk, CRM) passe l'alignement. Ajoutez des enregistrements MTA-STS et TLS-RPT pour imposer une livraison chiffrée vers vos serveurs de messagerie. Sur les domaines qui n'envoient ni ne reçoivent jamais de courrier, publiez un MX nul (MX 0 .), v=spf1 -all et un enregistrement DMARC avec p=reject : le MX nul dit seulement que le domaine n'accepte pas de courrier, ce sont SPF et DMARC qui permettent aux destinataires de rejeter les contrefaçons. Vérifiez chaque enregistrement avec le Vérificateur d'Enregistrement SPF, le Vérificateur DKIM et le Vérificateur DMARC, et comparez vos IP d'envoi aux listes de blocage avec la Vérification de Liste Noire IP si la délivrabilité baisse.

Journaliser, surveiller et anticiper l'intrusion

Deux des dix catégories de l'OWASP 2025 portent sur ce qui se passe après une erreur : Security Logging and Alerting Failures (A09) et la nouvelle catégorie Mishandling of Exceptional Conditions (A10). Une intrusion typique passe encore inaperçue pendant des mois, parce que les preuves n'ont jamais été enregistrées, ou qu'elles l'ont été sans que personne ne les consulte.

  • Journalisez les événements de sécurité avec leur contexte : chaque connexion réussie ou échouée, les modifications de MFA, les réinitialisations de mot de passe, les changements de permissions, les refus du contrôle d'accès, les échecs de validation des entrées et les actions d'administration, chacun avec l'horodatage, l'ID utilisateur, l'IP source et le user agent.
  • Ne journalisez jamais de secrets : mots de passe, jetons de session, numéros de carte complets, clés d'API. Masquez-les au niveau de la couche de journalisation, pas à chaque point d'appel.
  • Envoyez les journaux hors du serveur vers un stockage centralisé (CloudWatch, Loki, Elastic, un SIEM) avec une rétention d'au moins 90 jours, pour qu'un attaquant ayant obtenu les droits root ne puisse pas effacer ses traces.
  • Déclenchez des alertes sur des schémas, pas sur des événements isolés : 50 échecs de connexion en une minute, un pic de 403 depuis une même session, un nouvel administrateur créé en dehors des heures ouvrées, un certificat émis pour votre domaine que vous n'avez pas demandé.
  • Échouez en mode fermé (fail closed) : lorsqu'un contrôle en aval (service d'authentification, limiteur de débit, WAF) renvoie une erreur, refusez la requête. La catégorie A10 existe parce que tant de systèmes accordent l'accès lorsque le contrôle qui aurait dû bloquer la requête lève une exception.
  • Surveillez de l'extérieur : disponibilité, expiration des certificats, changements DNS, inscriptions sur liste de blocage et régressions d'en-têtes. Relancez le Vérificateur SSL, le Vérificateur d'en-têtes HTTP et le Test de santé DNS (40 contrôles sur la délégation, les serveurs de noms, DNSSEC et SPF/DMARC) après chaque déploiement.

Rédiger le plan de réponse aux incidents avant d'en avoir besoin

Décidez à l'avance qui est d'astreinte, comment renouveler chaque identifiant, comment passer le site en lecture seule, où se trouvent les sauvegardes saines, et quel régulateur ou quels clients doivent être informés et sous combien d'heures (72 selon le RGPD). Faites un exercice sur table une fois par an. Un plan répété transforme des jours d'improvisation en liste de contrôle.

Publiez un fichier security.txt à l'adresse /.well-known/security.txt (RFC 9116) avec une ligne Contact: et une date Expires:, les deux champs obligatoires (une clé Encryption: est facultative). Les chercheurs qui trouvent une faille sur votre site regarderont là en premier ; sans lui, ils risquent de ne trouver personne à prévenir.

Tester : scanners, tests d'intrusion et contrôles continus

Chacun des contrôles ci-dessus peut être vérifié, et cette vérification doit être automatisée autant que possible pour ne pas se dégrader avec le temps. Voici une progression raisonnable, du gratuit et instantané au périodique et payant :

ContrôleOutilFréquence
Configuration TLS, chaîne, expirationVérification du Certificat SSL, SSL Labs, testssl.shAprès chaque changement de certificat ou de serveur ; expiration tous les jours
En-têtes de sécurité et CSPVérification des En-têtes HTTP, MDN HTTP ObservatoryAprès chaque déploiement (intégrez-le à la CI)
Ports ouvertsVérificateur de Ports, nmap depuis l'extérieur de votre réseauAprès chaque modification du pare-feu ou du cloud
DNS, DNSSEC, authentification des e-mailsTest de santé DNS, Vérificateur DMARCChaque mois, et après toute modification DNS
Sous-domaines obsolètesRecherche de Sous-domainesChaque trimestre et à chaque démantèlement
Dépendances connues comme vulnérablesnpm audit, Dependabot, TrivyÀ chaque build
Failles au niveau du code (SAST)Semgrep, CodeQLÀ chaque pull request
Vulnérabilités web à l'exécution (DAST)ZAP, NucleiChaque semaine sur l'environnement de staging
Autorisation et logique métierTest d'intrusion manuel ou programme de bug bountyChaque année, et après chaque fonctionnalité majeure

Les scanners sont efficaces sur les injections, les en-têtes et les composants obsolètes, mais mauvais sur l'autorisation et la logique métier : prévoyez donc au moins un test humain par an pour tout ce qui manipule de l'argent ou des données personnelles. Corrigez selon l'exposition : tout ce qu'un utilisateur non authentifié peut exploiter depuis internet passe en premier.

La checklist de sécurité web

Copiez-la dans le README de votre projet ou dans votre outil de suivi de tickets. Chaque ligne reprend l'une des pratiques ci-dessus, formulée pour pouvoir être cochée ou non ; la dernière colonne en apporte la preuve.

CouchePratiqueValidé quand
DomaineRegistrar lock et MFA sur le compte registrar ; renouvellement automatique activéLe WHOIS affiche clientTransferProhibited ; expiration à plus de 12 mois
DNSZone signée avec DNSSEC ; enregistrement CAA ne listant que vos ACdig +dnssec renvoie RRSIG ; enregistrement DS présent dans la zone parente
DNSAucun enregistrement CNAME ou A orphelinChaque nom d'hôte trouvé par la Recherche de Sous-domaines pointe vers une ressource que vous contrôlez
TLSTLS 1.2+ uniquement, TLS 1.3 de préférence, chaîne complète servieVérification du Certificat SSL : chaîne complète, TLS 1.0/1.1 refusés
TLSHSTS avec max-age d'un an et includeSubDomains (préchargement facultatif)Le Vérificateur d'en-têtes HTTP réussit le test HSTS
TLSRenouvellement automatisé via ACME ; expiration surveilléecertbot renew --dry-run réussit ; alerte réglée à 14 jours
En-têtesCSP (à base de nonce), frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyVérificateur d'en-têtes HTTP : note A ou A+
AuthentificationHachage Argon2id ou bcrypt ; règles de mot de passe NIST ; vérification dans une liste de fuitesUn hash prend de 100 à 250 ms ; aucune règle de composition
AuthentificationMFA proposée à tous, obligatoire pour les administrateurs ; passkeys prises en chargeConnexion admin impossible sans second facteur
AuthentificationEndpoints de connexion, de réinitialisation et de MFA limités par IP et par compteSix tentatives rapides depuis une IP : la sixième renvoie 429
SessionsCookie __Host- avec Secure, HttpOnly, SameSite ; ID renouvelé à la connexionAttributs du cookie visibles dans les DevTools ; ancienne session invalide après connexion
EntréesRequêtes paramétrées partout ; sorties encodées selon le contexte ; uploads validés par leur contenuAucune requête construite par concaténation dans une recherche de code ; les payloads XSS s'affichent comme du texte
Contrôle d'accèsRoutage avec refus par défaut ; contrôle de propriété par objet ; CORS strictRejouer les ID d'un autre utilisateur renvoie 404 ou 403
DépendancesLockfile commité ; npm ci ; audit en CI ; actions épinglées par SHA ; SRI sur les scripts CDNLe build échoue sur une CVE de gravité élevée
ServeurSeuls 80 et 443 publics ; SSH par clé uniquement ; mises à jour de sécurité automatiques ; secrets en variables d'environnement ou dans un coffre-fortLe Vérificateur de Ports affiche 3306 et 6379 comme closed ou filtered, et 22 aussi depuis l'extérieur de votre propre plage
Sauvegardes3-2-1 avec une copie immuable ; restauration testéeDernier test de restauration réussi datant de moins de 90 jours
E-mailSPF -all, DKIM, DMARC p=reject, MTA-STSLe Vérificateur DMARC valide ; rapports agrégés reçus
SurveillanceÉvénements d'authentification et d'autorisation journalisés de façon centralisée ; alertes sur des schémas ; surveillance externe de la disponibilité, des certificats et du DNSAlerte de test déclenchée et reçue
RéponsePlan d'incident écrit ; security.txt publié ; exercice sur table réaliséPlan revu au cours des 12 derniers mois

Correspondance avec l'OWASP Top 10:2025

L'OWASP Top 10 est la liste de risques des applications web la plus citée, et son édition 2025 a remanié l'ordre et introduit deux nouvelles catégories. Si un client, un auditeur ou un référentiel de conformité vous demande comment vous y répondez, voici la correspondance avec les pratiques de ce guide :

OWASP Top 10:2025Pratiques de ce guide
A01 Broken Access ControlRefus par défaut, contrôles par objet, CORS strict, verrouillage de l'administration
A02 Security MisconfigurationEn-têtes de sécurité, HSTS, ports fermés, en-têtes de version supprimés, listing des répertoires désactivé
A03 Software Supply Chain Failures (nouveau)Lockfiles, audits, actions épinglées, SRI, SBOM, CI à privilèges minimaux
A04 Cryptographic FailuresTLS 1.2+ et 1.3, HSTS, Argon2id, gestion des secrets, sauvegardes chiffrées
A05 InjectionRequêtes paramétrées, encodage des sorties, CSP, validation des uploads
A06 Insecure DesignModélisation des menaces par couche, comportement fail-closed par défaut, limitation de débit dès la conception
A07 Authentication FailuresRègles de mot de passe NIST, vérification des fuites, MFA et passkeys, rotation des sessions
A08 Software or Data Integrity FailuresSRI, dépendances signées et épinglées, désérialisation sûre
A09 Security Logging and Alerting FailuresJournalisation centralisée, alertes sur des schémas, surveillance externe
A10 Mishandling of Exceptional Conditions (nouveau)Fail closed, réponses d'erreur uniformes, aucune stack trace montrée aux utilisateurs

L'ASVS de l'OWASP (Application Security Verification Standard) transforme ces mêmes éléments en checklist numérotée pour les audits. Le niveau 1 est un objectif réaliste pour tout site public ; le niveau 2 convient à tout ce qui traite des données personnelles ou financières.

Vérifiez les en-têtes de sécurité de votre site en quelques secondes

Le Vérificateur d'en-têtes HTTP gratuit de DNS Robot affiche les en-têtes de réponse de n'importe quelle URL exactement comme le serveur les envoie et note ses en-têtes de sécurité avec les tests de Mozilla HTTP Observatory, avec la correction de chacun de ceux qui manquent. Sans inscription.

Sources

  1. 2026 Data Breach Investigations Report, Verizon
  2. OWASP Top 10:2025, OWASP
  3. Password Storage Cheat Sheet, OWASP
  4. SP 800-63B-4: Authentication and Authenticator Management, NIST
  5. Ballot SC-081v3: reducing certificate validity and data reuse periods, CA/Browser Forum
  6. HTTPS by default, Google
  7. RFC 9116: A File Format to Aid in Security Vulnerability Disclosure, IETF

FAQ sur la sécurité web

Quelles sont les bonnes pratiques de sécurité web les plus importantes ?

Imposez HTTPS avec un TLS moderne et HSTS, envoyez des en-têtes de sécurité stricts (en particulier une Content Security Policy), hachez les mots de passe avec Argon2id derrière la MFA et la limitation de débit, utilisez des requêtes paramétrées et l'encodage des sorties, appliquez le contrôle d'accès côté serveur pour chaque objet, gardez les dépendances à jour et épinglées, fermez les ports inutilisés et journalisez les événements de sécurité de façon centralisée. Verrouillez d'abord le domaine et le DNS, car tout le reste suppose que vous contrôliez toujours votre nom de domaine.

Qu'est-ce que l'OWASP Top 10 et est-il toujours pertinent en 2026 ?

L'OWASP Top 10 est un classement, maintenu par la communauté, des risques de sécurité les plus critiques pour les applications web. L'édition 2025 recense Broken Access Control, Security Misconfiguration, Software Supply Chain Failures, Cryptographic Failures, Injection, Insecure Design, Authentication Failures, Software or Data Integrity Failures, Security Logging and Alerting Failures et Mishandling of Exceptional Conditions. Il reste la référence citée par la plupart des audits, des référentiels et des clients.

Quels en-têtes de sécurité HTTP chaque site doit-il envoyer ?

Au minimum : Strict-Transport-Security, Content-Security-Policy (avec frame-ancestors), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin et Permissions-Policy. X-Frame-Options: DENY est une solution de repli historique pour frame-ancestors, et Cross-Origin-Opener-Policy: same-origin est un ajout peu coûteux. Supprimez Server et X-Powered-By pour que les scanners ne puissent pas lire les versions de vos logiciels.

HTTPS suffit-il pour sécuriser un site web ?

Non. HTTPS chiffre le trafic entre le navigateur et le serveur ; il ne fait rien contre l'injection, le contrôle d'accès défaillant, les mots de passe faibles, les dépendances vulnérables ou un port de base de données ouvert. C'est la couche de base, et HSTS la rend durable : une fois qu'un navigateur a vu l'en-tête, il n'envoie plus jamais de requête HTTP simple vers votre domaine.

Comment stocker les mots de passe des utilisateurs ?

Jamais en clair, et jamais avec un hash rapide comme MD5 ou SHA-256. Utilisez Argon2id (19 Mio de mémoire, 2 itérations) ou bcrypt avec un facteur de coût de 10 ou plus, un sel unique par mot de passe, et un réglage tel qu'un hash prenne environ 100 à 250 ms. Vérifiez les nouveaux mots de passe dans une liste de fuites et exigez la MFA pour les comptes à privilèges.

Qu'est-ce qu'une Content Security Policy et en ai-je besoin ?

Une CSP est un en-tête HTTP qui indique au navigateur quelles sources de scripts, de styles, de cadres et d'autres ressources une page peut charger. Une CSP à base de nonce avec 'strict-dynamic' bloque la plupart des attaques de cross-site scripting, même lorsqu'une faille d'injection existe. Tout site qui affiche du contenu fourni par les utilisateurs ou charge des scripts tiers devrait en avoir une ; commencez en mode report-only et passez en mode bloquant une fois que les rapports de violation sont propres.

Comment vérifier si mon site web est sécurisé ?

Commencez par les contrôles de l'extérieur : une vérification SSL pour la version de TLS, la chaîne et l'expiration ; une vérification des en-têtes HTTP pour les en-têtes de sécurité ; une vérification de ports pour les services exposés ; et un test de santé DNS pour DNSSEC et SPF/DMARC. Analysez ensuite les dépendances avec npm audit ou l'équivalent de votre pile, lancez ZAP contre une copie de préproduction et testez manuellement le contrôle d'accès en rejouant des requêtes sous l'identité d'un autre utilisateur.

Pourquoi la durée de vie des certificats TLS raccourcit-elle ?

Le CA/Browser Forum a voté la réduction de la durée de vie maximale des certificats de 398 jours à 200 jours (15 mars 2026), puis à 100 jours (15 mars 2027) et à 47 jours (15 mars 2029), car des certificats plus courts limitent les dégâts d'une clé volée ou d'un certificat émis par erreur et réduisent la dépendance à la révocation. Concrètement, le renouvellement doit être automatisé avec ACME.

À quelle fréquence mettre à jour les dépendances de mon site web ?

Appliquez les correctifs de sécurité dès leur publication, idéalement sous 24 heures pour tout ce qui est exposé à internet, et lancez un audit automatisé à chaque build. Pour les mises à jour non liées à la sécurité, un court délai de quelques jours est plus sûr, car les versions de paquets compromises sont généralement retirées rapidement ; des outils comme Renovate peuvent imposer ce délai automatiquement.

Les petits sites web sont-ils vraiment attaqués ?

Oui, en permanence, car les attaques sont automatisées et ne choisissent pas leurs cibles selon leur taille. Des scanners sondent chaque adresse IP publique à la recherche de ports ouverts et de vulnérabilités CMS connues, et les outils de credential stuffing testent des mots de passe divulgués sur chaque formulaire de connexion qu'ils trouvent. Un petit site a aussi de la valeur comme hébergeur de phishing, relais de spam ou tête de pont vers un client plus important.

À propos de l’auteur

Shaik Vahid

Fondateur de DNS Robot. Vahid a passé des années au support d’hébergement web à réparer les domaines, les enregistrements DNS, les certificats SSL et la distribution des e-mails de clients. Il développe les outils de DNS Robot et écrit ces guides à partir des erreurs que les gens rencontrent vraiment.

Vérificateur d'en-têtes HTTP

Analysez les en-têtes de réponse HTTP et la notation des en-têtes de sécurité