Comment HTTPS et TLS fonctionnent réellement : handshake et certificats

Security2026-10-27TryQuickToolBox

Vous ajoutez un certificat SSL, pointez votre domaine vers un serveur, et le cadenas apparaît. La plupart des développeurs s'arrêtent là. Puis un jour, un client API échoue avec UNABLE_TO_VERIFY_LEAF_SIGNATURE, une application mobile rejette votre certificat sur un Android plus ancien, ou un load balancer termine TLS et votre application voit tout en HTTP simple. Soudain, vous devez savoir ce qui se passe réellement entre la connexion TCP et la première requête HTTP.

Cet article détaille le fonctionnement réel de HTTPS et TLS : ce que fait le handshake, comment les certificats sont validés, ce qui a changé dans TLS 1.3, et comment diagnostiquer les erreurs que vous rencontrerez réellement.

Ce que HTTPS ajoute réellement

HTTPS est du HTTP envoyé sur une connexion TLS. TLS offre trois garanties :

Notez ce qui n'est pas sur cette liste : le client n'est pas authentifié par défaut. TLS authentifie le serveur ; votre application authentifie l'utilisateur.

Le handshake TLS 1.2, étape par étape

TLS 1.2 est encore courant sur les infrastructures plus anciennes et dans de nombreux proxys d'entreprise, il vaut donc la peine de le comprendre. Un handshake complet se déroule ainsi :

  1. ClientHello — le client envoie les versions TLS supportées, une valeur aléatoire, une liste de suites de chiffrement et (le cas échéant) le nom d'hôte SNI.
  2. ServerHello — le serveur choisit une version et une suite de chiffrement, renvoie sa propre valeur aléatoire et envoie sa chaîne de certificats.
  3. Échange de clés — avec ECDHE, le serveur envoie une clé publique éphémère ; le client envoie la sienne. Les deux dérivent le même secret partagé. Le serveur signe la transcription du handshake avec la clé privée de son certificat.
  4. Finished — les deux côtés envoient un MAC sur la transcription du handshake, confirmant que rien n'a été altéré.
  5. Données applicatives — les requêtes et réponses HTTP circulent chiffrées.

Le détail crucial est l'échange de clés éphémère. Avec ECDHE, une nouvelle paire de clés est générée à chaque connexion. Même si un attaquant enregistre des années de trafic et vole ensuite la clé privée du serveur, il ne peut pas déchiffrer les sessions passées. Cette propriété s'appelle la confidentialité persistante (forward secrecy), et c'est la principale raison pour laquelle l'échange de clés RSA statique a été déprécié.

Ce que TLS 1.3 a changé

TLS 1.3 simplifie le handshake en un seul aller-retour et supprime entièrement les algorithmes hérités.

AspectTLS 1.2TLS 1.3
Aller-retours (handshake complet)21
Échange de clésRSA ou ECDHEECDHE uniquement (confidentialité persistante)
Suites de chiffrementChiffrement, MAC et échange de clés séparésSuites AEAD uniquement, par ex. TLS_AES_128_GCM_SHA256
RSA statique, CBC, RC4AutorisésSupprimés
Reprise de sessionID de session / ticketsPSK avec option 0-RTT

Dans TLS 1.3, le client devine le groupe d'échange de clés et envoie sa part dans le premier message, de sorte que le serveur peut conclure l'accord de clés immédiatement. Les certificats sont toujours envoyés, mais ils sont désormais chiffrés, ce qui signifie que les observateurs passifs ne peuvent plus voir quel nom d'hôte est servi — seul le SNI dans le ClientHello le révèle, sauf si Encrypted Client Hello est utilisé.

La reprise 0-RTT permet à un client qui revient d'envoyer des données applicatives dès le premier vol. C'est rapide, mais les données 0-RTT sont rejouables, donc ne l'utilisez jamais pour des requêtes non idempotentes comme les paiements.

Certificats et validation de chaîne

Un certificat lie une clé publique à un nom d'hôte. La validation est un parcours de chaîne :

La cause la plus fréquente des erreurs unable to verify est un certificat intermédiaire manquant. Les navigateurs contournent parfois cela en mettant en cache les intermédiaires, mais les outils en ligne de commande et les applications mobiles échouent systématiquement. Servez toujours la chaîne complète, la feuille en premier, puis les intermédiaires — jamais la racine.

Débogage pratique avec OpenSSL

Quand quelque chose casse, inspectez ce que le serveur envoie réellement avant de blâmer le client.

# Afficher la chaîne de certificats présentée par le serveur
openssl s_client -connect example.com:443 -servername example.com -showcerts

# Négocier uniquement TLS 1.3 et lister la suite de chiffrement choisie
openssl s_client -connect example.com:443 -tls1_3

# Vérifier l'expiration du certificat en une ligne
echo | openssl s_client -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates -subject -ext subjectAltName

Si s_client signale verify error:num=21:unable to verify the first certificate, la chaîne est incomplète. S'il signale une incompatibilité de nom d'hôte, vérifiez la liste SAN — les certificats wildcard ne couvrent qu'un seul niveau, donc *.example.com correspond à api.example.com mais pas à a.b.example.com.

Erreurs de configuration courantes

Une configuration serveur raisonnable

Pour Nginx, une base moderne ressemble à ceci :

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;

Laissez le serveur choisir les suites de chiffrement en TLS 1.3 — la préférence du client y est acceptable car les suites sont toutes fortes. Gardez les tickets de session désactivés sauf si vous faites tourner les clés de ticket, car une clé de ticket compromise peut compromettre la reprise.

FAQ

HTTPS chiffre-t-il le nom d'hôte ?

Pas par défaut. L'extension SNI dans le ClientHello est envoyée en clair pour que le serveur sache quel certificat présenter. Encrypted Client Hello (ECH) le masque, mais l'adoption reste limitée. Le chemin et la chaîne de requête sont toujours chiffrés.

Pourquoi mon certificat fonctionne-t-il dans un navigateur mais échoue dans curl ou une application mobile ?

Presque toujours un certificat intermédiaire manquant. Les navigateurs récupèrent ou mettent souvent en cache les intermédiaires eux-mêmes, tandis que les clients plus stricts exigent que le serveur envoie la chaîne complète. Vérifiez avec openssl s_client -showcerts.

TLS 1.3 est-il toujours plus rapide que TLS 1.2 ?

Pour les nouvelles connexions, oui — un aller-retour au lieu de deux. Pour les connexions reprises, l'écart se réduit, et 0-RTT peut rendre TLS 1.3 encore plus rapide, au prix d'un risque de rejeu sur les requêtes non idempotentes.

Si vous auditez un serveur web après un changement TLS, l'analyse des logs révèle souvent l'impact réel : redirections cassées, pics de 4xx inattendus, ou clients qui continuent d'utiliser HTTP. Vous pouvez déposer un journal d'accès dans l'analyseur de logs Nginx pour voir la répartition des codes de statut et repérer les clients qui n'ont jamais terminé la migration vers HTTPS.