Guides 6 min de lecture

En-têtes de sécurité HTTP : lesquels envoyer et comment les vérifier

HSTS, Content-Security-Policy, X-Content-Type-Options, protection contre l’affichage en cadre, Referrer-Policy et Permissions-Policy : le rôle de chacun et une valeur sûre pour commencer.

Les en-têtes de sécurité HTTP sont des en-têtes de réponse qui demandent au navigateur d’appliquer des protections que votre site devrait sinon mettre en place lui-même : rester en HTTPS, n’exécuter que des scripts provenant de sources de confiance, ne pas deviner les types de fichiers, empêcher d’autres sites d’afficher la page dans un cadre, et en dire moins sur la provenance d’un visiteur. Six en-têtes couvrent l’essentiel : Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, X-Frame-Options (ou la directive frame-ancestors de la CSP), Referrer-Policy et Permissions-Policy. La plupart tiennent en une ligne de configuration serveur. Content-Security-Policy demande de la préparation : commencez donc en mode Report-Only.

Les six en-têtes en un coup d’œil

En-têteProtège contreUne valeur pour commencerStrict-Transport-SecurityLes connexions rétrogradées en HTTP simplemax-age=31536000Content-Security-PolicyLes scripts injectés (cross-site scripting)Une politique d’abord testée en Report-OnlyX-Content-Type-OptionsLes navigateurs qui exécutent un fichier comme un autre typenosniffX-Frame-Options ou frame-ancestorsLe clickjacking via des cadresSAMEORIGIN et frame-ancestors ‘self’Referrer-PolicyLes adresses complètes qui fuient vers d’autres sitesstrict-origin-when-cross-originPermissions-PolicyLes demandes d’accès à des fonctions du navigateur inutiliséescamera=(), microphone=(), geolocation=()

Strict-Transport-Security (HSTS)

Même avec une redirection de HTTP vers HTTPS, un visiteur qui tape votre domaine envoie la première requête en HTTP simple, où elle peut être lue ou modifiée en chemin. HSTS indique au navigateur d’utiliser désormais HTTPS pour votre domaine, pendant la durée fixée par max-age, en secondes :

Strict-Transport-Security: max-age=31536000

Commencez court. Les navigateurs appliquent HSTS jusqu’à son expiration : une erreur reste donc en place. Essayez max-age=300 pendant quelques jours, puis passez à un an (31536000).

includeSubDomains applique la règle à tous les sous-domaines. Ne l’ajoutez que lorsque tous fonctionnent en HTTPS, y compris les vieux serveurs de préproduction et de messagerie.

preload demande l’intégration du domaine dans les navigateurs via hstspreload.org, ce qui exige un max-age d’au moins un an et includeSubDomains. Le retrait prend beaucoup de temps : considérez-le comme définitif.

Les navigateurs ignorent HSTS sur les réponses en HTTP simple. Envoyez-le en HTTPS, et gardez un œil sur le certificat : avec HSTS, impossible de passer outre un certificat expiré.

Content-Security-Policy

Une Content Security Policy liste les sources depuis lesquelles la page peut charger scripts, styles, images, polices et cadres, et les adresses vers lesquelles les formulaires peuvent envoyer leurs données. Si un attaquant parvient à glisser un script dans la page, via un champ de commentaire ou une extension compromise, le navigateur refuse de l’exécuter tant que la politique n’autorise pas sa source. C’est le plus efficace des six, et le plus facile à mal configurer : une politique trop stricte casse vos propres outils d’analyse, votre widget de chat ou votre formulaire de paiement.

Commencez par Report-Only

Envoyez d’abord la politique sous la forme Content-Security-Policy-Report-Only. Le navigateur n’applique rien, mais signale chaque violation à l’adresse indiquée dans report-uri (ou dans le plus récent report-to) et l’affiche dans la console. Un point de départ pour un site qui sert ses propres fichiers :

Content-Security-Policy-Report-Only: default-src ‘self’; script-src ‘self’; style-src ‘self’; img-src ‘self’ data:; font-src ‘self’; object-src ‘none’; base-uri ‘self’; form-action ‘self’; frame-ancestors ‘self’; report-uri /csp-report

Parcourez le site, collectez les rapports pendant une semaine ou deux, et ajoutez les sources que vous utilisez vraiment, comme votre outil d’analyse ou votre prestataire de paiement. Quand les rapports ne montrent plus que ce que vous voulez bloquer, envoyez la même politique sous la forme Content-Security-Policy.

Scripts inline : des nonces, pas unsafe-inline

Une politique stricte bloque les blocs <script> inline et les attributs onclick, puisqu’un script injecté leur ressemble trait pour trait. Ajouter ‘unsafe-inline’ fait disparaître le problème, et avec lui l’essentiel de la protection. À la place, attribuez à chaque réponse un nonce aléatoire, déclarez-le dans la politique sous la forme ‘nonce-…’ et placez la même valeur sur vos propres balises script ; déplacez les gestionnaires d’événements inline dans des fichiers de script. Les gestionnaires de balises qui injectent leurs propres scripts demandent une attention particulière, car chaque balise qu’ils ajoutent doit aussi être autorisée.

X-Content-Type-Options

Les navigateurs devinaient autrefois le type d’un fichier d’après son contenu quand le Content-Type envoyé par le serveur semblait faux. Une « image » téléversée pouvait ainsi s’exécuter comme un script. X-Content-Type-Options: nosniff désactive cette devinette. Il n’a qu’une seule valeur valide et aucun inconvénient connu, tant que votre serveur envoie des types de contenu corrects : envoyez-le donc sur chaque réponse.

X-Frame-Options et frame-ancestors

Lors d’une attaque par clickjacking, un autre site affiche votre page dans un cadre invisible et pousse les visiteurs à cliquer sur ses boutons. X-Frame-Options: DENY interdit tout affichage en cadre, et SAMEORIGIN ne l’autorise que pour vos propres pages. La directive CSP frame-ancestors fait la même chose avec plus de contrôle, par exemple une liste de sites partenaires, et prime dans les navigateurs qui la prennent en charge. Envoyez les deux : frame-ancestors pour les navigateurs actuels, X-Frame-Options pour les plus anciens. L’ancienne valeur ALLOW-FROM n’est plus prise en charge : utilisez frame-ancestors pour tout ce qui va au-delà de votre propre origine.

Referrer-Policy

Quand un visiteur suit un lien, le navigateur indique au site suivant d’où il vient dans l’en-tête Referer. Sans limite, cela peut être l’adresse complète, y compris une recherche, un jeton de réinitialisation ou un numéro de commande présent dans l’URL. strict-origin-when-cross-origin envoie l’adresse complète au sein de votre site, seulement le domaine aux autres sites, et rien du tout de HTTPS vers HTTP. C’est le comportement des navigateurs actuels quand l’en-tête est absent, mais l’envoyer rend le choix explicite. Utilisez no-referrer sur les pages dont l’URL contient des données privées, et évitez unsafe-url, qui envoie tout, partout.

Permissions-Policy

Permissions-Policy, anciennement Feature-Policy, désactive les fonctions du navigateur que votre site n’utilise pas, pour la page et pour chaque cadre qui y est intégré. Une liste vide, (), signifie que personne ne peut utiliser la fonction :

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

Laissez de côté les fonctions que vous utilisez, ou autorisez-les pour votre propre origine avec (self), par exemple payment=(self) sur une boutique dotée d’un bouton de paiement.

Les en-têtes dont vous pouvez vous passer

X-XSS-Protection pilotait un filtre que les navigateurs actuels ont supprimé. Omettez-le, ou envoyez 0.

Expect-CT et Public-Key-Pins sont obsolètes. L’épinglage pouvait empêcher les visiteurs d’accéder à un site, c’est pourquoi les navigateurs l’ont abandonné.

Server et X-Powered-By ne sont pas des en-têtes de sécurité, mais les numéros de version exacts qu’ils contiennent aident les attaquants à choisir une faille. Réduisez-les dans la mesure où votre serveur le permet.

Où les définir

Définissez les en-têtes à un seul endroit, aussi près de la périphérie que possible : le serveur web, le CDN ou le middleware de l’application. Dans nginx et Apache :

# nginx (in the server block)
add_header Strict-Transport-Security « max-age=31536000 » always;
add_header X-Content-Type-Options « nosniff » always;
add_header X-Frame-Options « SAMEORIGIN » always;
add_header Referrer-Policy « strict-origin-when-cross-origin » always;
add_header Permissions-Policy « camera=(), microphone=(), geolocation=() » always;

# Apache (.htaccess or virtual host, with mod_headers)
Header always set X-Content-Type-Options « nosniff »
Header always set Referrer-Policy « strict-origin-when-cross-origin »

Deux subtilités de nginx piègent souvent. Sans always, les en-têtes ne sont ajoutés qu’aux réponses réussies, pas aux pages d’erreur. Et un bloc location qui possède ne serait-ce qu’un add_header perd tous ceux du bloc server : un simple en-tête de cache pour les images peut ainsi supprimer en silence vos en-têtes de sécurité à cet endroit. Méfiez-vous aussi d’un même en-tête défini deux fois, par le serveur et par l’application ou le CDN : les navigateurs gèrent les doublons différemment selon l’en-tête, alors confiez chacun à un seul responsable.

Comment vérifier vos en-têtes

Depuis un terminal, curl -sI https://example.com affiche les en-têtes de réponse. Vérifiez aussi l’adresse finale après redirections, une page d’erreur et un fichier statique, car chacun peut être servi par une partie différente de votre infrastructure. Dans un navigateur, l’onglet Réseau des outils de développement affiche les en-têtes de chaque requête, et la console montre les violations CSP.

Ou utilisez notre vérificateur d’en-têtes HTTP gratuit. Il liste tous les en-têtes envoyés par une URL après avoir suivi les redirections, signale lesquels des six en-têtes de sécurité manquent, repère quelques valeurs qui les annulent, comme un max-age HSTS trop court, une CSP uniquement en Report-Only ou unsafe-url, et montre comment la page est mise en cache et où passe le temps. Il vérifie que les en-têtes sont présents ; il n’évalue pas ce qu’autorise une Content Security Policy, à vous donc de la relire.

Empêchez-les de disparaître

Les en-têtes de sécurité cassent rarement de façon visible. Ils disparaissent quand un site change de serveur, de CDN, qu’une extension est mise à jour ou que quelqu’un ajoute un bloc location, et le site continue de fonctionner, donc personne ne s’en aperçoit. Un moniteur HTTP de la surveillance de disponibilité d’Uptimecheck peut vérifier les en-têtes de réponse à chaque requête, jusqu’à 10 vérifications de réponse par moniteur, par exemple :

Strict-Transport-Security existe.

X-Content-Type-Options est égal à nosniff.

Content-Security-Policy contient frame-ancestors.

Chaque vérification doit être satisfaite pour que le moniteur soit considéré comme en ligne : un en-tête manquant le fait passer en panne, une seconde vérification le confirme, et vous recevez une alerte. Placez les vérifications d’en-têtes sur un moniteur dédié si vous ne voulez pas qu’elles pèsent sur la disponibilité de la page. Les vérifications tournent jusqu’à toutes les minutes depuis Stockholm, Londres et New York ; consultez comment surveiller un endpoint d’API pour configurer les vérifications de réponse, et la checklist de maintenance d’un site web pour le reste de la routine.

Sachez le jour même qu’un en-tête a disparu. Essayez Uptimecheck gratuitement pendant 14 jours, sans carte bancaire.

Questions

Quels en-têtes de sécurité HTTP tout site web devrait-il envoyer ?

Strict-Transport-Security, X-Content-Type-Options: nosniff, X-Frame-Options ou une directive CSP frame-ancestors, Referrer-Policy et Permissions-Policy sont simples à ajouter. Content-Security-Policy offre la meilleure protection, mais doit d’abord être testée en mode Report-Only.

Qu’est-ce que Content-Security-Policy-Report-Only ?

La même politique que Content-Security-Policy, mais le navigateur se contente de signaler ce qu’il aurait bloqué au lieu de le bloquer. Utilisez-la pour identifier les sources dont votre site a réellement besoin avant d’appliquer la politique.

Ai-je encore besoin de X-Frame-Options si j’utilise frame-ancestors ?

Les navigateurs actuels suivent frame-ancestors et ignorent X-Frame-Options quand les deux sont présents. Envoyer les deux ne coûte rien et protège les visiteurs qui utilisent d’anciens navigateurs.

X-XSS-Protection est-il encore nécessaire ?

Non. Le filtre qu’il pilotait a été supprimé des navigateurs actuels. Omettez l’en-tête ou envoyez 0, et appuyez-vous plutôt sur une Content Security Policy.

À lire aussi

Guides 6 min de lecture

Site en panne ? La checklist de dépannage étape par étape

Votre site est en panne et vous devez savoir pourquoi. Passez en revue dans l’ordre le DNS, la connexion, le certificat, le CDN, le serveur et l’application, avec un test rapide pour chacun.

Lire

Guides 6 min de lecture

Budget d’erreur : définition et mode d’emploi

Comment calculer un budget d’erreur à partir d’un SLO, ce qui le consomme, comment fonctionne le burn rate et comment rédiger une politique de budget d’erreur que votre équipe respectera vraiment.

Lire

Les pannes, c’est du passé.

Configurez votre premier moniteur en moins d’une minute, ou explorez d’abord la démo en ligne.

Essai gratuit de 14 jours · Puis gratuit pour 5 moniteurs · Sans carte bancaire