iframe „Verbindung abgelehnt“: X-Frame-Options beheben

Kernaussage

„hat die Verbindung abgelehnt“ im iframe ist kein Netzwerkfehler. Die eingebettete Website hat einen X-Frame-Options- oder CSP-frame-ancestors-Header gesendet, der dem Browser verbietet, sie in einer anderen Seite darzustellen. Die Lösung liegt auf dem Server der eingebetteten Website, nie im iframe-Tag: Lassen Sie SAMEORIGIN für die ganze Website stehen und öffnen Sie nur einen einzigen Einbettungspfad mit frame-ancestors *.

Jetzt prüfen

X-Frame-Options erklärt: ein iframe mit „hat die Verbindung abgelehnt“ und die Lösung – SAMEORIGIN für die ganze Website, CSP frame-ancestors * nur für den Einbettungspfad
X-Frame-Options erklärt: ein iframe mit „hat die Verbindung abgelehnt“ und die Lösung – SAMEORIGIN für die ganze Website, CSP frame-ancestors * nur für den Einbettungspfad
Jetzt lesen
  1. Was „hat die Verbindung abgelehnt“ in einem iframe wirklich bedeutet
  2. So funktioniert X-Frame-Options
  3. DENY oder SAMEORIGIN: Was sollten Sie senden?
  4. ALLOW-FROM ist tot – nicht verwenden
  5. frame-ancestors: Die CSP-Direktive, die ihn ersetzt
  6. Was passiert, wenn beide Header gesetzt sind
  7. Schritt 1: Den blockierenden Header finden
  8. Schritt 2: Entscheiden, wer die Seite einbetten darf
  9. Das richtige Muster: Website sperren, einen Embed-Pfad öffnen
  10. Nginx (und die add_header-Falle)
  11. Apache
  12. Next.js und Express
  13. Ein Drittanbieter-Widget sicher einbetten
  14. sandbox: Was Sie für ein Rechner-Widget erlauben sollten
  15. Warum es auf der einbettenden Seite keine Lösung gibt
  16. Header nach jeder Änderung prüfen
  17. Symptom → Ursache → Lösung
  18. Häufige Fragen

Was „hat die Verbindung abgelehnt“ in einem iframe wirklich bedeutet

Sie fügen einen <iframe> ein, der auf eine andere Website zeigt, laden neu und sehen statt der Seite eine graue Box mit traurigem Smiley. Fahren Sie mit der Maus darüber, steht dort example.com hat die Verbindung abgelehnt. Ihr erster Gedanke ist ein Netzwerkproblem, denn genau das zeigt Chrome bei einem toten Server. Öffnen Sie aber die DevTools, erzählt die Konsole etwas anderes:

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

Im Netzwerk ist nichts fehlgeschlagen. DNS wurde aufgelöst, die TCP-Verbindung kam zustande, TLS wurde abgeschlossen, und der Server lieferte eine völlig normale 200. Der Browser hat die Seite geladen, einen Antwort-Header gelesen und sich dann absichtlich geweigert, sie in Ihrer Seite darzustellen. Dieser Header heißt X-Frame-Options und soll Clickjacking verhindern – einen Angriff, bei dem eine feindliche Seite ein Login- oder Zahlungsformular in einem unsichtbaren iframe lädt und Besucher dazu bringt, auf Schaltflächen zu klicken, die sie nicht sehen.

Das ist für die Fehlersuche wichtig. Ein echter Verbindungsfehler – ERR_CONNECTION_REFUSED, wenn Sie die URL direkt in einem Tab öffnen – ist ein Server- oder Firewall-Problem und wird in ERR_CONNECTION_REFUSED behandelt. Die iframe-Variante tritt nur auf, wenn die Seite eingebettet ist; dieselbe URL funktioniert im eigenen Tab einwandfrei. Lädt die Website direkt, aber nicht im Frame, haben Sie es mit einer Einbettungsrichtlinie zu tun, nicht mit einem Ausfall.

X-Frame-Options und CSP-Header einer Seite ansehen

So funktioniert X-Frame-Options

X-Frame-Options ist ein HTTP-Antwort-Header, erstmals beschrieben in RFC 7034, einem informativen RFC, den inzwischen der HTML-Standard ablöst. Er wird seit Internet Explorer 8 von allen Browsern unterstützt. Der Server hängt ihn an eine Seite an; der Browser liest ihn vor dem Rendern und entscheidet, ob die Seite in einem <frame>, <iframe>, <embed> oder <object> auf einer anderen Seite erscheinen darf.

Es gibt zwei Werte, die noch relevant sind, und einen, der es nicht mehr ist:

WertWer die Seite einbetten darfTypischer Einsatz
DENYNiemand – nicht einmal dieselbe WebsiteLogin-Seiten, Admin-Bereiche, alles mit Sitzung
SAMEORIGINNur Seiten mit exakt demselben Origin (Schema + Host + Port)Sinnvoller Standard für die meisten Websites; erlaubt das Einbetten eigener Seiten
ALLOW-FROM https://a.comVeraltet – von allen modernen Browsern ignoriertNicht verwenden; siehe unten

Der Header gilt pro Antwort, nicht pro Website. Das ist das Detail, das die meisten Anleitungen auslassen und das die Lösung in diesem Artikel erst möglich macht: Ein Server kann auf 99 % seiner Seiten SAMEORIGIN senden und auf dem einen Pfad, der eingebettet werden soll, eine andere Richtlinie.

DENY oder SAMEORIGIN: Was sollten Sie senden?

Senden Sie SAMEORIGIN, wenn nichts dagegen spricht. Es blockiert jeden Drittanbieter-Frame, lässt Ihrer eigenen Website aber das Einbetten eigener Seiten – Hilfe-Widgets, Vorschauen, Dashboards, die andere interne Seiten laden.

Senden Sie DENY auf Seiten, bei denen Einbettung keinen legitimen Zweck hat und der Schaden groß wäre: Anmeldeformulare, Zahlungsseiten, Ein-Klick-Aktionen wie „Konto löschen“. DENY deckt auch einen subtilen Fall ab, in dem ein Angreifer einen Frame in eine Ihrer eigenen Seiten einschleust – bei SAMEORIGIN wäre dieser eingeschleuste Frame weiterhin erlaubt.

Wofür Sie sich auch entscheiden: Setzen Sie den Header einmal auf Webserver- oder CDN-Ebene, damit er jede Antwort abdeckt, auch Fehlerseiten und statische Dateien. Header, die im Anwendungscode gesetzt werden, übersehen gern die 404-Seite und die Wartungsseite. Setzen Sie sie dort, wo alle Antworten durchlaufen.

ALLOW-FROM ist tot – nicht verwenden

Ältere Artikel empfehlen immer noch X-Frame-Options: ALLOW-FROM https://partner.com, um eine einzelne einbettende Website zuzulassen. In Chrome und Safari hat das nie funktioniert, und Firefox hat es in Version 70 (Oktober 2019) entfernt. Schlimmer noch: Ein moderner Browser, der ALLOW-FROM sieht, behandelt den ganzen Header als ungültig und ignoriert ihn vollständig, sodass die Seite von jedem eingebettet werden kann – das Gegenteil des Gewollten.

Wenn Sie bestimmte Websites zulassen müssen, lautet die Antwort CSP frame-ancestors, das als Nächstes folgt. X-Frame-Options kann nur „niemand“ oder „nur ich“ ausdrücken.

frame-ancestors: Die CSP-Direktive, die ihn ersetzt

Content Security Policy Level 2 führte frame-ancestors ein, eine Direktive, die alles kann, was X-Frame-Options kann, und zusätzlich das, was Letzterer nicht kann: eine echte Positivliste. Sie steckt im Standard-Header Content-Security-Policy und akzeptiert eine oder mehrere Quellen:

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 *

Drei Details sollten Sie vor der Umstellung kennen:

  • Sie prüft jeden Vorfahren, nicht nur das übergeordnete Element. Bettet Seite A Seite B ein und B wiederum Ihre Seite, müssen sowohl A als auch B erlaubt sein (CSP). Der HTML-Standard wendet inzwischen auch X-Frame-Options auf jeden Vorfahren an (WHATWG), ältere Browser prüften aber nur das übergeordnete Element oder die oberste Seite.
  • Sie funktioniert nur als HTTP-Header. frame-ancestors wird ausdrücklich ignoriert, wenn CSP über ein <meta http-equiv>-Tag geliefert wird – der Browser muss die Richtlinie kennen, bevor er entscheidet, ob er das Dokument überhaupt rendert. Dasselbe gilt für X-Frame-Options. Keiner von beiden lässt sich aus HTML setzen.
  • Platzhalter gelten pro Host, nicht global. https://*.example.com passt auf jede Subdomain einer Website; ein einzelnes * passt auf jeden Origin im Internet. Für ein Rechner-Widget in Ordnung, für alles mit Sitzung falsch.

Was passiert, wenn beide Header gesetzt sind

Die meisten Websites senden während einer Migration beide, und die Rangfolge ist festgelegt: Ist frame-ancestors vorhanden, setzt der Browser es durch und ignoriert X-Frame-Options. Die CSP-Level-2-Spezifikation sagt das ausdrücklich, und Chrome, Firefox, Safari und Edge halten sich daran.

Damit ist der sichere Migrationsweg einfach. Behalten Sie X-Frame-Options: SAMEORIGIN für die wenigen uralten Clients, die älter als CSP 2 sind, fügen Sie Content-Security-Policy: frame-ancestors 'self' hinzu, und jeder moderne Browser nutzt die CSP-Regel. Probleme entstehen nur, wenn beide Header Unterschiedliches sagen – etwa X-Frame-Options: DENY neben frame-ancestors *: Dann erlauben moderne Browser das Einbetten, und nur sehr alte blockieren. Halten Sie beide konsistent, gibt es nichts zu debuggen.

Schritt 1: Den blockierenden Header finden

Bevor Sie etwas ändern, klären Sie, welche Richtlinie greift. Den Header-Namen hat die Browser-Konsole bereits genannt; curl zeigt Ihnen den genauen Wert, den der Server sendet. Das Beispiel nutzt die Website aus dem Praxisbeispiel weiter unten – ihre Hauptseiten sind bewusst gesperrt:

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

# Output:
# x-frame-options: SAMEORIGIN

Eines von drei Ergebnissen kommt zurück:

  • x-frame-options: SAMEORIGIN oder DENY – die klassische Einbettungsrichtlinie. Nur eine Änderung auf jenem Server kann sie aufheben.
  • content-security-policy: … frame-ancestors … – eine CSP-Richtlinie. Lesen Sie die Quellenliste; steht Ihr Origin nicht darin, sind Sie blockiert. Die Direktive steckt oft in einem langen CSP-Header neben script-src und Co., lesen Sie also den ganzen Wert.
  • Keiner der beiden Header: Die eingebettete Website erlaubt den Frame, und „hat die Verbindung abgelehnt“ hat eine andere Ursache: eine Weiterleitung auf eine Seite, die gesperrt ist (oft eine Anmeldeseite; folgen Sie ihr mit curl -sIL), oder ein Cross-Origin-Embedder-Policy: require-corp-Header auf Ihrer eigenen Seite, der jeden Frame blockiert, der nicht zustimmt, und dieselbe graue Box zeigt.

Schritt 2: Entscheiden, wer die Seite einbetten darf

Alles Weitere hängt an einer Frage: Kontrollieren Sie die eingebettete Website?

Wenn nicht, hören Sie hier auf. Es gibt keinen clientseitigen Workaround – kein sandbox-Attribut, keine andere src, kein Browser-Flag, das Ihre Besucher hätten. Der Website-Betreiber hat entschieden, dass seine Seite nicht eingebettet werden soll, und der Browser setzt diese Entscheidung in seinem Namen durch. Ihre Optionen: stattdessen auf die Seite verlinken, den Betreiber fragen, ob er einen Embed-Endpunkt anbietet, oder ein offizielles Widget nutzen, falls es eines gibt. Viele Dienste, die ihre Hauptseite sperren, bieten eines an; das Beispiel im nächsten Abschnitt zeigt, wie das aussieht.

Wenn Sie sie kontrollieren, widerstehen Sie der Versuchung, den Header website-weit zu entfernen. Das öffnet Clickjacking auf jeder Seite wieder – auch auf denen mit Sitzungen und Formularen –, nur um eine Einbettung zu reparieren. Legen Sie stattdessen fest, welche Pfade eingebettet werden sollen und von wem:

SituationHeader für diesen Pfad
Internes Tool, eingebettet in Ihr eigenes Dashboardframe-ancestors 'self' (plus X-Frame-Options: SAMEORIGIN)
Widget, eingebettet von einigen bekannten Partnernframe-ancestors 'self' https://partner-a.com https://partner-b.com
Öffentliches einbettbares Widget (Rechner, Karte, Player)frame-ancestors * nur auf dem Embed-Pfad
Alles andereframe-ancestors 'self' plus X-Frame-Options: SAMEORIGIN

Das richtige Muster: Website sperren, einen Embed-Pfad öffnen

Das sauberste Praxisbeispiel für dieses Muster, das mir begegnet ist, ist EMICalcs, eine kostenlose Sammlung von 45 indischen Finanzrechnern – Kredit-EMI, SIP, Einkommensteuer, GST und so weiter –, die andere Websites einbetten dürfen. Die Hauptseite ist gesperrt; ein eigener /embed/-Pfad ist offen. Vergleichen Sie die Header beider:

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 *

Beachten Sie, was die Embed-Antwort nicht enthält: Auf /embed/ gibt es überhaupt keinen X-Frame-Options-Header. Das ist Absicht. Weil die CSP-Direktive Vorrang hat, wäre ein stehengelassenes SAMEORIGIN in modernen Browsern harmlos – es würde aber den nächsten Entwickler verwirren, der die Header liest, und würde die wenigen alten Clients weiter blockieren, die nur X-Frame-Options verstehen. Der Embed-Pfad sendet eine Richtlinie, und die sagt genau eine Sache.

Alles andere auf der Website behält SAMEORIGIN, sodass Startseite, Artikelseiten und die vollständigen Rechnerseiten vor Clickjacking geschützt bleiben. Die Embed-Versionen sind abgespeckte Dokumente ohne Navigation und ohne etwas, das sich zu kapern lohnt – deshalb ist es ein vertretbarer Kompromiss, sie für * zu öffnen.

Ihr Embed-Leitfaden ist als Vorlage lesenswert, wenn Sie ein eigenes Widget veröffentlichen: eine stabile URL pro Rechner, eine feste Höhe, die für die meisten passt, loading="lazy" im Snippet und das Versprechen, dass eingestellte Embed-URLs weiterleiten statt 404 zu liefern – denn jede Website, die Sie einbettet, vertraut darauf, dass Ihre URL weiter funktioniert.

Nginx (und die add_header-Falle)

Hier dasselbe Muster an den drei Stellen, an denen die meisten Websites Header setzen. Jeweils sperrt eine website-weite Regel alles, und eine engere Regel überschreibt sie für den Embed-Pfad. Zuerst Nginx, weil es eine Falle hat:

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;
}

Der Kommentar ist keine optionale Lektüre. add_header wird nicht über Ebenen hinweg zusammengeführt: Sobald ein location-Block irgendein add_header deklariert, erbt er kein einziges add_header mehr aus dem server-Block. Teams verlieren so regelmäßig HSTS oder nosniff auf dem Embed-Pfad und merken es erst Monate später bei einem Sicherheitsscan. Deklarieren Sie neu, was Sie brauchen, und lassen Sie X-Frame-Options im Embed-Block weg, damit der Pfad eine klare Richtlinie sendet. Seit nginx 1.29.3 kann add_header_inherit merge die Vererbung wieder einschalten (nginx), nutzen Sie es aber nicht im Embed-Block: Es würde das website-weite X-Frame-Options und frame-ancestors 'self' auf diesen Pfad zurückbringen, und bei zwei CSP-Headern setzt der Browser beide durch, sodass der Frame blockiert bleibt.

Apache

Die Header-Direktive von Apache wird über Bereiche hinweg zusammengeführt, sodass Sie den Standard einmal setzen und auf dem Embed-Pfad nur die beiden geänderten Header anfassen:

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 und Express

In Next.js werden Header in next.config.js deklariert. Passen zwei Regeln auf denselben Pfad und setzen denselben Header, gewinnt die spätere – ein Header, den nur die frühere Regel setzt, gilt aber trotzdem. Damit X-Frame-Options dem Embed-Pfad ganz fernbleibt, nehmen Sie ihn per negativem Lookahead aus der website-weiten Regel heraus:

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 *' },
        ],
      },
    ]
  },
}

In Express sendet die verbreitete Middleware helmet standardmäßig bereits X-Frame-Options: SAMEORIGIN und eine CSP mit frame-ancestors 'self'. Binden Sie sie global ein, rufen Sie dann im Embed-Router res.removeHeader('X-Frame-Options') auf und setzen Sie Content-Security-Policy vor dem Rendern auf frame-ancestors *. Die Reihenfolge zählt: Ihre Überschreibung muss nach helmet laufen, sonst überschreibt helmet sie.

Ein Drittanbieter-Widget sicher einbetten

Nun die andere Seite des Zauns: Sie sind die einbettende Website, der Anbieter hat einen offenen Embed-Pfad, und Sie möchten, dass sich der Frame ordentlich verhält. Ein gut gemachtes Widget-Snippet sieht so aus; es ist das, das EMICalcs auf jeder Rechnerseite veröffentlicht:

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>

Jedes Attribut hat eine Aufgabe:

  • title – benennt den Frame für Screenreader. Ohne es sagt die Assistenztechnik nur „Frame“, und Barrierefreiheits-Audits lassen die Seite durchfallen.
  • width="100%" mit max-width in style – füllt schmale Spalten auf dem Handy, ohne auf dem Desktop breite zu sprengen.
  • Eine feste height – die einbettende Seite kann die Inhaltshöhe eines seitenübergreifenden Frames nicht lesen, ein fest eingetragener Wert ist also der einzige Weg, Layoutverschiebungen beim Laden zu vermeiden. Setzen Sie ihn einmal pro Widget.
  • loading="lazy" – verschiebt die Anfrage, bis der Frame in die Nähe des Viewports scrollt, sodass ein Widget am Ende eines langen Artikels beim ersten Laden nichts kostet.
  • border:0; border-radius; overflow:hidden – entfernt den Standardrahmen und rundet die Ecken, damit das Widget zu Ihrer Seite passt.

Die Quellenangabe steht bewusst außerhalb des iframes. Alles im Frame gehört zum eingebetteten Dokument – seine Links sind die Links des Anbieters auf der URL des Anbieters –, ein Link im Frame ist für Ihre Leser oder einen Suchmaschinen-Crawler also nicht Teil Ihrer Seite. Möchten Sie die Quelle nennen, oder verlangt der Anbieter das, setzen Sie wie oben einen schlichten Absatz neben den Frame in Ihr eigenes HTML.

sandbox: Was Sie für ein Rechner-Widget erlauben sollten

Das sandbox-Attribut ist der eigene Schutz des Einbettenden. Fügen Sie es ohne Wert hinzu, bekommt die eingebettete Seite nichts: keine Skripte, keine Formulare, keine Pop-ups, keine Navigation Ihres Fensters und einen undurchsichtigen Origin, der ihre eigenen Cookies und ihren Speicher deaktiviert. Dann erlauben Sie nur wieder, was das Widget braucht:

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 und allow-forms sind das Minimum für alles Interaktive. allow-same-origin lässt die eingebettete Seite ihren eigenen Origin behalten, damit Speicher und Cookies funktionieren – bei einer seitenübergreifenden Einbettung ist das sicher, denn „ihr Origin“ ist weiterhin der des Anbieters, nicht Ihrer. allow-popups braucht es nur, wenn das Widget Links in einem neuen Tab öffnet, wie es der Quellenlink in der EMICalcs-Einbettung tut.

Was Sie nicht tun sollten: allow-scripts mit allow-same-origin kombinieren bei einem Frame, der auf Ihren eigenen Origin zeigt. Das eingebettete Skript kann dann sein eigenes sandbox-Attribut entfernen, und Sie haben nichts abgeschottet.

Warum es auf der einbettenden Seite keine Lösung gibt

Die Suche nach „iframe Verbindung abgelehnt“ liefert drei beliebte Workarounds. Alle sind schlecht, und es hilft zu wissen, warum genau.

  • Browser-Erweiterungen, die X-Frame-Options entfernen – sie wirken nur in Ihrem eigenen Browser. Jeder Besucher Ihrer Website sieht weiterhin die graue Box, und Sie haben währenddessen den Clickjacking-Schutz auf jeder Website abgeschaltet, die Sie besuchen.
  • Die Seite über Ihren eigenen Server proxien – Sie holen das Fremd-HTML serverseitig und liefern es von Ihrem Origin aus, sodass der Header den Browser nie erreicht. Das zerstört relative Links, Cookies, Logins und alles Skriptgesteuerte, macht Sie für fremde Inhalte verantwortlich und verstößt meist gegen die Bedingungen des Anbieters. Websites, die Sie dabei erwischen, sperren die IP Ihres Servers.
  • Screenshot- oder „Web-to-Image“-Dienste – Sie erhalten ein statisches Bild, keine funktionierende Seite. Für ein Vorschaubild in Ordnung, für einen Rechner nutzlos.

Der Header ist eine Erklärung des Website-Betreibers darüber, was mit seiner Seite geschehen darf, und der Browser setzt sie durch. Die einzigen legitimen Wege sind die beiden bereits behandelten: Der Betreiber öffnet einen Embed-Pfad, oder Sie verlinken. Anbieter, die eingebettet werden wollen, machen es leicht – die guten veröffentlichen ein Snippet, halten die URL stabil und öffnen nur den Pfad, der sich gefahrlos öffnen lässt.

Header nach jeder Änderung prüfen

Einbettungs-Header werden in einer Konfigurationsdatei gesetzt und dann vergessen, und ein CDN, ein Reverse-Proxy oder ein gut gemeintes Sicherheits-Plugin kann sie jederzeit hinzufügen, entfernen oder duplizieren. Prüfen Sie nach dem Deployment von außerhalb Ihres Netzwerks:

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'

Testen Sie dann so, wie es ein Browser tut: Setzen Sie die Embed-URL in einen <iframe> auf einer Seite, die von einem anderen Origin ausgeliefert wird – eine lokale file://-Seite genügt nicht, da Browser sie besonders behandeln –, und öffnen Sie die Konsole. Lädt alles sauber, erscheint keine Zeile mit Refused to display oder Refused to frame.

Steht die Website hinter Cloudflare oder einem anderen CDN, können eine zwischengespeicherte Kopie oder eine Edge-Regel andere Header tragen als Ihr Origin. Der HTTP-Header-Checker ruft die URL von unserem Server aus ab, außerhalb Ihres Browsers und Netzwerks, und zeigt X-Frame-Options und Content-Security-Policy mit einem Einbettungsurteil (SAMEORIGIN oder DENY, über CSP frame-ancestors oder nicht gesendet): eine schnelle Möglichkeit, eine CDN-Regel aufzuspüren, die stillschweigend SAMEORIGIN wieder auf Ihren Embed-Pfad gelegt hat.

Symptom → Ursache → Lösung

Nutzen Sie die Tabelle, um direkt zur Lösung zu springen, statt die ganze Anleitung erneut zu lesen:

Was Sie sehenWas es bedeutetLösung
Graue Box „hat die Verbindung abgelehnt“, aber die URL lädt im TabX-Frame-Options oder frame-ancestors hat den Frame blockiertNur der Website-Betreiber kann es ändern – seinen Embed-Pfad nutzen oder verlinken
Konsole: Refused to display … 'X-Frame-Options' to 'sameorigin'Klassischer Header; nur Frames desselben Origins erlaubtAuf der eingebetteten Website den Embed-Pfad mit frame-ancestors * oder einer Partnerliste öffnen
Konsole: Refused to frame … violates … frame-ancestorsDie CSP-Positivliste enthält Ihren Origin nichtIhren Origin zu den frame-ancestors-Quellen der eingebetteten Website hinzufügen
Gestern ging es, heute nicht, keine Code-ÄnderungCDN oder Sicherheits-Plugin fügt nun SAMEORIGIN einMit curl prüfen; den Embed-Pfad aus der CDN- oder Plugin-Regel ausnehmen
Ihr eigenes Dashboard kann Ihre eigene Seite nicht einbettenSubdomain- oder Schema-Abweichung (www gegen Apex, http gegen https)frame-ancestors 'self' https://example.com https://*.example.com verwenden (der Platzhalter deckt die nackte Domain nicht ab)
Einbettung funktioniert, aber HSTS oder nosniff fehlen auf diesem PfadDie add_header-Vererbung in Nginx hat sie verworfenAlle Header im location-Block neu deklarieren
ERR_CONNECTION_REFUSED beim direkten Öffnen der URLEin echter Netzwerkfehler, keine EinbettungsrichtlinieSiehe ERR_CONNECTION_REFUSED und den Port-Checker

Schlägt die URL auch im eigenen Tab fehl, ist der Frame eine falsche Fährte. Gehen Sie die Netzwerkschichten der Reihe nach durch – DNS, Port, TLS, Header – mit dem Leitfaden zum Testen öffentlicher Endpunkte, bevor Sie Einbettungs-Header anfassen.

Alle Sicherheits-Header einer URL anzeigen

Prüfen Sie X-Frame-Options, Content-Security-Policy, HSTS und die übrigen Header jeder Seite. Der Abruf erfolgt von unseren Servern, sodass eine Browser-Erweiterung oder ein Proxy in Ihrem Netzwerk das Ergebnis nicht verändert. Kostenlos, ohne Anmeldung.

Quellen

  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

Häufige Fragen

Ist X-Frame-Options veraltet?

Funktional wurde es von der CSP-Direktive frame-ancestors abgelöst, die Browser bevorzugen, sobald beide Header vorliegen. Nutzlos ist es aber nicht: Jeder aktuelle Browser beachtet X-Frame-Options weiterhin, wenn frame-ancestors fehlt, und es schützt die wenigen alten Clients, die älter als CSP Level 2 sind. Praktischer Rat: beide senden und konsistent halten – SAMEORIGIN neben frame-ancestors 'self'.

Was bedeutet X-Frame-Options: DENY?

DENY teilt dem Browser mit, dass die Seite niemals in einem Frame-, iframe-, embed- oder object-Element auf irgendeiner Seite dargestellt werden darf – auch nicht auf Seiten derselben Website. Es ist die strengste Einstellung und die richtige für Login-Formulare, Zahlungsseiten und Admin-Bereiche, bei denen es keinen legitimen Grund zur Einbettung gibt und Clickjacking gravierend wäre.

Was ist der Unterschied zwischen DENY und SAMEORIGIN?

DENY blockiert jede Einbettung. SAMEORIGIN erlaubt sie nur Seiten mit exakt demselben Origin – gleiches Schema, gleicher Host, gleicher Port – und blockiert alle anderen. SAMEORIGIN ist der sinnvolle Standard für die ganze Website, weil es Drittanbieter-Clickjacking stoppt und Ihre Website trotzdem eigene Seiten einbetten kann; DENY ist für die wenigen Seiten, die nie eingebettet werden sollen.

Wie umgehe ich X-Frame-Options, um eine Website einzubetten?

Von der einbettenden Seite aus gar nicht. Der Header wird von der Website gesetzt, die Sie einbetten möchten, und von den Browsern Ihrer Besucher durchgesetzt; kein iframe-Attribut, kein sandbox-Flag und kein clientseitiger Trick ändert das. Erweiterungen, die den Header entfernen, wirken nur in Ihrem eigenen Browser, und die Seite über Ihren Server zu proxien zerstört sie und verstößt meist gegen die Bedingungen des Anbieters. Legitime Wege sind ein offizieller Embed-Endpunkt, falls der Anbieter einen bietet, oder ein Link auf die Seite.

Wie setze ich X-Frame-Options auf DENY?

Fügen Sie ihn als HTTP-Antwort-Header auf Webserver-Ebene hinzu, damit er jede Seite abdeckt, auch Fehlerseiten. In Nginx: add_header X-Frame-Options "DENY" always; in Apache: Header always set X-Frame-Options "DENY". Kombinieren Sie ihn für moderne Browser mit Content-Security-Policy: frame-ancestors 'none'. Per Meta-Tag lässt er sich nicht setzen – nur ein HTTP-Header funktioniert.

Warum meldet mein iframe „hat die Verbindung abgelehnt“, obwohl die Website im neuen Tab funktioniert?

Weil mit der Verbindung nichts falsch ist. Die Website lieferte die Seite normal aus, aber mit einem X-Frame-Options- oder frame-ancestors-Header, der das Rendern in einer anderen Seite verbietet. Chrome zeigt dafür dieselbe graue Box wie bei einem echten Netzwerkfehler, was verwirrend ist; die Konsolenmeldung „Refused to display … in a frame“ verrät die wahre Ursache.

Kann ich X-Frame-Options oder frame-ancestors in einem Meta-Tag setzen?

Nein. Beide müssen als HTTP-Antwort-Header geliefert werden. Der Browser muss die Einbettungsrichtlinie kennen, bevor er entscheidet, ob er das Dokument überhaupt rendert, und ein Meta-Tag kommt zu spät. frame-ancestors wird in einer Meta-http-equiv-CSP ausdrücklich ignoriert, und X-Frame-Options in einem Meta-Tag ignoriert jeder Browser.

Macht frame-ancestors * meine Website unsicher?

Nur für die Antworten, die es senden. Der Header wird pro Dokument ausgewertet; sendet ein eigener /embed/-Pfad frame-ancestors *, bleibt der Rest der Website durch SAMEORIGIN oder frame-ancestors 'self' voll geschützt. Das Risiko beschränkt sich darauf, was ein Angreifer durch Einbetten der Embed-Seite selbst gewinnen könnte – bei einem zustandslosen Widget ohne Sitzungs-Cookie und ohne sensible Aktionen ist das nichts.

Warum funktioniert X-Frame-Options: ALLOW-FROM nicht?

ALLOW-FROM wurde nur vom Internet Explorer, dem ursprünglichen Edge (Versionen 12 bis 18) und von Firefox umgesetzt, das es in Version 70 entfernt hat. Chrome und Safari haben es nie unterstützt. Moderne Browser behandeln einen Header mit ALLOW-FROM als ungültig und ignorieren ihn vollständig, sodass die Seite von jedem eingebettet werden kann. Nutzen Sie die CSP-Direktive frame-ancestors, die eine echte Liste erlaubter Origins unterstützt.

Welcher Header gewinnt, wenn X-Frame-Options und frame-ancestors gesetzt sind?

frame-ancestors. Der HTML-Standard weist Browser an, X-Frame-Options zu ignorieren, sobald eine durchgesetzte CSP frame-ancestors enthält (schon CSP Level 2 empfahl das), und alle aktuellen Browser tun es; eine Report-Only-Richtlinie zählt nicht. Nur Clients, die zu alt für CSP sind, greifen auf X-Frame-Options zurück, weshalb es sich weiterhin lohnt, ihn zu senden – solange beide Header übereinstimmen.

Über den Autor

Shaik Vahid

Gründer von DNS Robot. Vahid hat jahrelang im Webhosting-Support Domains, DNS-Einträge, SSL-Zertifikate und E-Mail-Zustellung für Kunden in Ordnung gebracht. Er entwickelt die Tools von DNS Robot und schreibt diese Anleitungen über die Fehler, die Menschen wirklich sehen.

HTTP-Header-Checker

HTTP-Antwort-Header und Sicherheits-Header-Bewertung analysieren