Voilà, plus d'un an après les révélations de
Snowden, ce blog est enfin sécurisé par
HTTPS. Avant de vous précipiter pour vous
connecter à https://www.bortzmeyer.org/
, il est prudent
de lire quelques avertissements.
L'intérêt de TLS (et de son utilisation pour
le Web, HTTPS) pour sécuriser un site ne se
discute plus. C'est conseillé à la fois par
l'ANSSI (dans ses « Recommandations
pour la sécurisation des sites web » : « Le recourt [sic] à TLS, c’est à dire [re-sic] l’emploi du protocole HTTPS, est recommandé dès lors que les
communications entre le client et le serveur doivent être protégées en
confidentialité ou en intégrité »), mais également par tous les
hackers, darknetteurs, cryptoterroristes, cipherpunks, etc. Depuis
qu'Edward Snowden a courageusement publié
plein de détails sur l'intensité de l'espionnage de masse sur le Web,
c'est encore plus crucial. Sans TLS, n'importe qui peut savoir ce que
vous regardez sur ce blog, quelles recherches vous faites, et un attaquant actif
peut même modifier le contenu des pages avant qu'elles ne vous
arrivent, me faisant dire encore plus n'importe quoi que d'habitude
(voir un joli exemple avec Haka).
Alors, pourquoi cet avertissement au début, vous suggérant de ne
pas vous précipiter ? C'est parce que j'ai fait le choix d'une
autorité de certification que votre
navigateur Web ne connait peut-être pas. Pour
comprendre, il faut revenir au modèle de TLS (et donc de
HTTPS). Client et serveur se mettent d'accord sur un mécanisme de
chiffrement et sur ses paramètres, comme la
clé. Une fois le chiffrement en route, un attaquant passif ne peut
plus comprendre le contenu des communications (mais il peut toujours
regarder qui communique, donc savoir que vous parlez à mon serveur) et
un attaquant actif ne peut plus le modifier sans que ce soit
détecté. Mais il reste un problème : comment le client peut-il savoir
qu'il parle au vrai serveur et pas à un homme du
milieu, un serveur qui se serait glissé au milieu de la
conversation ? (Il existe plusieurs techniques pour être homme du
milieu. Le domaine bortzmeyer.org
étant signé
avec DNSSEC, cela en élimine une,
l'empoisonnement DNS, mais il en reste
d'autres.) Ce genre d'attaques est fréquent : beaucoup d'entreprises
font cela pour surveiller leurs employés, par exemple, et il existe
une offre commerciale pour cela (par exemple,
Blue Coat se vante d'être
capable de « visibility of SSL [sic] -encrypted traffic
(including the ability to stream decrypted content to an external
server with an Encrypted Tap license) ». C'est réalisé en
détournant le trafic dans le routeur de sortie
et en l'envoyant à un équipement qui déchiffre et rechiffre après,
pour l'envoyer au vrai serveur après examen. Cela se fait aussi au
niveau des États (en Iran, par exemple).
Comment est-ce que TLS se protège contre ce genre d'attaques ? En
authentifiant le
serveur : il existe plusieurs techniques pour cela mais la plus
courante, de loin, est d'utiliser un certificat
à la norme X.509 (souvent appelé, par très gros abus de langage, « certificat SSL »). Ce certificat est composé
d'une clé publique et de diverses métadonnées,
notamment un nom (en X.509, on dit un sujet) comme
www.bortzmeyer.org
, et une signature de la clé publique par
une autorité de certification (AC). Le client TLS va
vérifier la signature des messages (prouvant que le serveur connait
bien la clé privée) et la signature du certificat (prouvant que l'AC a
validé que le certificat appartenait bien au titulaire légitime du
nom). Quelles sont les autorités de certification acceptées ? Eh bien,
c'est justement le piège : il n'existe pas de liste officielle, chacun
a la sienne, stockée dans son magasin de certificats, et un même site Web peut donc parfaitement être accepté
sans histoires par un navigateur et rejeté par un autre. En pratique,
la plupart des utilisateurs font une confiance aveugle aux auteurs de
leur navigateur Web (Mozilla,
Google, Microsoft, etc)
et utilisent sans se poser de questions les AC incluses par défauts
dans les navigateurs. Cela marche à peu près, tant qu'une AC ne trahit
pas (par exemple, au Ministère
des finances français).
Mais le problème est qu'on ne peut jamais être sûr que son
certificat sera accepté partout. Pour limiter les risques, la plupart
des webmestres ne prennent pas de risques et
font appel à une des grosses AC connues partout. Ce n'est pas
satisfaisant, ni du point de vue de la sécurité, ni du point de vue du
business (il devient très difficile d'introduire
une nouvelle AC, la concurrence reste donc assez théorique). J'ai
choisi une AC qui est très simple à utiliser, rend un bon service, et est
contrôlée par ses utilisateurs, CAcert. Mais CAcert est dans peu de magasins et,
si vous visitez mon blog en
HTTPS, il y a des chances que vous ayiez un message d'erreur du
genre « Unknown issuer ». Ce n'est pas
satisfaisant, je le sais mais, comme je ne fais pas de
e-commerce sur ce blog et que je ne manipule pas de
données personnelles, je trouve que c'est acceptable et que c'est
l'occasion de faire de la publicité pour les AC « alternatives ». Je
vous encourage donc à ajouter le certificat de
CAcert à votre magasin (j'ai mis un lien HTTP ordinaire car, si
vous n'avez pas déjà le certificat CAcert, le HTTPS vous donnera une
erreur : vous devez vérifier l'empreinte du
certificat par un autre moyen). Au fait, pour les utilisateurs
d'Android, on me souffle que sur un téléphone
non rooté, il faut passer par les paramètres Sécurité > Installer depuis stockage. En tout
cas, ça a bien marché sur mon Fairphone rooté.
Bien sûr, il y a d'autres AC, plus traditionnelles et qui auraient
créé moins de surprises à mes visiteurs. Certaines sont très chères
et, surtout, l'obtention d'un certificat nécessite un processus
compliqué (et pas forcément plus sûr). En revanche, on m'a souvent
cité StartSSL comme bonne AC assez
reconnue. J'ai réussi à m'y créer un compte (non sans difficultés car
ils testent l'adresse de courrier, non pas par la bonne méthode
- envoyer un courrier - mais en faisant une connexion SMTP directe, ce qui
pose un problème avec le
greylisting et génère un
stupide message d'errreur « We were not able to verify your
email address! Please provide us with a real email
address! »). Je testerai plus loin un autre jour. À noter
que ce débat « AC commerciales privées ou bien CAcert » agite tous les
acteurs du libre, par exemple
LinuxFr, qui utilise également CAcert (pour ces
raisons), ce qui suscite de vigoureuses
discussions (merci à Patrick Guignot pour les références).
En raison de cettte méconnaissance de CAcert par beaucoup de
magasins, je n'ai donc pas imposé HTTPS (par exemple, http://www.bortzmeyer.org/
ne redirige pas d'autorité vers
https://www.bortzmeyer.org/
). Pour la même raison, je
n'ai pas mis d'en-tête HSTS (RFC 6797) car HSTS ne permet pas d'erreur : tout problème est
fatal.
Bien sûr, une solution à ce problème des AC non connues est
d'utiliser DANE (RFC 6698
et mon article à JRES). C'est sur
ma liste des choses à faire (ceci dit, tant qu'aucun navigateur ne
fait du DANE, cela limite l'intérêt).
Bon, assez parlé de ce problème des autorités de certification. Un
autre sujet de dispute quand on configure TLS est le choix des
algorithmes cryptographiques utilisés. TLS (RFC 5246) permet en effet un large choix, qui va être
présenté par le client, et parmi lequel le serveur choisira. Il est donc
important de ne pas proposer d'algorithmes qui
soient trop faibles. Les sélections par défaut des logiciels utilisés
pour faire du TLS sont en général bien trop larges. Cela convient au
webmestre (car cela augmente les chances d'accepter tous les clients,
même les plus anciens ou bogués) mais moins à l'auditeur de
sécurité. Celui-ci teste le serveur avec SSLlabs ou bien un outil comme
SSLyze ou encore https://testssl.sh/
et il
vous engueule en disant « quoi, mais vous proposez encore SSLv3, c'est
bien trop dangereux ». Pour éviter cette engueulade, on peut mettre
dans sa configuration TLS une liste complète des bons algorithmes (on
en trouve par exemple dans le document de
l'ANSSI cité plus haut et Mozilla en publie
une pour GnuTLS) mais cette méthode est
longue et pénible et difficile à maintenir car la liste change
évidemment dans le temps. Cela ne devrait pas être au webmestre de
devenir expert en crypto ! Pour arriver à un réglage raisonnable,
j'ai donc choisi une autre solution, en partant des jeux d'algorithmes
disponibles dans le logiciel utilisé. Dans mon cas, c'est GnuTLS. Il fournit
des identificateurs désignant des jeux d'algorithmes déterminés comme
ayant certaines propriétés. Ainsi, NORMAL
est le
jeu par défaut. Il est très large. Pour le paranoïaque, il existe un
jeu SECURE
qui est plus raisonnable. On peut donc
configurer son Apache ainsi :
GnuTLSPriorities SECURE
et c'est déjà mieux. Mais, tout l'intérêt de la méthode, est qu'on
peut partir d'un jeu prédéfini puis ajouter ou enlever protocoles ou
algorithmes. Par exemple, le jeu
SECURE
inclut
actuellement le protocole SSLv3, vieux et bogué, et qui n'est
apparement nécessaire que pour Internet
Explorer version 6. Comme il est peu probable que beaucoup
de visiteurs de mon blog utilisent cette horreur d'IE 6, je supprime
SSL :
GnuTLSPriorities SECURE:-VERS-SSL3.0
(Cette directive veut dire : partir de la liste
SECURE
et retirer SSLv3.)
Maintenant, si je teste avec
testssl, j'ai :
% ./testssl.sh https://www.bortzmeyer.org/
...
SSLv3 NOT offered (ok)
TLSv1 offered (ok)
TLSv1.1 offered (ok)
TLSv1.2 offered (ok)
SPDY/NPN not offered
--> Testing standard cipher lists
Null Cipher NOT offered (ok)
Anonymous NULL Cipher NOT offered (ok)
Anonymous DH Cipher NOT offered (ok)
40 Bit encryption NOT offered (ok)
56 Bit encryption Local problem: No 56 Bit encryption configured in /usr/bin/openssl
Export Cipher (general) NOT offered (ok)
...
--> Checking RC4 Ciphers
RC4 seems generally available. Now testing specific ciphers...
Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits Cipher Suite Name (RFC)
--------------------------------------------------------------------------------------------------------------------
[0x05] RC4-SHA RSA RC4 128 TLS_RSA_WITH_RC4_128_SHA
RC4 is kind of broken, for e.g. IE6 consider 0x13 or 0x0a
...
Pas mal. SSLv3 a bien été retiré, le seul gros problème restant est
que RC4 est encore proposé alors que cet
algorithme a de sérieuses failles. Un dernier effort, pour le
supprimer :
GnuTLSPriorities SECURE:-VERS-SSL3.0:-ARCFOUR-128:-ARCFOUR-40
Et, cette fois, RC4 n'est plus proposé :
...
--> Checking RC4 Ciphers
No RC4 ciphers detected (OK)
Voilà, j'ai maintenant une configuration TLS raisonnable. Principal
manque : augmenter la priorité des algorithmes offrant la
forward secrecy, ce sera
pour une prochaine fois.
Ah, question outils de test, j'ai bien sûr utilisé SSLlabs mais il a deux
inconvénients : stupidement, il teste également le nom sans
www
(et échoue donc souvent), et il ne connait
pas CAcert donc la note globale reste à « T » (non documenté). Avec un
certificat qu'il connaitrait, https://www.ssllabs.com/ssltest/analyze.html?d=www.bortzmeyer.org
me donnerait une meilleure note (« If trust issues are ignored: A- »).
J'ai aussi testé le logiciel sslscan (qui est en paquetage sur ma
Debian) mais son ergonomie est vraiment
horrible, il sort juste une longue liste
de trucs testés, sans autre précision, hiérarchisation ou explication.
Quelques autres détails pratiques maintenant. Comme j'aime bien
regarder les journaux, j'ai voulu indiquer si
la connexion s'était faite en TLS ou pas (je rappelle que, pour
l'instant, TLS n'est pas obligatoire sur ce blog). Il existe une
variable HTTPS
mais qui est spécifique
à OpenSSL (voir un
exemple de son utilisation). Pour GnuTLS, j'ai donc créé deux
directives LogFormat
:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %v" complete
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %v TLS" completetls
et j'utilise l'une ou l'autre selon le
VirtualHost
:
CustomLog ${APACHE_LOG_DIR}/access.log complete
...
CustomLog ${APACHE_LOG_DIR}/access.log completetls
...
La visite de SSLlabs est ainsi correctement enregistrée :
64.41.200.103 - - [10/Sep/2014:08:43:13 +0000] "GET / HTTP/1.0" 200 285954 \
"-" "SSL Labs (https://www.ssllabs.com/about/assessment.html)" \
www.bortzmeyer.org TLS
Je n'ai pas encore changé la description OpenSearch de ce blog. Les recherches sont évidemment sensibles
(elles indiquent à un attaquant vos sujets d'intérêt) mais je ne sais
pas trop comment dire en OpenSearch « utilise HTTPS si tu peux et HTTP
sinon ». Si on met deux éléments url
, je ne sais
pas lequel est choisi. Donc, il faut que je relise
la spécification.
Un piège classique avec X.509 est l'oubli
du fait que les certificats ont, parmi leurs métadonnées, une date
d'expiration. Comme le mécanisme théorique de révocation des
certificats ne marche pas en pratique, cette
expiration est la seule protection qui empêche un voleur de clé privée
de s'en servir éternellement. Il faut donc superviser l'expiration des
certificats, ce que je fais depuis
Icinga :
# HTTPS
define service{
use generic-service
hostgroup_name Moi
service_description HTTPS
check_command check_http!-S -C 30,7
}
Cette directive indique de se connecter en HTTPS (option
-S
), d'avertir s'il ne reste que 30 jours de
validité au certificat et de passer en mode panique s'il ne reste plus
que 7 jours. Bien sûr, CAcert prévient automatiquement par courrier
lorsqu'un certificat s'approche de l'expiration mais, renouveler le
certificat chez l'AC ne suffit pas, encore faut-il l'installer sur le
serveur, et c'est cela que teste Icinga.
Merci à Manuel Pégourié-Gonnard pour la correction d'une grosse erreur sur TLS.