HSTS (HTTP Strict Transport Security) est un en-tête de réponse HTTP qui force le navigateur à ne communiquer avec ton site qu’en HTTPS, pendant une durée que tu définis. Une fois l’en-tête reçu, le navigateur mémorise l’instruction et refuse toute connexion en HTTP clair vers ton domaine, même si l’utilisateur tape http:// ou clique sur un vieux lien.
C’est une brique de sécurité simple à mettre en place, gratuite, et l’une des premières choses qu’on vérifie lors d’un audit de site.
Pourquoi HSTS, alors que j’ai déjà une redirection HTTP → HTTPS ?
Bonne question, et c’est le point que la plupart des gens ratent.
Une redirection Apache (RewriteRule ou Redirect vers https://) protège mal contre une attaque active. Le scénario du problème :
- L’utilisateur tape
etiennemotara.frdans son navigateur → par défaut, le navigateur tentehttp://en premier. - Cette première requête part en clair sur le réseau.
- Un attaquant positionné sur le réseau (Wi-Fi public, box compromise, etc.) intercepte cette requête avant même qu’elle atteigne ton serveur, et n’envoie jamais la redirection — il sert sa propre version du site ou reste en HTTP pour espionner.
C’est l’attaque dite SSL stripping. Ta redirection ne sert à rien parce que l’attaquant intercepte la requête avant qu’elle arrive à ton Apache.
HSTS ferme cette fenêtre : après la première visite légitime, le navigateur ne tente plus jamais de connexion HTTP vers ton domaine. Il passe directement en HTTPS, sans requête en clair à intercepter.
Nuance importante : HSTS ne protège pas la toute première visite (avant que le navigateur ait reçu l’en-tête). Pour couvrir même ce premier contact, il existe le mécanisme de preloading, détaillé plus bas.
Prérequis
Avant d’activer HSTS, ces trois conditions doivent être remplies :
- HTTPS fonctionne parfaitement sur ton domaine (certificat valide, chaîne complète).
- Tu as une redirection HTTP → HTTPS en place (HSTS la complète, ne la remplace pas).
- Tous tes sous-domaines sont accessibles en HTTPS si tu comptes utiliser l’option
includeSubDomains.
Ce dernier point est critique : activer includeSubDomains alors qu’un sous-domaine (api., blog., dev.…) n’est disponible qu’en HTTP le rendra totalement inaccessible dans les navigateurs qui ont reçu l’en-tête. Et vu que HSTS est mémorisé pour la durée du max-age, l’erreur est difficile à corriger vite.
L’en-tête et ses directives
L’en-tête complet ressemble à ça :
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Trois directives :
| Directive | Rôle |
|---|---|
max-age=<secondes> | Durée pendant laquelle le navigateur applique la règle. 31536000 = 1 an. Obligatoire. |
includeSubDomains | Applique la règle à tous les sous-domaines. Optionnel mais recommandé si ton infra le permet. |
preload | Autorise l’inscription du domaine dans la liste de préchargement des navigateurs (voir plus bas). Optionnel. |
Mise en place sur Apache
1. Activer le module headers
L’en-tête est envoyé via le module mod_headers, qui n’est pas toujours actif par défaut :
sudo a2enmod headers
sudo systemctl reload apache2
2. Ajouter l’en-tête dans le vhost HTTPS
L’en-tête doit être défini dans le vhost du port 443, jamais dans celui du port 80.
Règle absolue : ne jamais envoyer l’en-tête HSTS sur une réponse HTTP (port 80). La spec impose aux navigateurs de l’ignorer sur HTTP, mais le placer là est une erreur de configuration et peut semer la confusion. HSTS se sert uniquement en HTTPS.
Édite ton vhost SSL :
sudo nano /etc/apache2/sites-available/ton-site-le-ssl.conf
Ajoute la ligne Header à l’intérieur du bloc <VirtualHost *:443> :
<VirtualHost *:443>
ServerName etiennemotara.fr
ServerAlias www.etiennemotara.fr
DocumentRoot /var/www/ton-site
# ... reste de ta config SSL ...
# HSTS — 1 an, sous-domaines inclus
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</VirtualHost>
Le mot-clé always est important : il garantit que l’en-tête est envoyé sur toutes les réponses, y compris les pages d’erreur (403, 404, 500). Sans always, l’en-tête n’est ajouté que sur les réponses « normales » (2xx, 3xx), ce qui laisse un trou.
3. Tester la configuration et recharger
sudo apache2ctl configtest
sudo systemctl reload apache2
configtest doit renvoyer Syntax OK avant le reload.
Vérifier que HSTS est bien actif
En ligne de commande
curl -sI https://etiennemotara.fr | grep -i strict-transport-security
Tu dois voir apparaître :
strict-transport-security: max-age=31536000; includeSubDomains
Si rien ne s’affiche : le module headers n’est pas actif, l’en-tête est dans le mauvais vhost, ou Apache n’a pas été rechargé.
Dans le navigateur
Ouvre les DevTools (F12) → onglet Réseau → recharge la page → clique sur la requête du document principal → section En-têtes de réponse. L’en-tête strict-transport-security doit y figurer.
Stratégie de déploiement : monter le max-age progressivement
Ne pose pas max-age=31536000 (1 an) du premier coup. Si tu découvres ensuite un sous-domaine cassé ou un problème de certificat, tu ne peux pas annuler facilement — les navigateurs ont mémorisé la règle pour un an.
L’approche prudente :
Démarre court — teste avec une valeur faible pendant quelques jours :
Header always set Strict-Transport-Security "max-age=300(300 secondes = 5 minutes)
Vérifie que tout fonctionne : site principal, sous-domaines, pages d’erreur, tout en HTTPS sans accroc.
Monte à quelques heures, puis quelques jours :
Header always set Strict-Transport-Security "max-age=86400; includeSubDomainsPasse à 1 an une fois confiant :
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Pour désactiver HSTS pendant les tests, ne te contente pas de retirer la ligne — pose explicitement max-age=0, ce qui dit au navigateur d’oublier la règle :
Header always set Strict-Transport-Security "max-age=0"
Le preloading (option avancée)
Le point faible de HSTS, c’est la toute première visite : tant que le navigateur n’a jamais reçu l’en-tête, il peut encore tenter du HTTP. Le préchargement corrige ça.
Les navigateurs (Chrome, Firefox, Safari, Edge) embarquent une liste codée en dur de domaines à traiter en HTTPS-only dès la première requête, sans avoir jamais visité le site. Cette liste est maintenue sur hstspreload.org.
Conditions pour être éligible
Pour soumettre ton domaine, l’en-tête doit respecter exactement ces exigences :
max-aged’au moins 31536000 (1 an)- la directive
includeSubDomainsprésente - la directive
preloadprésente - une redirection HTTP → HTTPS valide sur le domaine racine
L’en-tête devient donc :
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Une fois l’en-tête en place, tu soumets ton domaine sur hstspreload.org.
⚠️ À bien peser avant de précharger
Le preloading est quasi irréversible et lent à défaire. Se retirer de la liste prend des mois (le temps que les nouvelles versions des navigateurs se déploient). N’active preload que si :
- tu es certain que tout ton domaine et tous ses sous-domaines resteront en HTTPS indéfiniment ;
- tu ne prévois pas de servir un jour quoi que ce soit en HTTP sur ce domaine.
Pour un site personnel ou vitrine stable, c’est un bon réflexe. Pour une infra en évolution avec des sous-domaines qui vont et viennent, mieux vaut s’abstenir.
Récapitulatif
| Étape | Commande / action |
|---|---|
| Activer le module | sudo a2enmod headers |
| Ajouter l’en-tête | Header always set Strict-Transport-Security "..." dans le vhost :443 |
| Tester la config | sudo apache2ctl configtest |
| Recharger | sudo systemctl reload apache2 |
| Vérifier | curl -sI https://ton-domaine \| grep -i strict |
HSTS est l’un des en-têtes de sécurité les plus faciles à déployer pour le gain qu’il apporte. Combiné à une redirection HTTP → HTTPS propre et à un certificat valide, il élimine toute une classe d’attaques réseau — et c’est un point systématiquement contrôlé lors d’un audit de sécurité web.