HSTS (HTTP Strict Transport Security)
HSTS force les navigateurs à utiliser HTTPS pour un domaine donné. Une fois actif, toute tentative en HTTP est automatiquement convertie en HTTPS par le navigateur, sans appel réseau en clair.
Comment ça fonctionne
- Le serveur renvoie l'en-tĂȘte
Strict-Transport-Securitysur une réponse HTTPS. - Le navigateur conserve cette rÚgle pendant
max-agesecondes. - Tant que la rĂšgle est active, le navigateur refuse le HTTP.
Syntaxe de l'en-tĂȘte
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
ParamĂštres:
max-age: durĂ©e en secondes.includeSubDomains: applique aussi aux sous-domaines.preload: signal pour ĂȘtre Ă©ligible Ă la liste de preload des navigateurs.
Pré-requis
- HTTPS actif partout, certificat valide.
- Redirection 301/308 de HTTP vers HTTPS.
- Tous les sous-domaines doivent ĂȘtre compatibles HTTPS si
includeSubDomainsest activé.
Recommandations
- Démarrer avec un
max-agecourt (ex: 86400) puis augmenter. - Pour le preload:
max-age >= 31536000+includeSubDomains+preload. - Ne jamais envoyer HSTS sur un domaine qui sert encore du HTTP.
Implémentation Symfony
Option 1: niveau serveur (recommandé)
Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Apache:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Avantage: appliqué à toutes les réponses, y compris les fichiers statiques.
Option 2: niveau application (Symfony)
Ajoutez un subscriber qui pose l'en-tĂȘte uniquement en HTTPS.
// src/EventSubscriber/HstsSubscriber.php namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; final class HstsSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [KernelEvents::RESPONSE => 'onResponse']; } public function onResponse(ResponseEvent $event): void { $request = $event->getRequest(); if (!$request->isSecure()) { return; } $event->getResponse()->headers->set( 'Strict-Transport-Security', 'max-age=31536000; includeSubDomains' ); } }
Notes:
- Ne pas activer HSTS en dev local si vous n'utilisez pas HTTPS.
- Si vous ĂȘtes derriĂšre un proxy, configurez
trusted_proxiespour queisSecure()soit fiable.
Preload (optionnel)
Si vous voulez ĂȘtre prĂ©chargĂ©:
- Activer
includeSubDomainsetpreload. - Mettre
max-age=31536000. - Soumettre le domaine: https://hstspreload.org/
Checklist go/no-go (preload)
Go:
- Tous les sous-domaines (existants et futurs) sont en HTTPS avec certificats valides.
- Redirection 301/308 HTTP -> HTTPS en place partout.
Strict-Transport-Securityenvoyé sur toutes les réponses HTTPS.max-age=31536000,includeSubDomains,preloaddéjà en prod et testés.- Plan de rollback documenté (retrait des directives + délai de propagation).
No-go:
- Un seul sous-domaine sert encore du HTTP ou est instable en HTTPS.
- Certificats non gérés pour tous les sous-domaines.
- Pas de visibilité sur tous les sous-domaines (legacy, marketing, vendors).
- HSTS activé récemment sans période d'observation suffisante.
- Redirections partielles ou incohérentes selon les apps/environnements.
Rollback (preload)
Si vous devez sortir du preload:
- Retirer
preloadde l'en-tĂȘte HSTS. - Retirer
includeSubDomainssi tous les sous-domaines ne sont pas en HTTPS. - Baisser
max-age(ex: 0 ou trÚs court) pour limiter la durée restante. - Attendre l'expiration cÎté clients (selon
max-age). - Soumettre la demande de retrait sur le site de preload (délai de propagation).
Note: le retrait est lent et dépend des mises à jour de listes intégrées aux navigateurs.
Vérification rapide
- Outils dev navigateur: inspecter la rĂ©ponse HTTPS et l'en-tĂȘte HSTS.
- OpenSSL/curl:
curl -I https://votre-domaine.
Voir aussi â en production
vps/05-securite.mdâ HSTS et headers de sĂ©curitĂ© dĂ©ployĂ©s sur Telaria.