formations/cesi/hebergement_web/03-https.md

174 lines
6.2 KiB
Markdown
Raw Permalink Normal View History

2019-05-15 12:23:31 +02:00
% Introduction au HTTPS
% Sylvain Eliade — S.C.O.P. Cadoles
% Mai 2019
## Introduction au HTTPS
* HTTP encapsulé dans une connexion chiffrée
* Historiquement avec le protocole SSL
* Aujourd'hui c'est TLS
---
## Chiffrement à clé publique et privée
* La clé publique est distribuée (non secrète) et ne sert qu'à chiffrer
* La clé privée est secrète et sert à déchiffrer
Le serveur possède une clé privée (secrète) et une clé publique (appelée certificat), signée par une *autorité*.
---
## Certificats
* Prouve l'identité du propriétaire du certificat
* Doivent être signés par une autorité reconnue (ou plusieurs)
* Peuvent être signés par soi-même (*self signed*) mais c'est relou (difficile à utiliser), et du coup ça ne prouve pas grand chose
---
## Autorités
* Système hiérarchique (une autorité peut signer des certificats d'une sous-autorité, etc.) : on parle de *chaîne* de certificats
* Combine des acteurs publics (états, ministères, etc.) et privés (entreprises)
* On doit avoir confiance envers ces autorités
* Chaque OS a un « app store » de certificats d'autorités (paquet `ca-certificates` dans Debian/Ubuntu)
* Système centralisé, moyennement sûr (nombreux cas d'autorités qui font n'importe quoi)
* Un peu mieux depuis Let's Encrypt
---
## Phase de négociation (handshake) TLS
![](./img/tls_handshake.gif)
---
En simplifié :
1. Le client se connecte au serveur, lui indique les protocoles cryptographiques qu'il supporte (cipher suite)
2. Le serveur lui répond, en indiquant le protocole choisi, ainsi que son certificat public (signé par une autorité).
3. Le client vérifie le certificat.
4. Échange de clé entre le client et le serveur. Cette clé est spécifique à cette session entre client et serveur.
Ensuite le client et le serveur communiquent en HTTP entre eux, mais tout est chiffré à l'aide des clés échangées.
---
La phase de négociation ne se reproduit pas à chaque requête HTTP : normalement la connexion TLS reste ouverte une ou deux minutes, permettant de faire passer d'autres requêtes.
De même, les étapes 1 à 3 peuvent être ignorées quand le serveur et le client se connaissent déjà et ont encore les infos de chacun en cache.
---
## Vérification OCSP
A l'étape 3, le client peut aller vérifier auprès d'un serveur OCSP (*Online Certificate Status Protocol*) que le certificat du serveur est bien valide.
De nos jours, le serveur peut s'en charger lui-même (*OCSP stapling*), il envoie une certification OCSP (avec la date) au client : évite un aller-retour du client avec le serveur OCSP.
---
## SNI (Server Name Indication)
Rappel du HTTP : le nom d'hôte demandé est transmis dans l'entête `Host` de la requête HTTP.
Donc : l'hôte demandé est dans la requête chiffrée, AVANT que le serveur web ne puisse savoir quel certificat utiliser pour le HTTPS !
Solution : le SNI !
---
* Le nom d'hôte demandé est inscrit dans la connexion TLS par le client
* Très bien supporté de nos jours (si pas supporté : utilisation du vhost par défaut)
* Inconvénient : le nom n'est pas chiffré (possibilité d'interception pour voir quel site vous visitez)
---
## Configuration Apache HTTPS
Attention : il faut créer un vhost différent, car le port est différent.
```
<VirtualHost *:443>
ServerName cesi.test
SSLEngine on
SSLCertificateFile "/var/www/certs/cesi.cert"
SSLCertificateKeyFile "/var/www/certs/cesi.private"
</VirtualHost>
```
Si on a un site en HTTPS il est recommandé que la version HTTP ne fasse que rediriger vers le site en HTTPS (plus simple niveau config serveur).
---
## Let's Encrypt
* Autorité de certification à but non lucratif qui délivre des certificats signés gratuits.
* Avant LE, il fallait payer (en général cher) pour avoir un certificat signé par une autorité !
* Inconvénient : durée du certificat limitée à 90 jours.
* Inconvénient : ne marche pas pour les domaines privés (réseau privé).
* Plusieurs manières de valider qu'on est bien propriétaire d'un domaine : HTTP ou DNS
* Plusieurs clients : certbot, dehydrated, etc.
---
## Let's Encrypt : certbot
* `# apt install certbot python-certbot-apache`
* `# certbot --apache`
C'est tout, il va poser des questions et va tout configurer à votre place… Mais des fois ça ne marche pas trop du coup quand notre configuration est un peu complexe.
---
## Let's Encrypt : [dehydrated](https://github.com/lukas2511/dehydrated)
Plus léger que certbot, un peu plus manuel.
* `# apt install dehydrated dehydrated-apache2`
* Ajouter les noms de domaine dans le fichier `/etc/dehydrated/domains.txt` (un par ligne)
* Lancer `dehydrated -c`
* Configurer son vhost :
```
SSLCertificateFile /var/lib/dehydrated/certs/example.org/fullchain.pem
SSLCertificateKeyFile /var/lib/dehydrated/certs/example.org/privkey.pem
```
Tester la config et recharger Apache.
---
## Attention !
Dans certains cas, `apache2ctl configtest` ne renvoie pas d'erreur s'il y a un problème au niveau des certificats, mais ensuite le `reload` (ou `graceful`) plantera !
Exemple : si on utilise `chain.pem` de Let's encrypt (qui ne contient que la chaîne de certification, et pas le certificat lui-même) à la place de `fullchain.pem`.
Solution : vérifier `/var/log/apache2/error.log` après un reload si on a modifié des trucs dans la config SSL !
---
## Exercice 1
Installer `dehydrated` et le configurer pour le domaine `cesi.sylvain.eliade.net`. Lancer dehydrated.
Il va tenter de vérifier l'appartenance du domaine et échouer (logique). A la place, prendre les fichiers `.pem` fournis et les recopier dans le bon répertoire.
Configurer un vhost Apache pour ce domaine, utilisant les certificats fournis. Ne pas oublier d'activer `mod_ssl` : `a2enmod ssl` et redémarrer Apache.
Dans `/etc/hosts` inscrire une ligne avec `127.0.0.1 cesi.sylvain.eliade.net`.
Tester la config avec curl, et si possible le navigateur de la machine hôte.
## Exercice 2 (facultatif)
Générer un certificat auto-signé :
```
# mkdir /etc/ssl/localcerts/
# openssl req -new -x509 -days 365 -nodes -out /etc/ssl/localcerts/apache.pem -keyout /etc/ssl/localcerts/apache.key
```
Le mettre en place dans Apache, et vérifier que ça fonctionne avec un navigateur (qui affichera un message d'avertissement).