iframe « n'autorise pas la connexion » : X-Frame-Options

Point clé

« n'autorise pas la connexion » dans une iframe n'est pas une erreur réseau. Le site intégré a envoyé un en-tête X-Frame-Options ou CSP frame-ancestors qui demande à votre navigateur de ne pas l'afficher dans une autre page. Le correctif se fait sur le serveur du site intégré, jamais dans votre balise iframe : gardez SAMEORIGIN sur tout le site et ouvrez un seul chemin d'intégration avec frame-ancestors *.

Vérifiez maintenant

X-Frame-Options expliqué : une iframe qui affiche « n'autorise pas la connexion » et le correctif — SAMEORIGIN sur tout le site, CSP frame-ancestors * sur le chemin d'intégration
X-Frame-Options expliqué : une iframe qui affiche « n'autorise pas la connexion » et le correctif — SAMEORIGIN sur tout le site, CSP frame-ancestors * sur le chemin d'intégration
Commencer la lecture
  1. Ce que signifie vraiment « n'autorise pas la connexion » dans une iframe
  2. Comment fonctionne X-Frame-Options
  3. DENY ou SAMEORIGIN : lequel envoyer ?
  4. ALLOW-FROM est mort — ne l'utilisez pas
  5. frame-ancestors : la directive CSP qui le remplace
  6. Que se passe-t-il quand les deux en-têtes sont présents
  7. Étape 1 : trouver l'en-tête qui vous bloque
  8. Étape 2 : décider qui peut encadrer la page
  9. Le bon modèle : verrouiller le site, ouvrir un seul chemin d'intégration
  10. Nginx (et le piège d'add_header)
  11. Apache
  12. Next.js et Express
  13. Intégrer un widget tiers en toute sécurité
  14. sandbox : quoi autoriser pour un widget de calculatrice
  15. Pourquoi il n'y a aucun correctif côté intégrateur
  16. Vérifier les en-têtes après chaque changement
  17. Symptôme → cause → correctif
  18. Questions fréquentes

Ce que signifie vraiment « n'autorise pas la connexion » dans une iframe

Vous ajoutez une <iframe> vers un autre site, vous rechargez, et au lieu de la page vous obtenez un cadre gris avec une icône de visage triste ; au survol, il affiche example.com n'autorise pas la connexion. Votre premier réflexe est de soupçonner le réseau, puisque c'est exactement ce que Chrome affiche pour un serveur injoignable. Mais ouvrez DevTools : la console raconte autre chose :

text
Refused to display 'https://emicalcs.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.

Rien n'a échoué côté réseau. Le DNS a répondu, la connexion TCP s'est ouverte, TLS s'est terminé et le serveur a renvoyé un très correct 200. Le navigateur a téléchargé la page, lu un en-tête de réponse, puis a délibérément refusé de l'afficher dans votre page. Cet en-tête est X-Frame-Options, et il existe pour empêcher le clickjacking — une attaque où une page hostile charge un formulaire de connexion ou de paiement dans une iframe invisible et pousse les visiteurs à cliquer sur des boutons qu'ils ne voient pas.

Cela change la façon de diagnostiquer. Une vraie panne de connexion — ERR_CONNECTION_REFUSED quand vous ouvrez l'URL directement dans un onglet — est un problème de serveur ou de pare-feu, traité dans ERR_CONNECTION_REFUSED. La version iframe n'apparaît que lorsque la page est encadrée, et la même URL fonctionne dans son propre onglet. Si le site se charge directement mais pas dans votre cadre, vous avez affaire à une politique de cadrage, pas à une panne.

Voir les en-têtes X-Frame-Options et CSP d'une page

Comment fonctionne X-Frame-Options

X-Frame-Options est un en-tête de réponse HTTP, décrit pour la première fois dans la RFC 7034, une RFC informative que le standard HTML remplace désormais, et pris en charge par tous les navigateurs depuis Internet Explorer 8. Le serveur l'attache à une page ; le navigateur le lit avant l'affichage et décide si la page peut apparaître dans un <frame>, <iframe>, <embed> ou <object> d'une autre page.

Il accepte deux valeurs qui comptent encore, plus une qui ne compte plus :

ValeurQui peut encadrer la pageUsage typique
DENYPersonne — pas même le même sitePages de connexion, panneaux d'administration, tout ce qui porte une session
SAMEORIGINUniquement les pages de la même origine exacte (schéma + hôte + port)Bon choix par défaut pour la plupart des sites ; permet d'encadrer vos propres pages
ALLOW-FROM https://a.comObsolète — ignorée par tous les navigateurs modernesÀ ne pas utiliser ; voir plus bas

L'en-tête s'applique par réponse, pas par site. C'est le détail que la plupart des guides omettent, et celui qui rend possible le correctif de cet article : un serveur peut envoyer SAMEORIGIN sur 99 % de ses pages et une autre politique sur le seul chemin destiné à être intégré.

DENY ou SAMEORIGIN : lequel envoyer ?

Envoyez SAMEORIGIN sauf raison contraire. Il bloque tout cadre tiers tout en laissant votre site encadrer ses propres pages — widgets d'aide, aperçus, tableaux de bord qui chargent d'autres pages internes.

Envoyez DENY sur les pages où le cadrage n'a aucune raison légitime et où le risque est grave : formulaires de connexion, pages de paiement, actions en un clic comme « supprimer le compte ». DENY couvre aussi un cas subtil où un attaquant parvient à injecter un cadre dans l'une de vos propres pages — avec SAMEORIGIN, ce cadre injecté resterait autorisé.

Quel que soit votre choix, définissez-le une fois au niveau du serveur web ou du CDN pour couvrir toutes les réponses, y compris les pages d'erreur et les fichiers statiques. Les en-têtes posés dans le code de l'application oublient souvent la page 404 et la page de maintenance : posez-les là où passent toutes les réponses.

ALLOW-FROM est mort — ne l'utilisez pas

D'anciens articles recommandent encore X-Frame-Options: ALLOW-FROM https://partner.com pour autoriser un seul site intégrateur. Cela n'a jamais fonctionné dans Chrome ni Safari, et Firefox l'a abandonné dans sa version 70 (octobre 2019). Pire, un navigateur moderne qui voit ALLOW-FROM considère l'en-tête entier comme invalide et l'ignore complètement, ce qui laisse la page encadrable par n'importe qui — l'inverse de l'effet voulu.

Pour autoriser des sites précis, la réponse est CSP frame-ancestors, expliqué ensuite. X-Frame-Options ne sait dire que « personne » ou « moi seul ».

frame-ancestors : la directive CSP qui le remplace

Content Security Policy niveau 2 a introduit frame-ancestors, une directive qui fait tout ce que fait X-Frame-Options et ajoute ce qu'il ne peut pas faire : une vraie liste d'autorisation. Elle voyage dans l'en-tête standard Content-Security-Policy et accepte une ou plusieurs sources :

http
# Nobody may frame this (same as X-Frame-Options: DENY)
Content-Security-Policy: frame-ancestors 'none'

# Only my own origin (same as SAMEORIGIN)
Content-Security-Policy: frame-ancestors 'self'

# My origin plus two named partners, one with a subdomain wildcard
Content-Security-Policy: frame-ancestors 'self' https://partner.example https://*.trusted.example

# Anyone may frame this — for a public embed endpoint only
Content-Security-Policy: frame-ancestors *

Trois détails à connaître avant de passer à cette directive :

  • Elle vérifie tous les ancêtres, pas seulement le parent. Si la page A encadre la page B et que B encadre la vôtre, A et B doivent être autorisées (CSP). Le standard HTML applique désormais aussi X-Frame-Options à tous les ancêtres (WHATWG), mais les anciens navigateurs ne vérifiaient que le parent ou la page de premier niveau.
  • Elle ne fonctionne qu'en en-tête HTTP. frame-ancestors est explicitement ignoré quand la CSP est livrée par une balise <meta http-equiv> — le navigateur doit connaître la politique avant même de décider d'afficher le document. Il en va de même pour X-Frame-Options. Aucun des deux ne peut être posé depuis le HTML.
  • Les jokers valent par hôte, pas globalement. https://*.example.com correspond à tout sous-domaine d'un site ; un simple * correspond à toutes les origines d'Internet. Parfait pour un widget de calculatrice, mauvais pour tout ce qui porte une session.

Que se passe-t-il quand les deux en-têtes sont présents

La plupart des sites finissent par envoyer les deux pendant une migration, et la priorité est définie : si frame-ancestors est présent, le navigateur l'applique et ignore X-Frame-Options. La spécification CSP niveau 2 le dit sans détour, et Chrome, Firefox, Safari et Edge la suivent.

La migration sûre est donc simple. Gardez X-Frame-Options: SAMEORIGIN pour les rares clients très anciens antérieurs à CSP 2, ajoutez Content-Security-Policy: frame-ancestors 'self' à côté, et tous les navigateurs modernes appliqueront la règle CSP. Les deux ne posent problème que si vous leur faites dire des choses différentes — X-Frame-Options: DENY à côté de frame-ancestors *, par exemple — auquel cas les navigateurs modernes autorisent le cadrage et seuls de très vieux navigateurs bloquent. Gardez-les cohérents et il n'y a rien à déboguer.

Étape 1 : trouver l'en-tête qui vous bloque

Avant de changer quoi que ce soit, confirmez quelle politique s'applique. La console vous a déjà donné le nom de l'en-tête ; curl vous montre la valeur exacte envoyée par le serveur. Cet exemple utilise le site de l'exemple détaillé plus bas — ses pages principales sont volontairement verrouillées :

bash
curl -sI https://emicalcs.com/ | grep -i -E 'x-frame-options|content-security-policy'

# Output:
# x-frame-options: SAMEORIGIN

Vous obtenez l'un de ces trois cas :

  • x-frame-options: SAMEORIGIN ou DENY — la politique de cadrage classique. Seul un changement sur ce serveur peut la lever.
  • content-security-policy: … frame-ancestors … — une politique CSP. Lisez la liste des sources ; si votre origine n'y figure pas, vous êtes bloqué. La directive est souvent noyée dans un long en-tête CSP à côté de script-src et consorts : lisez toute la valeur.
  • Aucun des deux en-têtes : le site intégré autorise le cadre, et « n'autorise pas la connexion » a une autre cause : une redirection vers une page qui, elle, est verrouillée (souvent une page de connexion ; suivez-la avec curl -sIL), ou un en-tête Cross-Origin-Embedder-Policy: require-corp sur votre propre page, qui bloque tout cadre n'ayant pas donné son accord et affiche le même cadre gris.

Étape 2 : décider qui peut encadrer la page

Tout ce qui suit dépend d'une question : contrôlez-vous le site encadré ?

Si non, arrêtez-vous ici. Il n'existe aucun contournement côté client — ni attribut sandbox, ni autre src, ni option de navigateur que vos visiteurs auraient. Le propriétaire du site a décidé que sa page ne devait pas être intégrée, et le navigateur applique cette décision pour lui. Vos options : lier vers la page, demander au propriétaire s'il propose un point d'intégration, ou utiliser un widget officiel s'il existe. Beaucoup de services qui verrouillent leur site principal en proposent un ; l'exemple de la section suivante en montre un.

Si vous le contrôlez, résistez à la tentation de retirer l'en-tête sur tout le site. Cela rouvre le clickjacking sur toutes les pages — y compris celles qui portent des sessions et des formulaires — pour réparer une intégration sur une seule. Décidez plutôt quels chemins précis doivent être encadrés, et par qui :

SituationEn-tête à envoyer sur ce chemin
Outil interne encadré par votre propre tableau de bordframe-ancestors 'self' (plus X-Frame-Options: SAMEORIGIN)
Widget intégré par quelques partenaires connusframe-ancestors 'self' https://partner-a.com https://partner-b.com
Widget public intégrable (calculatrice, carte, lecteur)frame-ancestors * sur le chemin d'intégration uniquement
Tout le resteframe-ancestors 'self' plus X-Frame-Options: SAMEORIGIN

Le bon modèle : verrouiller le site, ouvrir un seul chemin d'intégration

L'exemple réel le plus propre de ce modèle que j'aie rencontré est EMICalcs, une collection gratuite de 45 calculatrices financières indiennes — mensualité de prêt, SIP, impôt sur le revenu, GST, etc. — que d'autres sites sont invités à intégrer. Le site principal est verrouillé ; un chemin dédié /embed/ est ouvert. Comparez les en-têtes des deux :

bash
# The calculator page a visitor normally uses — locked
curl -sI https://emicalcs.com/income-tax-calculator/ | grep -i -E 'x-frame|frame-ancestors'
# x-frame-options: SAMEORIGIN

# The same calculator on its embed path — open to any site
curl -sI https://emicalcs.com/embed/income-tax-calculator/ | grep -i -E 'x-frame|frame-ancestors'
# content-security-policy: frame-ancestors *

Remarquez ce que la réponse d'intégration ne contient pas : aucun en-tête X-Frame-Options sur /embed/. C'est voulu. Comme la directive CSP a priorité, laisser SAMEORIGIN serait inoffensif dans les navigateurs modernes — mais cela dérouterait le prochain ingénieur qui lira les en-têtes, et cela bloquerait encore les quelques vieux clients qui ne comprennent que X-Frame-Options. Le chemin d'intégration envoie une seule politique, et elle dit une seule chose.

Tout le reste du site garde SAMEORIGIN : la page d'accueil, les articles et les pages de calculatrices complètes restent protégés contre le clickjacking. Les versions intégrées sont des documents épurés, sans navigation et sans rien à détourner, ce qui rend raisonnable de les ouvrir à *.

Leur guide d'intégration vaut la lecture comme modèle si vous publiez votre propre widget : une URL stable par calculatrice, une hauteur fixe qui convient à la plupart, loading="lazy" dans l'extrait, et la promesse que les URL d'intégration retirées redirigeront au lieu de renvoyer 404 — car chaque site qui vous intègre compte sur la pérennité de votre URL.

Nginx (et le piège d'add_header)

Voici le même modèle aux trois endroits où la plupart des sites posent leurs en-têtes. Dans chaque cas, une règle globale verrouille tout et une règle plus étroite la remplace pour le chemin d'intégration. Nginx d'abord, car il a un piège :

nginx
# Site-wide default (server block)
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;
add_header X-Content-Type-Options "nosniff" always;

location /embed/ {
    # WARNING: any add_header here stops ALL add_header inheritance from the
    # server block — re-declare every header you still want on this path.
    add_header Content-Security-Policy "frame-ancestors *" always;
    add_header X-Content-Type-Options "nosniff" always;
}

Le commentaire n'est pas facultatif. add_header n'est pas fusionné entre les niveaux : dès qu'un bloc location déclare un add_header, il cesse d'hériter de tous les add_header du bloc server. Des équipes perdent ainsi HSTS ou nosniff sur le chemin d'intégration et ne le découvrent que des mois plus tard lors d'un scan de sécurité. Redéclarez ce dont vous avez besoin, et laissez X-Frame-Options hors du bloc d'intégration pour que le chemin envoie une politique claire. Depuis nginx 1.29.3, add_header_inherit merge peut réactiver l'héritage (nginx), mais ne l'utilisez pas dans le bloc d'intégration : il y rajouterait X-Frame-Options et frame-ancestors 'self' du site entier, et avec deux en-têtes CSP le navigateur applique les deux, donc le cadre reste bloqué.

Apache

La directive Header d'Apache fusionne entre les portées : vous pouvez définir la valeur par défaut une fois et ne toucher que les deux en-têtes qui changent sur le chemin d'intégration :

apache
# Site-wide default (needs mod_headers)
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Content-Security-Policy "frame-ancestors 'self'"

<LocationMatch "^/embed/">
    Header always unset X-Frame-Options
    Header always set Content-Security-Policy "frame-ancestors *"
</LocationMatch>

Next.js et Express

Dans Next.js, les en-têtes se déclarent dans next.config.js. Quand deux règles correspondent au même chemin et définissent le même en-tête, la dernière l'emporte — mais un en-tête défini seulement par la première règle s'applique quand même. Pour garder X-Frame-Options totalement hors du chemin d'intégration, excluez-le de la règle globale avec un lookahead négatif :

javascript
// next.config.js
module.exports = {
  async headers() {
    return [
      {
        // Every path EXCEPT /embed/... gets the locked defaults
        source: '/((?!embed/).*)',
        headers: [
          { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
          { key: 'Content-Security-Policy', value: "frame-ancestors 'self'" },
        ],
      },
      {
        source: '/embed/:path*',
        headers: [
          { key: 'Content-Security-Policy', value: 'frame-ancestors *' },
        ],
      },
    ]
  },
}

Sur Express, le middleware populaire helmet envoie déjà par défaut X-Frame-Options: SAMEORIGIN et une CSP qui inclut frame-ancestors 'self'. Montez-le globalement, puis, sur le routeur d'intégration, appelez res.removeHeader('X-Frame-Options') et définissez Content-Security-Policy sur frame-ancestors * avant le rendu. L'ordre compte : votre remplacement doit s'exécuter après helmet, sinon helmet l'écrasera.

Intégrer un widget tiers en toute sécurité

Voyons l'autre côté de la barrière : vous êtes le site intégrateur, le fournisseur a un chemin d'intégration ouvert, et vous voulez que le cadre se comporte bien. Un extrait de widget bien fait ressemble à ceci ; c'est celui qu'EMICalcs publie sur chaque page de calculatrice :

html
<iframe src="https://emicalcs.com/embed/income-tax-calculator/"
        title="Income Tax Calculator FY 2026-27 — EMICalcs"
        width="100%" height="760"
        style="max-width:680px;border:0;border-radius:16px;overflow:hidden"
        loading="lazy"></iframe>
<p>Free <a href="https://emicalcs.com/income-tax-calculator/" target="_blank" rel="noopener">Income Tax Calculator FY 2026-27</a> by EMICalcs</p>

Chaque attribut a un rôle :

  • title — nomme le cadre pour les lecteurs d'écran. Sans lui, les technologies d'assistance annoncent « cadre » et rien d'autre, et les audits d'accessibilité font échouer la page.
  • width="100%" avec un max-width dans style — remplit les colonnes étroites sur mobile sans déborder des colonnes larges sur ordinateur.
  • Une height fixe — la page intégratrice ne peut pas lire la hauteur du contenu d'un cadre inter-origines ; une valeur codée en dur est donc le seul moyen d'éviter un décalage de mise en page pendant le chargement. Définissez-la une fois par widget.
  • loading="lazy" — reporte la requête jusqu'à ce que le cadre approche de la zone visible, si bien qu'un widget en bas d'un long article ne coûte rien au chargement initial.
  • border:0; border-radius; overflow:hidden — retire la bordure en relief par défaut et arrondit les coins pour que le widget paraisse natif dans votre page.

La ligne de crédit se place volontairement en dehors de l'iframe. Tout ce qui est dans le cadre appartient au document encadré — ses liens sont ceux du fournisseur, sur l'URL du fournisseur — donc un lien dans le cadre ne fait pas partie de votre page pour vos lecteurs ni pour un robot d'indexation. Si vous voulez citer la source, ou si le fournisseur le demande, mettez un simple paragraphe à côté du cadre dans votre propre HTML, comme ci-dessus.

sandbox : quoi autoriser pour un widget de calculatrice

L'attribut sandbox est la protection de l'intégrateur lui-même. Ajoutez-le sans valeur et la page encadrée n'obtient rien : ni scripts, ni formulaires, ni fenêtres surgissantes, ni navigation de votre fenêtre, et une origine opaque qui désactive ses propres cookies et son stockage. Ajoutez ensuite seulement ce dont le widget a besoin :

html
<iframe src="https://emicalcs.com/embed/loan-emi-calculator/"
        sandbox="allow-scripts allow-forms allow-same-origin allow-popups"
        title="Loan EMI Calculator — EMICalcs"
        width="100%" height="760" loading="lazy"></iframe>

allow-scripts et allow-forms sont le minimum pour tout ce qui est interactif. allow-same-origin laisse la page encadrée garder sa propre origine pour que son stockage et ses cookies fonctionnent — sur une intégration inter-origines c'est sans danger, car « son origine » reste celle du fournisseur, pas la vôtre. allow-popups n'est nécessaire que si le widget ouvre des liens dans un nouvel onglet, comme le fait le lien de crédit dans l'intégration EMICalcs.

Ce qu'il ne faut pas faire, c'est combiner allow-scripts avec allow-same-origin sur un cadre qui pointe vers votre propre origine. Le script encadré peut alors remonter et retirer son propre attribut sandbox, et vous n'avez rien isolé.

Pourquoi il n'y a aucun correctif côté intégrateur

Une recherche « iframe refused to connect » fait remonter trois contournements populaires. Tous sont mauvais, et il est utile de savoir exactement pourquoi.

  • Les extensions de navigateur qui suppriment X-Frame-Options — elles ne fonctionnent que dans votre propre navigateur. Tous les visiteurs de votre site voient toujours le cadre gris, et vous avez désactivé la protection contre le clickjacking sur tous les sites que vous visitez entre-temps.
  • Faire transiter la page par votre propre serveur — vous récupérez le HTML tiers côté serveur et le servez depuis votre origine, si bien que l'en-tête n'atteint jamais le navigateur. Cela casse les liens relatifs, les cookies, les connexions et tout ce qui repose sur des scripts ; vous devenez responsable de leur contenu ; et cela viole en général les conditions du fournisseur. Les sites qui vous repèrent bloquent l'IP de votre serveur.
  • Les services de capture d'écran ou « web-to-image » — vous obtenez une image fixe, pas une page qui fonctionne. Correct pour une vignette d'aperçu, inutile pour une calculatrice.

L'en-tête est une déclaration du propriétaire du site, appliquée par le navigateur, sur ce qui peut arriver à sa page. Les seules voies légitimes sont les deux déjà vues : le propriétaire ouvre un chemin d'intégration, ou vous faites un lien. Les fournisseurs qui veulent être intégrés le rendent facile — les bons publient un extrait, gardent l'URL stable et n'ouvrent que le chemin qu'il est sûr d'ouvrir.

Vérifier les en-têtes après chaque changement

Les en-têtes de cadrage sont posés dans un fichier de configuration puis oubliés, et un CDN, un reverse proxy ou un plugin de sécurité bien intentionné peut les ajouter, les retirer ou les dupliquer à tout moment. Après le déploiement, vérifiez depuis l'extérieur de votre réseau :

bash
# The locked pages should show SAMEORIGIN and/or frame-ancestors 'self'
curl -sI https://example.com/ | grep -i -E 'x-frame-options|content-security-policy'

# The embed path should show ONLY frame-ancestors, with the sources you intended
curl -sI https://example.com/embed/widget/ | grep -i -E 'x-frame-options|content-security-policy'

# Error pages should carry the header too
curl -sI https://example.com/this-does-not-exist | grep -i -E 'x-frame-options|content-security-policy'

Testez ensuite comme le fait un navigateur : placez l'URL d'intégration dans une <iframe> sur une page servie depuis une origine différente — une page locale file:// ne convient pas, car les navigateurs la traitent à part — et ouvrez la console. Un chargement propre signifie aucune ligne Refused to display ni Refused to frame.

Si le site est derrière Cloudflare ou un autre CDN, une copie en cache ou une règle de périphérie peut porter d'autres en-têtes que votre origine. Le vérificateur d'en-têtes HTTP demande l'URL depuis notre serveur, en dehors de votre navigateur et de votre réseau, et affiche X-Frame-Options et Content-Security-Policy avec un verdict de cadrage (SAMEORIGIN ou DENY, via CSP frame-ancestors, ou non envoyé) : un moyen rapide de repérer une règle de CDN qui a discrètement remis SAMEORIGIN sur votre chemin d'intégration.

Symptôme → cause → correctif

Utilisez ce tableau pour aller directement au correctif au lieu de relire tout le guide :

Ce que vous voyezCe que cela signifieCorrectif
Cadre gris « n'autorise pas la connexion », mais l'URL s'ouvre dans un ongletX-Frame-Options ou frame-ancestors a bloqué le cadreSeul le propriétaire du site peut le changer — utilisez son chemin d'intégration ou faites un lien
Console : Refused to display … 'X-Frame-Options' to 'sameorigin'En-tête classique ; seuls les cadres de même origine sont autorisésSur le site encadré, ouvrez le chemin d'intégration avec frame-ancestors * ou une liste de partenaires
Console : Refused to frame … violates … frame-ancestorsLa liste d'autorisation CSP n'inclut pas votre origineAjoutez votre origine aux sources frame-ancestors du site encadré
Fonctionnait hier, cassé aujourd'hui, sans changement de codeUn CDN ou un plugin de sécurité s'est mis à injecter SAMEORIGINVérifiez avec curl ; excluez le chemin d'intégration dans la règle du CDN ou du plugin
Votre propre tableau de bord ne peut pas encadrer votre propre pageSous-domaine ou schéma différent (www contre domaine nu, http contre https)Utilisez frame-ancestors 'self' https://example.com https://*.example.com (le joker ne couvre pas le domaine nu)
L'intégration fonctionne, mais HSTS ou nosniff ont disparu sur ce cheminL'héritage d'add_header de Nginx les a perdusRedéclarez chaque en-tête dans le bloc location
ERR_CONNECTION_REFUSED en ouvrant l'URL directementUne vraie panne réseau, pas une politique de cadrageVoir ERR_CONNECTION_REFUSED et le vérificateur de ports

Si l'URL échoue aussi dans son propre onglet, le cadre est une fausse piste. Parcourez les couches réseau dans l'ordre — DNS, port, TLS, en-têtes — avec le guide de test d'un point d'accès API public avant de toucher aux en-têtes de cadrage.

Voir tous les en-têtes de sécurité envoyés par une URL

Vérifiez X-Frame-Options, Content-Security-Policy, HSTS et le reste pour n'importe quelle page, récupérés depuis nos serveurs : une extension de navigateur ou un proxy de votre réseau ne peut donc pas changer ce que vous voyez. Gratuit, sans inscription.

Sources

  1. RFC 7034: HTTP Header Field X-Frame-Options, IETF
  2. CSP Level 3: frame-ancestors, W3C
  3. HTML Standard: the X-Frame-Options header, WHATWG
  4. ngx_http_headers_module (add_header, add_header_inherit), nginx

Questions fréquentes

X-Frame-Options est-il obsolète ?

Fonctionnellement, il a été supplanté par la directive CSP frame-ancestors, que les navigateurs privilégient dès que les deux en-têtes sont présents. Il n'est pourtant pas inutile : tous les navigateurs actuels respectent encore X-Frame-Options quand frame-ancestors est absent, et il protège le petit nombre de vieux clients antérieurs à CSP niveau 2. Le conseil pratique : envoyez les deux et gardez-les cohérents — SAMEORIGIN à côté de frame-ancestors 'self'.

Que signifie X-Frame-Options: DENY ?

DENY indique au navigateur que la page ne doit jamais être affichée dans un élément frame, iframe, embed ou object, sur aucune page — y compris les pages du même site. C'est le réglage le plus strict, adapté aux formulaires de connexion, pages de paiement et panneaux d'administration, où aucune raison légitime n'impose l'intégration et où le clickjacking serait grave.

Quelle différence entre DENY et SAMEORIGIN ?

DENY bloque tout cadrage. SAMEORIGIN n'autorise le cadrage que par des pages de la même origine exacte — même schéma, même hôte, même port — et bloque tous les autres. SAMEORIGIN est le bon défaut pour tout le site : il arrête le clickjacking tiers tout en laissant votre site encadrer ses propres pages ; DENY est pour la poignée de pages qui ne doivent jamais être encadrées.

Comment contourner X-Frame-Options pour intégrer un site ?

Depuis le côté intégrateur, c'est impossible. L'en-tête est défini par le site que vous essayez d'encadrer et appliqué par le navigateur de vos visiteurs ; aucun attribut d'iframe, drapeau sandbox ou astuce côté client n'y change rien. Les extensions qui suppriment l'en-tête n'agissent que sur votre navigateur, et faire transiter la page par votre serveur la casse et viole en général les conditions du fournisseur. Les voies légitimes : utiliser un point d'intégration officiel si le fournisseur en propose un, ou faire un lien vers la page.

Comment définir X-Frame-Options sur DENY ?

Ajoutez-le comme en-tête de réponse HTTP au niveau du serveur web pour couvrir toutes les pages, pages d'erreur comprises. Nginx : add_header X-Frame-Options "DENY" always; Apache : Header always set X-Frame-Options "DENY". Associez-le à Content-Security-Policy: frame-ancestors 'none' pour les navigateurs modernes. Impossible avec une balise meta : seul un en-tête HTTP fonctionne.

Pourquoi mon iframe affiche « n'autorise pas la connexion » alors que le site marche dans un nouvel onglet ?

Parce que la connexion n'a aucun problème. Le site a renvoyé la page normalement, mais avec un en-tête X-Frame-Options ou frame-ancestors qui interdit de l'afficher dans une autre page. Chrome affiche le même cadre gris « n'autorise pas la connexion » que pour une vraie panne réseau, ce qui prête à confusion ; le message de console « Refused to display … in a frame » est l'indice décisif.

Peut-on définir X-Frame-Options ou frame-ancestors dans une balise meta ?

Non. Les deux doivent être livrés comme en-têtes de réponse HTTP. Le navigateur doit connaître la politique de cadrage avant de décider d'afficher le document, et une balise meta arrive trop tard. frame-ancestors est explicitement ignoré dans une CSP meta http-equiv, et X-Frame-Options dans une balise meta est ignoré par tous les navigateurs.

frame-ancestors * rend-il mon site vulnérable ?

Seulement pour les réponses qui l'envoient. L'en-tête est évalué par document : envoyer frame-ancestors * sur un chemin /embed/ dédié laisse le reste du site pleinement protégé par SAMEORIGIN ou frame-ancestors 'self'. Le risque se limite à ce qu'un attaquant pourrait gagner en encadrant la page d'intégration elle-même — ce qui, pour un widget sans état, sans cookie de session et sans action sensible, n'est rien.

Pourquoi X-Frame-Options: ALLOW-FROM ne fonctionne-t-il pas ?

ALLOW-FROM n'a jamais été implémenté que par Internet Explorer, l'Edge d'origine (versions 12 à 18) et Firefox, qui l'a supprimé dans la version 70. Chrome et Safari ne l'ont jamais pris en charge. Les navigateurs modernes jugent invalide un en-tête contenant ALLOW-FROM et l'ignorent entièrement, ce qui laisse la page encadrable par n'importe qui. Utilisez la directive CSP frame-ancestors, qui accepte une vraie liste d'origines autorisées.

Quel en-tête l'emporte si X-Frame-Options et frame-ancestors sont tous deux définis ?

frame-ancestors. Le standard HTML demande aux navigateurs d'ignorer X-Frame-Options dès qu'une CSP appliquée contient frame-ancestors (CSP niveau 2 le recommandait déjà), et tous les navigateurs actuels le font ; une politique Report-Only ne compte pas. Seuls les clients trop anciens pour comprendre CSP se rabattent sur X-Frame-Options, d'où l'intérêt de l'envoyer encore — tant que les deux en-têtes concordent.

À propos de l’auteur

Shaik Vahid

Fondateur de DNS Robot. Vahid a passé des années au support d’hébergement web à réparer les domaines, les enregistrements DNS, les certificats SSL et la distribution des e-mails de clients. Il développe les outils de DNS Robot et écrit ces guides à partir des erreurs que les gens rencontrent vraiment.

Vérificateur d'en-têtes HTTP

Analysez les en-têtes de réponse HTTP et la notation des en-têtes de sécurité