Mise en place de headers de protection

L’hardening d’un serveur Apache2 passe par plusieurs étapes : configuration des virtual hosts, configuration du TLS etc… L’une des étapes qui est souvent oubliée ou en tout cas que je ne croise pas souvent lors de tests d’intrusion c’est la mise en place de headers de protections. Pourtant il existe tout un tas de headers qui vont vraiment vous permettre d’augmenter la sécurité de nos applications. Tout au long de cet article nous verrons comment implémenter huit d’entre eux.

I/ Header HSTS

Celui là nous avons déjà vu comment l’implémenter dans l’article sur la mise en place du SSL/TLS. Pour rappel HSTS est un header émis par un serveur web qui va indiquer au navigateur du client qu’il doit utiliser la version sécurisée d’HTTP (i.e : HTTPS). Ce header est surtout utilisé pour empêcher tout downgrade HTTP via Man In The Middle. Pour le mettre en place sous Apache2 il faudra ajouter cette ligne dans le fichier de configuration de votre virtual host :

Header always set Strict-Transport-Security: "max-age=63072000;include Subdomains;"

La directive max-age indique pour combien de temps la règle HSTS est valable tandis que la directive include indique que tous les sous domaines doivent aussi appliqués cette règle.

II/ Header CSP

Le header CSP (pour Content Security Policy) va nous permettre d’indiquer d’où peuvent être chargées les ressources de notre site web. Ce header est utilisé notamment pour mitiger les attaques via injection de code telles que les XSS. Ainsi un attaquant qui voudrait injecter du code hébergé sur l’URL « https://somewhere/inject.js » sera bloqué par la policy.

Bien évidemment cela n’empêchera pas tous les types d’XSS. En effet un attaquant sera toujours en mesure d’injecter son code JavaScript brut directement dans la page sans passer par un serveur distant.

En plus d’empêcher le chargement de JavaScript externe on va aussi pouvoir paramétrer le chargement des images, des vidéos ou encore des plugins. La liste complète étant disponible sur la documentation officiel du projet firefox.

Du coup si on voulait empêcher le chargement de script externe à notre site on pourrait le faire ainsi :

Content-Security-Policy: "default-src 'self'; script-src 'self'"

La valeur self indiquant que le contenu est chargé depuis notre serveur uniquement. A l’inverse si on veut indiquer que les scripts peuvent être chargés depuis le domaine somewhere.com on pourra le faire ainsi :

Content-Security-Policy: "default-src 'self'; script-src somewhere.com"

Et si vous voulez que les scripts soient chargés aussi depuis google.com alors on pourra le spécifier ainsi :

Content-Security-Policy: "default-src 'self'; script-src somewhere.com google.com"

Attention, si vous spécifiez un schéma HTTP il faudra que celui-ci soit respecté. Ainsi si dans votre policy vous autorisez le chargement de scripts depuis http://somewhere.com et que le chargement effectif se fait depuis https://somewhere.com alors une erreur sera levée.

Attention2 à l’attribut default-src. Celui-ci indique que pour chaque politique non définie dans le header CSP, les ressources associées ne pourront être chargées que depuis ‘self’.

Attention3, une mauvaise configuration du header CSP peut complètement bloquer votre application. Si vous bloquez le chargement de scripts externes alors vous ne pourrez plus utiliser les boutons de partage sur les réseaux sociaux (par exemple). Il convient donc de tester cette fonctionnalité en implémentant, pour commencer, le header Content-Security-Policy-Report-Only. En effet ce dernier ne bloquera pas le chargement de la ressource mais se contentera d’envoyer un rapport s’il y a violation de la policy.

Du coup pour implémenter le header CSP sous Apache2 on ajoutera cette ligne :

Header always set Content-Security-Policy: "default-src 'self'; script-src 'self'"

III/ X-XSS-Protection

Le header X-XSS-Protection est un header spécifique au navigateur Internet Explorer, Chrome et et Safari qui va leur permettre d’empêcher l’exécution d’XSS reflected quand elles seront repérées.

Il existe quatre mode de paramétrage :

  • 0: Le filtre anti XSS est désactivé.
  • 1: Le filtre anti XSS est activé et le code malicieux sera supprimé si détecté.
  • 1; mode-block: le filtre anti XSS est activé et le code malicieux sera bloqué sans pour autant être supprimé de la page.
  • 1; report=: le filtre anti XSS est activé et le navigateur supprimera le code malveillant en plus d’émettre un rapport vers l’URL spécifié.

Pour activer ce header sous Apache2 il faudra ajouter cette ligne dans le fichier de configuration du virtual host :

Header always set X-XSS-Protection: "1; mode=block"

A savoir que ce header n’est pas supporté par Firefox contrairement à Chrome, Safari ou Opera. Résultat les XSS ne seront pas stoppées sous Firefox :

LhLheader1.png

IV/ X-Frame-Options

Les balises iframe sont des balises HTML utilisées afin d’inclure du contenu venant d’un autre site. Par exemple le bloc twitter que vous trouvez sur la droite de la page d’accueil de ce blog est inclus via une iframe :

header2.png

Ce qui au final donne ceci:

header3.png

Pour plusieurs raisons un développeur web peut ne pas vouloir que le contenu de son site soit affiché sur un autre site. En effet il n’est pas rare que des attaquants incluent des morceaux d’applications distantes authentiques sur leurs propres applications malveillantes dans le but de mettre en confiance leurs victimes et ainsi les inciter à cliquer sur un lien, télécharger un fichier, entrer leurs numéros de carte bancaire etc…

Dans le cas où vous ne voulez pas que n’importe qui puisse inclure votre contenu sur son propre site on pourra le header X-Frame-Options. Le header X-Frame-Options peut avoir plusieurs valeurs :

  • DENY: empêche toute inclusion distante
  • SAMEORIGIN: autorise l’inclusion si elle vient de la même application
  • ALLOW-FROM https://example.com: autorise l’inclusion pour le site https://example.com
  • ALLOWALL: autorise toute inclusion

Du coup encore une fois pour inclure ce header sur votre serveur web il suffira d’ajouter cette ligne :

Header always set X-Frame-Options: "DENY"

De cette manière nul ne pourra inclure votre site dans le sien.

V/ Referrer-policy

Lorsque un utilisateur navigue sur un site web ou lorsqu’un site web charge une ressource externe, vous pourrez voir un header assez particulier : le header Referrer. Regardez maintenant sa valeur et vous verrez qu’elle contient le nom du site depuis lequel vous venez.

Ce header est surtout utilisé pour faire des statistiques et ainsi savoir d’où viennent les utilisateurs. Sur le panel d’administration WordPress de whiteflag je peux ainsi voir, plus ou moins, d’où viennent les personnes qui se connectent à mon site :

header4.png

Sur la capture ci-dessus on apprend que 56 personnes ont atterris sur mon site après avoir fait une recherche Google. Bon dans ce cas précis ce n’est pas bien intéressant mais globalement le header Referrer, niveau confidentialité, c’est pas top. Donc nous nous allons le désactiver.

Pour cela il faudra ajouter le header referrer-policy qui peut avoir huit valeurs différentes :

  • no-referrer: aucun header Referrer n’est émis
  • no-referrer-when-downgrade: aucun header Referrer n’est émis si la sécurité de la connection est downgradée (HTTPS vers HTTP)
  • origin: seul l’origine est envoyé dans le header (example si vous venez de https://somewebsite.com/somepage.html, seul la partie https://somewebsite.com/ sera émise dans le header)
  • origin-when-cross-origin: envoie l’origine, le chemin et le fichier si la requête est émise vers l’application elle même. Sinon n’envoie que l’origine.
  • same-origin: émet le header Referrer si la requête est émise vers la même application
  • strict-origin: n’émet le header Referrer que si la connexion garde le même niveau de sécurité (HTTPS vers HTTPS mais pas HTTPS vers HTTP)
  • strict-origin-when-cross-origin: émet le  header Referrer en entier (origine, chemin et fichier) si la requête cible la même application sinon n’émet que l’origine si le niveau de sécurité n’est plus identique (HTTPS vers HTTP)
  • unsafe-url: émet toujours le header Referrer (attention aux problématiques de confidentialité encore une fois).

Pour ajouter le header Referer-Policy avec la valeur no-referrer sous Apache2 on ajoutera cette ligne dans le fichier de configuration de notre virtual host:

Header always set Referrer-Policy: "no-referrer"

VI/ X-Content-Type-Options

Pour comprendre l’utilité de ce header il est nécessaire de connaître l’attaque « MIME sniffing ». Si vous ne la connaissez pas (ce qui était le cas pour moi lors de l’écriture de cet article) je vous recommande de lire cet article : « MIME Sniffing in browsers and the security implications« .

Globalement voilà ce qu’il faut retenir. Lorsque vous naviguez sur une page Internet des ressources multiples sont chargées (des images, du JavaScript, du texte etc…) Votre navigateur va ensuite parser toutes ces données afin de les rendre de la meilleure façon possible. C’est grâce à cette opération de parsing que les images ressemblent à des images et non pas à de la data brute.

Pour que cette opération de parsing soit fonctionnelle il faut que le navigateur connaisse le type de data qui lui est renvoyé. Cette information il la trouve généralement dans le header HTTP : « Content-Type ». Ci-dessous on peut voir que le contenu de la data envoyé par le serveur web qui héberge whiteflag.blog est text/html:

header5.png

Le serveur web a renvoyé le bon type MIME donc mon navigateur a pu afficher la donnée comme étant du texte. En revanche il peut arriver que le content type ne soit pas le bon (principalement à cause d’erreurs de programmation). Dans ce cas là le navigateur va tenter de détecter lui même le type de la donnée. Ce comportement c’est ce que l’on appelle le « MIME sniffing ».

Et là malheureusement les résultats peuvent être assez funky et parfois même mené à l’exploitation de vulnérabilités telles que des XSS.

Pour empêcher ce comportement du navigateur, on peut mettre en place le header X-Content-Type-Options qui va tout simplement indiquer aux navigateurs des clients de ne pas interpréter eux même le contenu des données reçues (on va leur dire de faire confiance au header Content-Type émis).

Ce header ne peut avoir qu’une seule valeur : nosniff et pour l’implémenter sous Apache2 il faudra ajouter cette ligne :

Header always set X-Content-Type-Options: "nosniff"

VII/ Feature-Policy

Un navigateur dispose de pleins de fonctionnalités différentes. Par exemple il pourra accéder à votre caméra, votre microphone ou encore votre localisation géographique. Toutes ces petites fonctionnalités sont ce que l’on appelle des browser features. Pour certaines applications ça peut être cool d’avoir ces features mais pour d’autres ce n’est clairement pas nécessaire.

Avec le header Feature-Policy on pourra tout simplement les désactiver. Le header Feature-Policy peut avoir cinq valeurs différentes :

  • *: le feature est valide pour cette page et toutes les iframes incluant cette page
  • self: le feature est valide pour cette page et toutes les iframes ayant la même origine.
  • src: le feature est valide pour cette iframe
  • none: le feature est désactivé globalement
  • origin: le feature est activé pour certaines origines.

Ainsi si on veut désactiver l’utilisation de la caméra on pourra ajouter le header Feature-Policy sous Apache2 de cette manière :

Header always set Feature-Policy: "camera 'none'"

VIII/ Flag Secure et HttpOnly

Dans la foulé on pourra aussi éditer les flags de nos cookies de manière à ce qu’ils soient sécurisés contre les attaques via XSS. Pour cela il faudra ajouter les flags Secure et HttpOnly de cette manière :

Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure

Au final le fichier de configuration de mon virtual host ressemble à ça :

header6.png

Et la réponse de mon serveur sera la suivante:

header7.png