The Daily Shaarli
TL;DR : HSTS c'est bien si ta conf' TLS est propre ; HPKP c'est du passé ; Expect-CT me semble être en partie aussi pipeau que CAA ; Referrer-Policy est cool au sein d'un intranet / webmail / agrégateur RSS web ou autre ressource web privée et inutile au-delà ; X-Frame-Options, c'est du passé ; X-XSS-Protection et X-Content-Type-Options, ça ne mange pas de pain même si le gain est faible et que ce n’est pas encore normalisé ; Content-Security-Policy est loin d'être simple en pratique, même sur un logiciel qui se veut être simple comme Shaarli, car ça nécessite une parfaite connaissance du code de l'application web et des compromis utilisabilité / sécurité qui me semblent être très vite déconnants.
Toujours à la recherche de la hype en 2020 et m'étant fait tej' par TLS 1.3 et HTTP/2, je me demande quels entêtes HTTP trop stylés ajouter dans la configuration de mes serveurs web.
HTTP Strict Transport Security (HSTS), c'est plié : j'utilise une autorité de certification x509 maison, ce qui est incompatible.
HTTP Public Key Pinning Extension for HTTP (HPKP), c'est compliqué. On a vite fait de faire de grosses erreurs durables (même contre sa volonté, en raison de la fluctuation de ce que les autorités de certification incorporent dans un certificat x509 et en fonction des implémentations logicielles…), ce qui bloque l'accès au site web. Ça serait un deal à examiner si je n'avais pas déployé DANE TLSA, une solution concurrente au même problème qui propose une deuxième chaîne de certification via le DNS. De plus, je ne pense pas qu'un faux certificat x509 émis pour mon petit site de bouseux fasse partie de mon modèle de menaces… Au final, HPKP a été déprécié par son créateur, Google et retiré de Chrome. Affaire classée, donc.
Expect-CT indique au navigateur web de vérifier que le certificat x509 présenté par le serveur est bien publié dans Certificate Transparency, une base de donnée publique dans laquelle les autorités de certification peuvent ajouter (impossible de modifier et de supprimer) tous les certificats qu'elles génèrent… sauf quand elles se font vraiment pirater jusqu'à l'os. C'est là le hic. Je ne suis donc pas convaincu du gain foudroyant apporté par cet entête. De toute façon, j'utilise une autorité de certification maison qui ne publie donc pas dans Certificate Transparency, donc je ne suis pas éligible.
Referrer-Policy indique au navigateur web si, quand un utilisateur clique sur un lien présent sur un site web, il doit dire au site web de destination d'où il vient. On peut interdire toute communication ou demander à ce que seul le domaine soit communiqué et faire des mélanges genre communiquer l'URL complète si la destination du lien est le même site web et ne rien dire si la destination est externe, par exemple. Même possibilité de mélange si le site web de destination propose le même niveau de sécurité (comprendre HTTPS) que le site web source ou non. Je suis mitigé. Je vois très bien l'intérêt de cet entête pour un intranet ou un webmail ou un agrégateur RSS web , par exemple, mais pas pour mes sites web persos… Des extensions pour navigateurs web, comme Smart Referer permettent déjà de configurer l'envoi (ou non) du referrer, et, au moins, ça fonctionne pour tous les sites web consultés par un utilisateur, pas juste pour ceux qui ont mis un entête. L'utilisateur ne devrait pas compter sur l'administrateur d'un site web pour préserver sa vie privée. ÉDIT DU 07/04/2020 à 23 h 25 : cela permet à des adminsys de réduire (un peu, mais à moindre coût) le flicage des sites web qu'ils hébergent. FIN DE L'ÉDIT.
X-Frame-Options est déprécié et est remplacé par l'attribut « frame-ancestors » dans la version 2 de Content Security Policy, donc affaire classée.
X-XSS-Protection indique au navigateur web de bloquer les tentatives d'exploitation de failles XSS les plus triviales. Ça ne mange pas de pain. J'ajoute donc cet entête à mes configurations : X-XSS-Protection "1; mode=block".
X-Content-Type-Options indique au navigateur de ne plus faire de MIME sniffing, c'est-à-dire d'interprétation du type d'un fichier quand le serveur web ne le précise pas ou que le navigateur web pense qu'il est erroné. Ça évite des attaques par fichiers malveillants spécifiquement fabriqués pour une attaque. Son utilisation suppose que le site web qui envoie cet entête soit irréprochable sur les types de fichier qu'il envoie. Mais, contrairement à HPKP, il n'y a pas de sanction durable dans le temps si ce n'est pas le cas. Donc ça ne mange pas de pain, donc j'ajoute cet entête à mes configurations : X-Content-Type-Options "nosniff".
Content-Security-Policy. J'en ai déjà parlé, expliqué ce que c'est, etc.. Dans la pratique, son usage n'est pas si simple et suppose une grande maîtrise du code du site web auquel cet entête sera appliqué. Exemple concret : j'ai voulu ajouter CSP à mon shaarli, car je considère qu'il s'agit d'une application web toute simple. Grosse erreur.
Au début, j'envisageais de positionner la valeur « default-src 'none'; frame-ancestors 'none'; script-src 'none'; style-src 'self'; img-src 'self'; form-action 'self'; ». Dans l'ordre, ça dit ce qui suit. Tout ce qui n'est pas défini sera bloqué. Ce site ne peut pas être inclus dans un autre. Le seul CSS autorisé est celui provenant de la même origine (même protocole + nom de domaine + port). Même chose pour les images (comme les miniatures de vidéos ou d'images proposées par shaarli). Les formulaires peuvent uniquement être envoyés à une cible de même origine.
Rien que là, il y a des pièges. Il y a les non-dits, comme le fait que les scripts « inline » (insérés directement dans le XHTML) sont interdits de base sauf mention explicite. Il y a des différences de comportements. Je n'ai pas besoin de préciser « script-src », « font-src », « child-src », « object-src », « manifest-src », « media-src », « worker-src », « connect-src » car, en cas d'absence, un repli sur « default-src » est prévu. En revanche, il n'y a pas de repli pour form-action ou frame-ancestors, donc aucun blocage par défaut. Il y a des subtilités. « plugin-types » est un sous-type de « object-src », par exemple. Il faut donc lire la norme ou sa vulgarisation avec attention, ce qui est jamais top en matière de sécurité.
Ensuite, la définition CSP toute simple ci-dessus ne fonctionne pas avec shaarli.
Du coup, pour un shaarli qui semble être fonctionnel, il faut la CSP default-src 'none'; frame-ancestors 'none'; script-src 'self' 'unsafe-inline'; style-src 'self'; img-src * data:; media-src 'self'; form-action 'self';. Si l'on est prêt à sacrifier les miniatures de vidéos Youtube (et sites externes), la CSP suivante suffit : default-src 'none'; frame-ancestors 'none'; script-src 'self' 'unsafe-inline'; style-src 'self'; img-src 'self' data:; media-src 'self'; form-action 'self';. Et tout ça, sans être sûr que j'ai bien identifié tous les problèmes…
CSP est une bonne idée, mais il faut connaître parfaitement son application web. Et même en la connaissant, il faut autoriser de gros trous dans la raquette pour qu'elle fonctionne, ce qui diminue d'autant la sécurité apportée par CSP. Et encore, j'ai travaillé sur une application web qui se veut être simple, qu'est-ce que ça doit être avec n'importe quel CMS, site web pseudo-moderne ou application web Java ! Imagine les ressources externes (police récupérée ici, JavaScript récupéré chez Google, etc.). Imagine l'interférence des CDN (réseaux de distribution de contenus à l'échelle de la planète) et les possibilités de rendre caduque CSP que cela offre.
Bref, hors de question que je me prenne la tête avec CSP.
TL;DR : HTTP/2 est possible uniquement au-dessus de TLS avec nginx. HTTP/2 est possible avec ou sans TLS avec Apache httpd, mais, avec un système Debian GNU/Linux Stretch cela nécessite mpm_event ou mpm_worker (c'est recommandé par la fondation Apache pour Debian Buster et autres systèmes), ce qui, dans mon cas, signifie migrer préalablement vers PHP FPM. Bref, j'ai encore du taff.
Que faire en 2020 pour avoir la hype alors qu'on est un retardataire blasé par le progrès technique ? Activer TLS 1.3, la nouvelle version du protocole de sécurisation (confidentialité, authenticité et intégrité) des communications sur Internet ? Le retardataire a uniquement des systèmes Debian Stretch qui livrent la version 1.1.0 d'OpenSSL. Or, la version 1.3 de TLS nécessite la version 1.1.1 d'OpenSSL au minimum.
Bon bah alors, activer HTTP/2, le nouveau protocole qui soutient le web ? Faisons ça, avec Apache httpd et nginx.
Avec la version d'Apache httpd packagée dans la version Stretch de Debian GNU/Linux, il n'est pas possible d'activer HTTP/2 avec le module de multitraitements mpm_prefork (source, confirmé par /usr/share/doc/apache2/NEWS.Debian.gz). Notons que la documentation officielle Apache httpd ne recommande pas d'activer HTTP/2 avec mpm_prefork et préconise plutôt l'utilisation de mpm_event.
Oui, mais avec mpm_event (ou mpm_worker), il n'est pas possible d'utiliser le module PHP pour Apached httpd (car mpm_event est multithread, pas le module PHP). Il faut utiliser FPM ou FastCGI. Hé ouais, le retardataire utilise encore le module PHP…
Du coup, le test de HTTP/2 se fait ainsi :
a2dismod php7.0 ;a2dismod mpm_prefork && a2enmod mpm_event ;apt-get install libgcc-6-dev ;/etc/apache/apache2.conf : LoadFile /usr/lib/gcc/x86_64-linux-gnu/6/libgcc_s.so.1 ;a2enmod http2 ;Protocols h2 h2c http/1.1 dans /etc/apache2/mods-available/http2.conf). On peut surcharger ça dans un serveur virtuel. Pour un serveur virtuel HTTPS (TLS), la ligne de config' est Protocols h2 http/1.1. Pour un serveur virtuel HTTP, la ligne de config' est : Protocols h2c http/1.1. On peut aussi mettre du h2c dans du TLS, le module sait faire avec même si ça produira aucun effet ;systemctl restart apache2.J'ai jamais eu de PHP sur mon serveur web géré par nginx et il y a jamais eu d'histoire de module de pré-traitement avec nginx. Du coup, l'activation d'HTTP/2 devrait être plus facile que pour Apache httpd, non ? Oui avec un serveur virtuel HTTPS (TLS), non avec un serveur virtuel HTTP.
systemctl restart nginx.Sans TLS, le client web ne peut pas utiliser l'extension TLS ALPN (Application Layer Protocol Negociation) pour indiquer qu'il veut communiquer en HTTP/2.
Le client web pourrait causer HTTP/1.1 et positionner l'entête « Upgrade: h2c » qui est l'un des mécanismes permettant de monter en HTTP/2, mais nginx ne permet pas cela.
Il reste une possibilité : que le serveur positionne un entête HTTP Alternative Services qui indique au client que le même service est disponible en HTTP/2. Le client web cause alors en HTTP/2 en utilisant la méthode « prior knowledge » (différente de TLS + ALPN et de HTTP/1.1 + entête Upgrade). Sauf que, si l'on positionne la directive de configuration « http2 » sur une socket HTTP, nginx cause directement HTTP/2, donc pas de HTTP/1.1 (ou 1.0) avec un entête pour informer le client web. Donc le serveur virtuel devient accessible uniquement en HTTP/2. Il faudrait que le serveur virtuel port 80 positionne cet entête en redirigeant vers un serveur virtuel sur le port 81, par exemple. Sauf que, à ce jour, les clients web (cURL y compris) n'implémentent pas les services alternatifs HTTP.
Si l'on veut, on peut activer HTTP/2 comme dans un serveur virtuel HTTPS et tester avec curl -D - --http2-prior-knowledge <URL>. Mais, pour rappel, ton site web ne sera plus accessible en HTTP/1.1 ou HTTP/1.0. Ni en HTTP/2 avec la plupart des clients web actuels.
Apache httpd ou nginx, il faut tester le bon fonctionnement des manipulations décrites ci-dessus.
On peut tester avec curl -D - --http2 <URL> (« -D - » permet d'afficher les entêtes HTTP de la réponse, donc de vérifier la présence d'un « HTTP/2 » dès la première ligne).
On peut aussi utiliser l'onglet réseau des outils de développement de Firefox, mais, attention si tu utilises HTTP (non sécurisé) : Firefox ne positionne pas l'entête HTTP/1.1 « Upgrade: h2c » qui est l'un des mécanismes permettant de monter en HTTP/2. Curl le positionne. Bref, toujours avoir un wireshark en bandoulière.
On peut enfin regarder le journal des requêtes sur son serveur web, car la version y est mentionnée genre « GET / HTTP/2.0 ».
Bref, HTTP/2 avec Apache httpd, ça fonctionne, mais ça nécessite que je migre du module PHP à PHP-FPM ou que je mette à jour mon système vers la version Buster de Debian. Avec nginx, HTTP/2 fonctionne uniquement au-dessus de TLS en attendant que les clients web prennent en charge les services alternatifs HTTP ou que nginx gère h2c (« HTTP/2 in clear ») sans connaissance préalable de la part du client.
