Cybreach Consulting Prendre RDV
Retour aux articles
Vulnérabilités

En-têtes de sécurité HTTP : ce que votre serveur ne dit pas au navigateur

Les en-têtes de sécurité HTTP sont des instructions que votre serveur envoie au navigateur pour lui dire comment se comporter. Ils n'exigent aucun code applicatif, aucune dépendance, aucun redéploiement complexe. Une ligne de configuration Nginx ou Apache suffit. Pourtant, dans la grande majorité des audits, ces en-têtes sont absents, incomplets ou mal configurés.

Ce n'est pas un détail cosmétique. L'absence de ces en-têtes laisse des vecteurs d'attaque ouverts que le navigateur pourrait bloquer nativement : clickjacking, MIME confusion, injection de ressources HTTP sur des pages HTTPS, vol de session facilité. Voici les six en-têtes qui comptent vraiment, et comment les configurer sans casser la production.

Strict-Transport-Security (HSTS)

HSTS force le navigateur à n'utiliser HTTPS que pour votre domaine, pour une durée donnée. Sans cet en-tête, un utilisateur qui tape monsite.com dans sa barre d'adresse fait d'abord une requête HTTP, qui est ensuite redirigée vers HTTPS. Ce premier aller-retour HTTP se passe en clair : il est interceptable par un attaquant en position Man-in-the-Middle sur le réseau.

Configuration recommandée

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

max-age=31536000 : le navigateur mémorise la règle pendant 1 an. includeSubDomains : tous les sous-domaines héritent de la règle. preload : permet d'inscrire votre domaine dans la liste HSTS préchargée des navigateurs (votre domaine sera forcé en HTTPS même à la toute première visite, avant même que le navigateur ait reçu l'en-tête). Commencez avec un max-age court (300 secondes) en phase de test, puis augmentez progressivement.

Content-Security-Policy (CSP)

La CSP est la défense en profondeur contre les attaques XSS. Elle dit au navigateur quelles sources de scripts, styles, images et autres ressources sont autorisées à se charger sur votre page. Un script injecté par XSS qui tente de charger du code depuis un domaine externe sera bloqué si ce domaine n'est pas dans la politique.

CSP stricte pour une SPA sans CDN externe

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; object-src 'none'; base-uri 'self'; frame-ancestors 'none';

La CSP est l'en-tête le plus complexe à déployer car une politique trop stricte casse les ressources légitimes. La bonne approche : déployer d'abord en Content-Security-Policy-Report-Only avec un endpoint de rapport, mesurer les violations pendant quelques jours, puis passer en mode bloquant. 'unsafe-inline' et 'unsafe-eval' dans script-src annulent une grande partie de la protection, à éviter.

X-Content-Type-Options

Cet en-tête empêche le navigateur de deviner (sniff) le type MIME d'une réponse. Sans lui, certains navigateurs ignorent le Content-Type déclaré et essaient de déduire le type du contenu à partir de son contenu réel. Un attaquant peut exploiter ce comportement : uploader un fichier texte contenant du JavaScript, le serveur le déclare text/plain, mais le navigateur le détecte comme text/javascript et l'exécute.

Configuration

X-Content-Type-Options: nosniff

C'est l'en-tête le plus simple à déployer. Il n'a qu'une valeur possible, pas d'effet de bord, et est supporté par tous les navigateurs modernes depuis des années. Il n'y a aucune raison valable de ne pas l'activer.

X-Frame-Options et frame-ancestors

Le clickjacking consiste à intégrer votre page dans un <iframe> invisible superposé à une autre page, pour piéger l'utilisateur en lui faisant cliquer sur des éléments de votre application sans le savoir. L'en-tête X-Frame-Options empêche votre page d'être embarquée dans une iframe.

Deux approches selon votre besoin

# Option 1 : interdire tout embedding (recommandé si vous n'utilisez pas d'iframes)
X-Frame-Options: DENY

# Option 2 : n'autoriser que le même domaine
X-Frame-Options: SAMEORIGIN

# Approche moderne via CSP (remplace X-Frame-Options)
Content-Security-Policy: frame-ancestors 'none';

La directive CSP frame-ancestors est plus flexible et remplace avantageusement X-Frame-Options dans les navigateurs modernes. Elle permet de définir une liste précise de domaines autorisés à embarquer votre page. Si vous utilisez les deux, frame-ancestors a priorité dans les navigateurs qui le supportent.

Contenu mixte

Le contenu mixte désigne le chargement de ressources HTTP (non chiffrées) depuis une page HTTPS. Un script chargé en HTTP sur une page HTTPS peut être modifié par un attaquant en position Man-in-the-Middle : le navigateur a établi une connexion sécurisée avec votre serveur, mais la ressource elle-même transite en clair sur le réseau.

Les navigateurs modernes bloquent le contenu mixte actif (scripts, iframes) mais peuvent encore charger du contenu mixte passif (images, CSS) selon la configuration. L'en-tête upgrade-insecure-requests demande au navigateur de transformer automatiquement toutes les requêtes HTTP en HTTPS :

Forcer HTTPS pour toutes les ressources

Content-Security-Policy: upgrade-insecure-requests;

Permissions-Policy

Cet en-tête contrôle l'accès aux API sensibles du navigateur : caméra, microphone, géolocalisation, accéléromètre, paiement. Il remplace l'ancien Feature-Policy. Il est particulièrement utile pour limiter ce que les scripts tiers (publicités, analytics) peuvent faire.

Désactiver les APIs non utilisées

Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()

Déploiement : Nginx, Apache, Netlify

Nginx

server {
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
  add_header X-Content-Type-Options "nosniff" always;
  add_header X-Frame-Options "DENY" always;
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;
  add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
  add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'" always;
}

Netlify (_headers)

/*
  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()
  Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'

Récapitulatif

  1. HSTS : force HTTPS, protège contre les attaques de downgrade et les interceptions sur le premier aller-retour HTTP
  2. CSP : défense en profondeur contre XSS, contrôle les sources de ressources autorisées. Déployer d'abord en report-only
  3. X-Content-Type-Options: nosniff : empêche le MIME sniffing. Aucune raison de ne pas l'activer
  4. X-Frame-Options / frame-ancestors : empêche le clickjacking en bloquant l'embedding dans des iframes
  5. upgrade-insecure-requests : force HTTPS pour toutes les ressources, élimine le contenu mixte
  6. Permissions-Policy : limite l'accès aux APIs sensibles du navigateur pour le code tiers

Une question après la lecture ?

Vous voulez un audit des en-têtes de sécurité de votre application ? Envoyez un message.

Ou réservez directement un cadrage de 30 minutes

Réserver un appel