Si votre site WordPress « a un SSL » mais que le navigateur affiche encore un avertissement, vous n’êtes pas seul. Le cadenas ment — enfin, pas exactement. Il fait ce pour quoi il a été conçu : dénoncer quand n’importe quelle ressource sur une page HTTPS est récupérée via HTTP.
C’est à ce moment-là que les équipes paniquent, installent trois plugins supplémentaires et empirent involontairement la situation. N’en faites rien. Le contenu mixte est un problème système : base de données, thèmes, plugins, CDN, proxies, caches et en-têtes ont tous leur mot à dire. Vous le réparez en restreignant les sources, en modifiant la bonne couche et en empêchant la rechute.
Ce qu’est réellement le contenu mixte (et pourquoi les navigateurs s’en préoccupent)
Le contenu mixte survient lorsqu’une page chargée via HTTPS récupère n’importe quelle sous-ressource via HTTP non chiffré. Les sous-ressources incluent les images, CSS, JavaScript, polices, iframes, vidéos, appels XHR/fetch, et même les images de fond référencées dans le CSS.
Les navigateurs considèrent cela comme une dégradation de sécurité. TLS sécurise le document de premier niveau, mais si vous chargez un script via HTTP, un attaquant sur le réseau peut le remplacer. Votre page « sécurisée » peut alors devenir un kiosque de collecte d’identifiants.
Contenu mixte actif vs passif
- Contenu mixte actif (scripts, iframes, XHR) peut exécuter du code ou modifier le comportement de la page. Les navigateurs le bloquent généralement par défaut.
- Contenu mixte passif (images, audio, vidéo) ne peut généralement pas exécuter de code directement. Les navigateurs peuvent l’autoriser mais signaler un avertissement. « Peut autoriser » n’est pas une stratégie.
Pourquoi « j’ai installé SSL » ne suffit pas
La terminaison SSL signifie simplement que le périmètre peut parler HTTPS. WordPress peut encore :
- Stocker des URL absolues en HTTP dans la base de données.
- Générer des liens HTTP s’il pense qu’il est en HTTP (mauvais réglage de reverse proxy).
- Charger des ressources tierces via HTTP (thème ancien, extraits fournisseurs, contenus intégrés).
- Servir des redirections de manière inconsistante (certaines routes 301 vers HTTPS, d’autres non).
- Mettre en cache du HTML ancien contenant des URL HTTP (cache de page, cache CDN).
Encore une chose : les avertissements du navigateur ne portent pas toujours sur un évident http://. Ils peuvent provenir d’URL relatives au protocole (//example.com), de url() en CSS, de scripts inline, ou d’endpoints codés en dur par des plugins. Le contenu mixte est une chasse au trésor, sauf que le trésor se cache dans votre widget de pied de page.
Faits intéressants et un peu d’historique
- « Contenu mixte » existe depuis avant les navigateurs modernes. Les premiers sites HTTPS intégraient souvent des images HTTP pour économiser le CPU — TLS était autrefois coûteux.
- La mention de Google « HTTPS comme signal de classement » (2014) a transformé le cadenas d’un simple plus en objectif organisationnel.
- Let’s Encrypt (lancement public 2015) a rendu les certificats gratuits et automatisés, augmentant l’adoption de HTTPS — et exposant des décennies d’URLs codées en dur en HTTP.
- HTTP/2 (standardisé 2015) a été pratiquement réservé au HTTPS dans les principaux navigateurs, poussant les sites à migrer pour profiter des performances.
- Chrome a commencé à marquer les pages HTTP « Non sécurisé » (2018), en particulier sur les formulaires, forçant des entreprises réticentes à corriger le contenu mixte lors des migrations HTTPS.
- HSTS peut « verrouiller » un domaine en HTTPS. Très bien pour la sécurité, brutal lorsqu’on a encore des sous-domaines en HTTP ou des ressources tierces non sécurisées.
- Les URL relatives au protocole (
//) étaient autrefois une astuce de migration. Aujourd’hui elles créent surtout de la confusion et devraient être abandonnées sur des sites modernes orientés HTTPS. - WordPress stocke des URLs partout. Pas seulement dans les articles : options, widgets, données de constructeurs, tableaux sérialisés, et parfois des modifications de thème.
- Certaines CDN réintroduisent du contenu mixte. Vous pouvez terminer TLS au niveau du CDN mais toujours récupérer l’origine via HTTP ou réécrire le HTML de façon inconsistante.
Mode opératoire pour un diagnostic rapide : trouver le coupable rapidement
Voici l’ordre de triage que j’utilise quand on me dit « le cadenas est cassé » cinq minutes avant un lancement.
1) Reproduire avec une page et regarder la console du navigateur
Choisissez une page problématique, ouvrez DevTools → Console et Réseau. Les erreurs de contenu mixte incluent généralement l’URL fautive exacte.
Décision : Si la ressource est sur votre domaine, corrigez WordPress/config/base de données. Si c’est tierce, décidez de la remplacer, la proxyfier, ou la supprimer.
2) Confirmer ce que WordPress pense de son propre URL
Si siteurl/home sont en HTTP, WordPress imprimera des liens HTTP indéfiniment.
Décision : Si mismatch, corrigez dans la BD ou via WP-CLI, puis purgez les caches.
3) Valider TLS et le comportement de redirection depuis le périmètre
Vérifiez si HTTP redirige systématiquement vers HTTPS, et si votre reverse proxy définit les bons en-têtes.
Décision : Si WordPress est derrière un load balancer/CDN, assurez-vous qu’il voit l’équivalent de HTTPS=on (typiquement X-Forwarded-Proto: https).
4) Chercher les http:// codés en dur dans le HTML rendu
Ne devinez pas. Récupérez la page et greppez. Si http:// apparaît, vous avez un problème de réécriture/base/thème.
Décision : Si c’est dans le HTML issu d’articles/options, effectuez un search-replace sécurisé. Si c’est dans du code thème/plugin, corrigez le code ou surchargez-le.
5) Si c’est « parfois seulement », suspectez caches ou rendu conditionnel
Le cache de page, cache d’objets, CDN et caches de constructeurs peuvent conserver des URLs anciennes. Aussi : la sortie pour les utilisateurs logués peut différer de celle des anonymes.
Décision : Purgez les couches de cache adéquates, puis vérifiez avec une requête fraîche en contournant le cache.
D’où vient le contenu mixte dans WordPress (scénarios réels d’échec)
URLs absolues stockées en base de données
Le contenu WordPress est un immense dépotoir d’URLs. Les articles et pages stockent des liens absolus. Les widgets aussi. Les plugins de builders également. Le pire : certains plugins conservent les données sous forme de tableaux PHP sérialisés, donc un search/replace naïf casse les longueurs de chaîne et corrompt les données.
WP-CLI moderne gère cela correctement. La plupart des plugins de « search replace » aussi, mais les exécuter en production sans sauvegarde est une façon rapide d’ajouter des cheveux gris.
Hardcoding dans le thème ou un plugin
Patrons courants :
- Scripts/styles enqueue avec
http://codé en dur. - Google Fonts ou extraits d’analytics copiés d’un vieux billet de blog.
- CSS inline avec
background-image: url(http://...). - Anciennes widgets sociales et pixels de tracking.
Confusion du reverse proxy / CDN : WordPress croit être en HTTP
Si TLS est terminé au niveau du load balancer (AWS ALB, proxy NGINX, CDN), le backend peut recevoir du HTTP. À moins de transmettre les bons en-têtes et de configurer WordPress pour leur faire confiance, il génère des URLs d’actifs en HTTP.
C’est aussi là que vous voyez des boucles : HTTP→HTTPS redirections au proxy, mais WordPress redirige en retour, ou génère des schémas mixtes dans les liens canoniques.
CDN ou cache servant du HTML obsolète
Vous avez corrigé la BD, mais le CDN sert encore l’ancien HTML avec des URLs HTTP. Ou un plugin de cache de page a un fichier HTML statique de la semaine dernière. Ou votre cache d’objets contient des options périmées.
Contenu tiers : celui que vous ne pouvez pas corriger d’ici
Si un script tiers n’est disponible qu’en HTTP, c’est une dépendance morte. Remplacez-la. Si vous ne pouvez pas la remplacer, vous pouvez parfois la proxyfier via votre domaine en HTTPS, mais vous devenez alors responsable de la sécurité et du comportement de cache. Ne faites pas cela à la légère.
Blague #1 : Le contenu mixte, c’est comme porter une ceinture de sécurité en laissant la portière ouverte — techniquement vous avez essayé, pratiquement vous ne l’avez pas fait.
Tâches pratiques avec commandes : détecter, décider, corriger
Ces tâches supposent que vous pouvez SSHer dans l’hôte ou le conteneur exécutant WordPress. Sinon, vous pouvez quand même effectuer la plupart des vérifications depuis votre poste, mais la réalité opérationnelle est : la correction se trouve souvent côté serveur.
Règle : Chaque tâche se termine par une décision. Si vous ne décidez pas, vous collectionnez juste des logs pour votre album de souvenirs.
Tâche 1 : Vérifier le HTML rendu pour des ressources HTTP évidentes
cr0x@server:~$ curl -sS https://example.com/ | grep -Eo 'http://[^"]+' | head
http://example.com/wp-content/uploads/2022/10/hero.jpg
http://fonts.googleapis.com/css?family=Open+Sans:400,700
Ce que ça signifie : Le HTML de la page contient des URLs absolues en HTTP.
Décision : Si c’est votre domaine (example.com), corrigez la BD/thème. Si c’est tiers (fonts.googleapis.com), mettez à jour le snippet vers HTTPS ou remplacez-le.
Tâche 2 : Utiliser la vue façon navigateur avec les en-têtes pour confirmer les redirections
cr0x@server:~$ curl -I http://example.com/
HTTP/1.1 301 Moved Permanently
Location: https://example.com/
Server: nginx
Ce que ça signifie : HTTP redirige vers HTTPS au niveau du périmètre.
Décision : Bien. Si vous n’obtenez pas un 301/308 vers HTTPS, corrigez la politique de redirection de votre serveur web/CDN d’abord. Les corrections de contenu mixte sont inutiles si les utilisateurs peuvent encore atterrir en HTTP.
Tâche 3 : Confirmer l’URL canonique que WordPress émet
cr0x@server:~$ curl -sS https://example.com/ | grep -iE 'rel="canonical"|og:url' | head -n 5
<link rel="canonical" href="http://example.com/" />
<meta property="og:url" content="http://example.com/" />
Ce que ça signifie : WordPress (ou un plugin SEO) croit que l’URL du site est en HTTP.
Décision : Corrigez home et siteurl dans les options WP et vérifiez les en-têtes du reverse proxy.
Tâche 4 : Vérifier les paramètres d’URL de WordPress via WP-CLI
cr0x@server:~$ cd /var/www/html
cr0x@server:~$ wp option get home
http://example.com
cr0x@server:~$ wp option get siteurl
http://example.com
Ce que ça signifie : Vos URLs de base sont en HTTP, ce qui entraîne la génération de liens internes en HTTP.
Décision : Mettez à jour les deux en HTTPS (tâche suivante), puis purgez les caches.
Tâche 5 : Mettre à jour home et siteurl en toute sécurité
cr0x@server:~$ wp option update home 'https://example.com'
Success: Updated 'home' option.
cr0x@server:~$ wp option update siteurl 'https://example.com'
Success: Updated 'siteurl' option.
Ce que ça signifie : WordPress générera désormais par défaut des URLs en HTTPS.
Décision : Retestez la page. Si vous voyez encore du HTTP dans le contenu, faites un search/replace dans les articles/options.
Tâche 6 : Identifier les URLs HTTP dans la base de données (dry-run d’abord)
cr0x@server:~$ wp search-replace 'http://example.com' 'https://example.com' --all-tables --dry-run
+----------------------+--------------+--------------+------+
| Table | Column | Replacements | Type |
+----------------------+--------------+--------------+------+
| wp_posts | post_content | 128 | SQL |
| wp_postmeta | meta_value | 42 | PHP |
| wp_options | option_value | 19 | PHP |
+----------------------+--------------+--------------+------+
Success: Made 189 replacements.
Ce que ça signifie : Il y a 189 occurrences d’URLs HTTP, y compris des données sérialisées (marquées PHP).
Décision : Si les remplacements semblent corrects, exécutez la même commande sans --dry-run. Si le compte est anormalement élevé, arrêtez et faites une sauvegarde de la BD d’abord.
Tâche 7 : Effectuer le search/replace pour de vrai
cr0x@server:~$ wp search-replace 'http://example.com' 'https://example.com' --all-tables
+----------------------+--------------+--------------+------+
| Table | Column | Replacements | Type |
+----------------------+--------------+--------------+------+
| wp_posts | post_content | 128 | SQL |
| wp_postmeta | meta_value | 42 | PHP |
| wp_options | option_value | 19 | PHP |
+----------------------+--------------+--------------+------+
Success: Made 189 replacements.
Ce que ça signifie : Le contenu de la base de données référence désormais HTTPS pour votre domaine.
Décision : Purgez les couches de cache ; puis relancez la Tâche 1. Si des HTTP tiers subsistent, corrigez-les individuellement.
Tâche 8 : Trouver le HTTP codé en dur dans les thèmes/plugins
cr0x@server:~$ grep -RIn --exclude-dir=node_modules --exclude-dir=.git "http://" wp-content/themes wp-content/plugins | head
wp-content/themes/acme/header.php:44: <script src="http://cdn.vendor.example/widget.js"></script>
wp-content/plugins/old-analytics/old-analytics.php:12:$src = 'http://stats.vendor.example/pixel.js';
Ce que ça signifie : Vous avez du HTTP codé en dur dans le code. Le search/replace en BD ne touchera pas cela.
Décision : Mettez à jour vers HTTPS ou supprimez la dépendance. Si le fournisseur n’offre pas HTTPS, remplacez-le. N’ignorez pas l’avertissement.
Tâche 9 : Confirmer ce que le backend voit (vérification du reverse proxy)
cr0x@server:~$ wp eval 'var_dump($_SERVER["HTTPS"] ?? null, $_SERVER["HTTP_X_FORWARDED_PROTO"] ?? null);'
NULL
string(4) "http"
Ce que ça signifie : WordPress pense être en HTTP derrière le proxy (forwarded proto est http).
Décision : Corrigez le proxy pour définir X-Forwarded-Proto: https sur les requêtes TLS, et configurez WordPress pour lui faire confiance (souvent via wp-config.php ou la conf serveur). Sans cela, le contenu mixte peut réapparaître même après nettoyage de la BD.
Tâche 10 : Inspecter les en-têtes de réponse pour indices de sécurité et de schéma
cr0x@server:~$ curl -sSI https://example.com/ | grep -iE 'strict-transport-security|content-security-policy|location|x-forwarded-proto'
Strict-Transport-Security: max-age=0
Ce que ça signifie : HSTS est désactivé (max-age=0). Pas directement du contenu mixte, mais ça affecte la ténacité des navigateurs à rester en HTTPS.
Décision : N’activez pas un HSTS longue durée tant que le contenu mixte n’est pas totalement résolu et que tous les sous-domaines importants peuvent faire HTTPS.
Tâche 11 : Vérifier la config NGINX pour les en-têtes proxy (si vous l’utilisez)
cr0x@server:~$ sudo nginx -T 2>/dev/null | grep -n "X-Forwarded-Proto" | head
128: proxy_set_header X-Forwarded-Proto $scheme;
Ce que ça signifie : NGINX transmettra le schéma qu’il a reçu. Si NGINX termine TLS, $scheme devrait être https.
Décision : Si TLS est terminé ailleurs (CDN/ELB), NGINX peut voir HTTP et transmettre http. Dans ce cas, définissez-le explicitement en fonction des en-têtes transmis ou terminez TLS sur NGINX.
Tâche 12 : Trouver du contenu mixte dans les fichiers CSS (les images de fond sont sournoises)
cr0x@server:~$ grep -RIn "url(http://" wp-content | head
wp-content/themes/acme/assets/css/main.css:233:background-image: url(http://example.com/wp-content/uploads/2021/03/bg.png);
Ce que ça signifie : Des ressources statiques référencent HTTP dans le CSS. Les navigateurs le signaleront.
Décision : Corrigez le CSS (utilisez des chemins relatifs ou HTTPS) et rebuild/minifiez si nécessaire. Puis purgez caches/CDN.
Tâche 13 : Vérifier que les uploads sont servis en HTTPS et ne redirigent pas bizarrement
cr0x@server:~$ curl -I https://example.com/wp-content/uploads/2022/10/hero.jpg
HTTP/2 200
content-type: image/jpeg
cache-control: public, max-age=31536000
Ce que ça signifie : Les uploads sont accessibles via HTTPS directement.
Décision : Si vous voyez des redirections vers HTTP ou un autre hôte, corrigez les règles de réécriture, la configuration de l’origine CDN, ou les réglages du plugin d’externalisation.
Tâche 14 : Vérifier les réglages « forcer SSL » et le schéma admin
cr0x@server:~$ wp config get FORCE_SSL_ADMIN --type=constant
true
Ce que ça signifie : L’administration est forcée en SSL. Bien, mais cela ne garantit pas la correction du frontend.
Décision : Gardez-le, mais ne le confondez pas avec une correction du contenu mixte. Les ressources frontend et le contenu doivent être nettoyés.
Tâche 15 : Vérifier qu’il ne reste plus de HTTP dans la page après corrections
cr0x@server:~$ curl -sS https://example.com/ | grep -Eo 'http://[^"]+' | wc -l
0
Ce que ça signifie : Le HTML de cette page ne contient plus d’URLs HTTP évidentes.
Décision : Si le navigateur alerte encore, c’est probablement dû à des requêtes à l’exécution (JS, appels tiers) ou à un autre template de page. Utilisez DevTools Network pour les attraper.
Tâche 16 : Si vous utilisez un CDN, confirmez qu’il ne réécrit ni ne met en cache du contenu ancien
cr0x@server:~$ curl -sSI https://example.com/ | grep -iE 'cf-cache-status|x-cache|age|via'
Age: 8421
Via: 1.1 varnish
Ce que ça signifie : Vous touchez une couche de cache avec du contenu ancien. Elle peut encore contenir des liens HTTP anciens.
Décision : Purgez le cache pour les chemins affectés, ou invalidez tout si vous avez changé les URLs du site. Puis retestez en forçant Cache-Control: no-cache ou en contournant par query-string (selon les règles de votre CDN).
Trois mini-récits d’entreprise (comment ça tourne mal)
Mini-récit 1 : L’incident causé par une mauvaise hypothèse
La société A a déplacé un site marketing WordPress derrière un nouveau load balancer flambant neuf. TLS était terminé au LB ; le trafic vers l’origine était en HTTP sur un réseau privé. Tout le monde a hoché la tête et a dit « c’est bon, le trafic interne est de confiance ». Ils avaient à moitié raison, ce qui est la pire des bonnes réponses.
L’équipe web a vérifié que https:// chargeait et a vu un cadenas sur la page d’accueil. Le jour du lancement est arrivé. Soudain le trafic payant a commencé à atterrir sur des pages de campagne qui affichaient des avertissements « Non sécurisé » dans certains navigateurs. Les conversions ont chuté. Le marketing a blâmé le nouveau thème. L’équipe thème a blâmé le CDN. Le SRE de garde a blâmé la gravité.
La cause racine était simple : WordPress pensait que les requêtes étaient en HTTP parce que l’en-tête forwarded proto était erroné. Le LB envoyait X-Forwarded-Proto: http à cause d’une règle d’écoute mal configurée. La page d’accueil était mise en cache avec des liens HTTPS corrects depuis un chemin de requête antérieur, mais plusieurs pages d’atterrissage rendaient du HTML frais et généraient des liens d’actifs en HTTP.
Correction : corriger le comportement d’en-tête du LB, ajouter une logique backend pour faire confiance à l’en-tête seulement depuis les IPs connues du proxy, purger le cache, puis exécuter un search/replace en base pour nettoyer l’ancien contenu. L’hypothèse erronée était que « TLS au périmètre signifie que l’application sait qu’elle est en HTTPS ». Ce n’est pas le cas. Le logiciel n’est pas télépathique.
Mini-récit 2 : L’optimisation qui s’est retournée contre eux
La société B voulait des pages plus rapides. Quelqu’un a activé la « réécriture HTML » au CDN pour minifier et « normaliser » le contenu. Ça semblait inoffensif. Les scores Lighthouse ont même progressé pendant une semaine.
Puis une mise à jour d’un plugin a introduit des URLs relatives au protocole pour un include de script : //vendor.example/script.js. La logique de réécriture du CDN a voulu être utile et a « standardisé » les liens. Elle a réécrit certaines URLs relatives au protocole en http:// lorsque le fetch origine s’effectuait en HTTP (parce que la connexion CDN→origine utilisait HTTP pour des raisons de performance — oui, vraiment).
Résultat : les navigateurs ont commencé à bloquer du contenu mixte actif, mais seulement pour les utilisateurs qui touchaient des pages en cache traitées par ce chemin de réécriture. DevTools montrait le script venant en HTTP, mais chercher dans la base WordPress ne le trouvait pas. L’équipe a perdu des heures à faire des search/replace sur du contenu qui n’était jamais la source.
La correction n’était pas un rollback de plugin. C’était de désactiver la fonction de réécriture HTML du CDN (ou de la configurer pour préserver le schéma), de passer CDN→origine en HTTPS, et d’assigner explicitement HTTPS aux ressources tierces critiques. Optimisation qui se retourne contre vous, classique. Internet récupère toujours sa dette avec intérêts.
Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la journée
La société C avait un runbook ennuyeux pour les « migrations d’URL du site » que personne n’aimait. Il exigeait : sauvegarde BD, WP-CLI search/replace en dry-run, vérification via curl/grep, purge de cache, puis une page canari en staging et production.
Lors d’un rebranding, ils sont passés d’un ancien domaine à un nouveau et ont activé HTTPS partout. Le contenu mixte aurait dû apparaître — il y avait des années d’images intégrées, des blocs HTML inline, et un constructeur de pages qui stockait des blobs JSON en postmeta.
Mais le runbook les a forcés à faire les parties désagréables : un remplacement WP-CLI sûr pour les sérialisations, un scan pour http:// dans les répertoires thème/plugin, et une étape de vérification qui récupérait les 20 gabarits principaux et grepait le HTTP. Il nécessitait aussi une purge CDN après les changements, pas avant.
Le jour du lancement s’est déroulé sans histoire. Personne n’a félicité le runbook. C’est ainsi que vous savez qu’il a fonctionné. La pratique ennuyeuse n’a pas seulement corrigé le contenu mixte ; elle l’a empêché d’apparaître comme un avertissement gênant de navigateur lors d’un moment à haute visibilité.
Erreurs courantes : symptôme → cause racine → correctif
- Symptôme : La page d’accueil affiche le cadenas, mais certaines pages affichent « Non sécurisé »
- Cause racine : Page d’accueil mise en cache vs templates non mis en cache ; contenu mixte dans des blocs de constructeur ou postmeta spécifiques.
- Correctif : Utiliser DevTools sur une page échouée, puis exécuter WP-CLI search/replace sur toutes les tables, plus scanner le code thème/plugin pour du HTTP codé en dur.
- Symptôme : La console du navigateur indique « blocked active mixed content » pour un fichier JS
- Cause racine : Include de script en
http://codé en dur dans un thème, plugin, ou snippet de gestionnaire de tags injecté. - Correctif : Supprimer ou mettre à jour le snippet vers HTTPS ; si le tiers ne supporte pas HTTPS, remplacez le fournisseur. Ne proxyfiez pas du JS arbitraire à moins d’en accepter la responsabilité.
- Symptôme : L’administration WordPress est en HTTPS, mais le frontend génère des actifs HTTP
- Cause racine :
FORCE_SSL_ADMINactivé, maishome/siteurlencore en HTTP ; ou mismatch d’en-têtes reverse proxy. - Correctif : Mettre à jour
homeetsiteurlen HTTPS ; s’assurer queX-Forwarded-Protoest correct ; purger les caches. - Symptôme : Le contenu mixte n’apparaît que pour certains utilisateurs ou régions
- Cause racine : Cache edge CDN avec HTML obsolète ; POPs régionaux dans des états de cache différents ; A/B testing injectant des URLs HTTP.
- Correctif : Purger les caches CDN ; vérifier les clés de cache ; auditer les systèmes d’injection ; re-tester depuis plusieurs régions avec des en-têtes cohérents.
- Symptôme : Après avoir « corrigé » avec un plugin, la mise en page casse ou le contenu disparaît
- Cause racine : Search/replace naïf qui a corrompu des données sérialisées ou des blobs JSON de constructeur.
- Correctif : Restaurer la sauvegarde ; utiliser WP-CLI
search-replacequi gère la sérialisation ; relancer prudemment avec un dry-run d’abord. - Symptôme : Les images chargent, mais le navigateur avertit toujours à propos du contenu mixte
- Cause racine : Une iframe, un script, une police ou un XHR est encore en HTTP. Les images sont juste le suspect habituel, pas le seul.
- Correctif : Vérifier DevTools Network filtré par « blocked » ou « mixed content » ; scanner la source de la page et le CSS pour
http://. - Symptôme : Vous avez activé HSTS et maintenant des parties du site sont cassées
- Cause racine : Certaines sous-ressources (sous-domaines, contenus tiers) nécessitent encore HTTP ; HSTS force HTTPS et révèle brutalement les lacunes.
- Correctif : Revenir sur HSTS (max-age court), corriger toutes les dépendances, puis réactiver progressivement. Ne pas précharger avant d’être sûr.
- Symptôme : Le checkout WooCommerce échoue ou l’iframe de paiement ne se charge pas
- Cause racine : Actifs du prestataire de paiement demandés en HTTP, ou endpoints de callback mal schématisés derrière le proxy.
- Correctif : S’assurer que les URLs du prestataire sont en HTTPS ; confirmer les en-têtes proxy ; valider la page de checkout dans DevTools et la configuration du prestataire.
Listes de contrôle / plan étape par étape (faire une fois, bien faire)
Checklist A : WordPress mono-site, TLS direct sur le serveur web
- Confirmer que la redirection HTTP → HTTPS fonctionne pour
/et quelques chemins profonds (catégorie, article, asset). - Vérifier que le certificat est valide et que la chaîne est correcte (contrôle navigateur + curl en-têtes).
- Mettre
homeetsiteurlen HTTPS via WP-CLI. - Exécuter WP-CLI
search-replace(dry-run, puis réel) pour votre domaine. - Grepper les répertoires thème/plugin pour
http://; corriger les assets codés en dur. - Purgez le plugin de cache de page et régénérez les assets minifiés.
- Récupérer les principaux templates et grepper le HTML rendu pour
http://. - Vérifier dans DevTools : aucun contenu mixte dans la Console ; aucune requête bloquée dans Réseau.
Checklist B : WordPress derrière un reverse proxy / load balancer / CDN
- Confirmer que le périmètre redirige HTTP → HTTPS de façon cohérente.
- Confirmer que le périmètre envoie les en-têtes forwardés corrects (
X-Forwarded-Proto: httpslorsque le client utilise HTTPS). - Configurer le serveur backend et/ou WordPress pour faire confiance aux en-têtes du proxy uniquement depuis des plages IP connues.
- Mettre
homeetsiteurlen HTTPS. - Exécuter un remplacement en base sûr pour la sérialisation.
- Purger les caches CDN après les changements de contenu (pas avant).
- Vérifier que l’origine ne génère pas d’HTTP dans les balises canoniques/méta pour les pages non mises en cache.
- Ce n’est qu’ensuite qu’il faut envisager d’activer HSTS avec un max-age court, puis l’allonger.
Checklist C : Scénario de migration (changement de domaine ou de schéma)
- Sauvegarder la base de données et les uploads. Pas de sauvegarde, pas de modifications. Ce n’est pas du dogme, c’est de la survie.
- Mettre en scène le changement dans un environnement de staging avec une copie des données production.
- Exécuter WP-CLI dry-run search/replace ; revoir les comptes de remplacement par table/colonne.
- Effectuer le remplacement réel ; vérifier les pages principales et les flux critiques (connexion, checkout, formulaires).
- Basculer DNS / config périmètre ; vérifier redirections et balises canoniques.
- Purger les caches et préchauffer le CDN avec un petit crawl des pages importantes.
- Surveiller les logs d’erreurs et les erreurs côté client via RUM si disponible.
Prévention : empêcher le retour du contenu mixte
Définir les bonnes invariantes
- Tout est en HTTPS (y compris uploads, appels API, polices, analytics, embeds).
- Un seul hôte canonique (www vs apex, choisissez un et redirigez l’autre).
- Un seul schéma canonique (HTTPS, toujours).
Utiliser Content Security Policy (CSP) comme garde-fou, pas comme pansement
CSP peut vous aider à repérer les régressions en rapportant le contenu mixte bloqué ou les sources non autorisées. Mais CSP ne corrige pas magiquement des URLs cassées stockées en base. Il rend juste l’échec plus audible et plus déterministe.
Si vous déployez CSP, commencez en mode report-only, observez ce qui casse, puis resserrez. Traitez-le comme un processus de gestion du changement, pas comme une ligne de commande miracle.
HSTS : puissant, dangereux quand on est négligent
HSTS dit aux navigateurs : « Utilisez toujours HTTPS pour ce domaine. » C’est bien. Cela signifie aussi que toute dépendance HTTP restante devient une défaillance nette. Déployez-le en phases : max-age court, vérifiez, puis augmentez. Évitez le préchargement tant que tout n’est pas propre et durablement propre.
Citation opérationnelle
L’espoir n’est pas une stratégie.
— James Cameron
Blague #2 : Le cadenas du navigateur est essentiellement votre auditeur de sécurité, sauf qu’il travaille les week-ends et n’accepte jamais de donuts.
FAQ
Pourquoi le contenu mixte apparaît-il encore après avoir changé WordPress Address et Site Address ?
Parce que ces réglages modifient ce que WordPress génère à l’avenir, pas ce que vous avez déjà stocké. Les anciens articles, widgets, données de constructeur et options de thème peuvent encore contenir des URLs absolues en HTTP. Lancez un search/replace sûr pour la sérialisation et scannez le code thème/plugin.
Puis-je « réparer le contenu mixte » en utilisant un plugin qui force HTTPS ?
Parfois il masque les symptômes en réécrivant la sortie. Il corrige rarement la cause racine. Utilisez-le seulement comme mitigation temporaire pendant que vous nettoyez la base et le code. Sinon vous déployez un hack permanent qui échouera lors du caching, de la minification ou des mises à jour de plugins.
Quelle est la manière la plus sûre de remplacer HTTP par HTTPS dans la base de données ?
WP-CLI wp search-replace avec un dry-run d’abord. Il gère correctement les données sérialisées. Faites toujours une sauvegarde de la BD avant l’exécution réelle, surtout sur des sites utilisant des builders.
Pourquoi le contenu mixte apparaît-il seulement dans Chrome et pas dans Firefox (ou inversement) ?
Les navigateurs diffèrent sur ce qu’ils bloquent vs signalent, et sur leur comportement de cache et de reporting DevTools. Ne discutez pas avec le navigateur ; utilisez DevTools Réseau/Console pour identifier l’URL précise et corrigez-la à la source.
Je suis derrière Cloudflare (ou un autre CDN). Pourquoi WordPress pense-t-il être en HTTP ?
Parce que la connexion origine peut être en HTTP, et les en-têtes forwardés peuvent ne pas être définis ou approuvés. Assurez-vous que le CDN envoie X-Forwarded-Proto: https et configurez votre origine/WordPress pour considérer la requête comme HTTPS le cas échéant.
Est-il acceptable de laisser du contenu mixte « passif » comme des images ?
Non. Cela habitue les utilisateurs à ignorer les signaux de sécurité et peut encore divulguer des comportements via les métadonnées des requêtes. De plus, les navigateurs resserrent progressivement les règles. Corrigez-le maintenant tant que ce n’est qu’un avertissement, pas une page cassée.
Activer HSTS va-t-il corriger le contenu mixte ?
Non. HSTS force l’utilisation de HTTPS pour la navigation de premier niveau vers votre domaine. Il ne réécrit pas les URLs tierces et ne réparera pas les liens HTTP intégrés dans le HTML, le CSS ou les scripts. Il peut rendre les échecs plus visibles, ce qui est utile après nettoyage.
Pourquoi WooCommerce affiche-t-il du contenu mixte spécifiquement au checkout ?
Les pages de checkout incluent souvent des scripts fournisseurs de paiement, iframes et appels API. Une seule endpoint HTTP suffit pour déclencher des avertissements ou des blocages. Vérifiez DevTools pour les URLs tierces et assurez-vous que vos en-têtes proxy et réglages d’URL du site sont corrects.
Comment savoir que j’ai tout corrigé et pas seulement une page ?
Testez des templates représentatifs : page d’accueil, article, catégorie, recherche, login, panier/checkout, et quelques landing pages construites avec votre builder. Récupérez et greppez programmatiquement le HTML pour http://, et utilisez DevTools navigateur pour attraper les requêtes à l’exécution.
Prochaines étapes à déployer aujourd’hui
- Choisissez une page qui échoue et identifiez la ressource HTTP exacte dans DevTools.
- Vérifiez que
homeetsiteurlsont en HTTPS ; corrigez si nécessaire. - Exécutez WP-CLI
search-replace(dry-run, puis réel) pour votre domaine. - Scannez le code thème/plugin et le CSS pour des
http://codés en dur et supprimez-les. - Purgez toutes les couches de cache (cache de page + CDN) après les modifications.
- Ce n’est qu’après que le site est propre que vous pouvez déployer HSTS progressivement pour éviter les retours en arrière.
Si vous suivez ces étapes dans l’ordre, le contenu mixte cesse d’être un caprice du navigateur et redevient un simple nettoyage d’ingénierie. Comme ça a toujours été.