message von iframe wird nicht von parent empfangen
- event
- javascript
Moin,
seit drei Stunden will es mir nicht gelingen, was mit einem anderen Dokument (https://shanty-fsd.de/mitglieder/verzeichnis.php) funktioniert:
Das eingebettete iframe soll seine Höhe an parent melden, damit dort die Höhe des iframes angepasst wird.
Sender (iframe):
window.parent.postMessage( window.outerHeight );
Empfänger (parent):
window.addEventListener("message", function(messageEvent) {
console.log( "login.php: empfange message=[" +messageEvent.data + "]" );
if (messageEvent.origin == "https://shantyfreun.de") {
document.getElementById("shantyfreunde").style.height = messageEvent.data +"px";
}
});
Die console-Meldung wird nicht angezeigt. Auch keine Fehlermeldung
Gruß, Linuchs
Lieber Linuchs,
in solchen Fällen unbedingt die Fehlermeldungen in der Konsole ausführlich studieren! Wenn Framegrenzen Funktionalitäten blockieren, dann hat das mit an Sicherheit grenzender Wahrscheinlichkeit mit unterschiedlichen Domains zu tun. Und siehe da: Auf Deiner problematischen Seite erhalte ich diese Meldung in der Konsole
Für "https://shantyfreun.de/index_test.php" wurde partitionierter Cookie- oder Speicherzugriff verwendet, da es im Kontext eines Drittanbieters geladen wurde und dynamische Zustandspartitionierung aktiv ist.
In der Adresszeile des Browsers wird shanty-fsd.de
als Domain angezeigt. Die URL des Dokuments im iframe
wird dagegen von der Domain shantyfreun.de
geladen. Also bestätigt sich meine obige Annahme: Domain-Wirrwarr.
Warum musst Du hier unterschiedliche Domains vermischen? Das ist natürlich nicht unmöglich, erfordert aber passende Header-Angaben zum Cross-Origin Resource Sharing (CORS im Wiki).
Liebe Grüße
Felix Riesterer
Lieber Felix,
Warum musst Du hier unterschiedliche Domains vermischen?
Das klappt doch mit remso im iframe auch, wieso jetzt nicht?
Die Haupt-Domain wird von einer Web-Designerin (keine Ahnung von PHP und SQL) per Wordpress bei Strato neu gestaltet, der Mitgliederbereich soll aus der alten Version ausgekoppelt und weitergenutzt werden.
Bin dabei den Kern freizulegen und dabei auf die neueste PHP- und SQL-Version umzustellen.
Wordpress muss nur eine Seite zur Verfügung stellen, darin laufen dann die Mitglieder-Programme, darunter GEMA-Meldungen der Chöre.
Gruß, Linuchs
Da ich das CORS Konzept nicht verstanden habe, weiß ich nicht, wohin mit den Zeilen
Access-Control-Allow-Origin: https://shantyfreun.de
</head>
und
<script src = "https://shantyfreun.de" crossorigin="anonymus">
</head>
Nun wird der iframe Inhalt gar nicht mehr geladen.
Nochmal die Frage:
Warum kann die Seite https://shanty-fsd.de/ einen iframe mit src="https://remso.eu/?VIP=1010&LO=positionen&posi=19" zeigen?
Hallo Linuchs,
<script src = "https://shantyfreun.de" crossorigin="anonymus"> </head>
Nun wird der iframe Inhalt gar nicht mehr geladen.
<script src="https://shantyfreun.de" crossorigin="anonymous">
</script>
Bis bald!
Jonathan
@@Jonathan Harker
crossorigin="anonymus"
crossorigin="anonymous"
I’m not amoused.
🖖 Live long and prosper
Hallo Linuchs,
das crossorigin-Attribut VERSCHÄRFT die Situation und macht sie nicht besser. Egal ob mit "anonymous" oder mit "use-credentials". Ungültige Werte wie "anonymus" werden übrigens als "anonymous" interpretiert.
Wenn Du crossorigin nicht angibst, wird das Script ohne Verwendung von CORS geladen, d.h. dann kannst Du Scripte von beliebigen Stellen inkludieren. Aber wenn Du ihn angibst, dann wird CORS beachtet und Du bekommst das Script nur dann, wenn die CORS-Header es zulassen.
(crossorigin="anonymus") - Nun wird der iframe Inhalt gar nicht mehr geladen.
Was merkwürdig ist, weil der iframe-Inhalt nicht von der Ladbarkeit des Scripts abhängen sollte. Oder doch? Wird der Inhalt komplett vom Script generiert?
weiß ich nicht, wohin mit den Zeilen
Access-Control-Allow-Origin: https://shantyfreun.de
Das ist ein Response-Header. Den muss der Server von shanty-fsd.de setzen, damit die Seite, die von dort geladen wird, Daten von shantyfreun.de lesen darf. Das betrifft vor allem Ajax-Zugriffe (XMLHttpRequest und fetch). Scripte betrifft es nur, wenn das crossorigin-Attribut gesetzt ist. Setzen kannst Du den Header aus PHP heraus oder in der .htaccess Datei.
Disclaimer: Wenn Du den iframe mit dem sandbox-Attribut lädst, sieht die Sache nochmal anders aus, dieses Attribut aktiviert einen Paranoia-Modus, in dem alles verboten ist, was Du nicht ausdrücklich erlaubst.
Warum kann die Seite https://shanty-fsd.de/ einen iframe mit src="https://remso.eu/?VIP=1010&LO=positionen&posi=19" zeigen?
Weil das Zeigen kein Problem ist. Und Du dort kein postMessage machst.
Rolf
Aloha ;)
seit drei Stunden will es mir nicht gelingen, was mit einem anderen Dokument (https://shanty-fsd.de/mitglieder/verzeichnis.php) funktioniert
Empfänger (parent):
window.addEventListener("message", function(messageEvent) { console.log( "login.php: empfange message=[" +messageEvent.data + "]" ); if (messageEvent.origin == "https://shantyfreun.de") {
Ein Schuss ins Blaue, weil mir die unterschiedlichen Domains ins Auge stechen:
CORS?
Sind iframe und parent auf dem selben Origin, und falls nicht, was sagen die CORS-Header?
Grüße,
RIDER
Moin,
habe gewartet, ob noch eine brauchbare Hilfe kommt.
Bitte darum, die nötigen Code-Schnipsel für das Parent-Dokument (Domain A) und das Dokument (Domain B) im iframe aufzuschreiben oder besser noch auf ein funktionierendes Beispiel zu verlinken.
Bin aus diversen Dokumentationen nicht schlau geworden.
Auch CORS im Wiki ist leider keine Hilfe zur praktischen Umsetzung.
Habe vor 10, 12 Jahren eine eigene Lösung gebastelt:
Dokument (B) im iframe meldet seine Höhe per Ajax an seine eigene Domain, PHP erstellt daraus ein Image mit dieser Höhe.
Parent (A) wartet ein paar Sekundenbruchteile nach Fertigstellung der Seite und ruft dann das Bild von der anderen Domain ab, das ist zulässig (oder war zulässig). Die Höhe des Bildes plus kleine Zugabe sollte die Höhe des iframe sein.
Kompliziert und nicht zuverlässig. Wenn Domain (B) Zeit zum Antworten braucht, wird das vorige Bild abgerufen.
Hallo Linuchs,
ich war am verlängerten Wochenende weg vom PC und konnte das Thema deshalb nicht bearbeiten.
Habe vor 10, 12 Jahren eine eigene Lösung gebastelt
Was damals vermutlich wegen der IE-Quirks nötig war.
Das klappt doch mit remso im iframe auch, wieso jetzt nicht?
Das klappt mit shanty-fsd.de im Parent und remso.eu im iframe? Inwiefern? Dort finde ich auf den ersten Blick keinen postMessage vom iframe zum Frame-Host und im Frame-Host auch keine Registrierung auf das message-Event.
Ich finde im Netz allerdings auch die Hypothese (von 2013), dass ein unterschiedlicher Origin bei gleichem Host (also gleicher Empfänger-IP) nicht beachtet würde. Was damals möglicherweise ein Bug im IE war, mein eigener Versuch mit Edge bestätigt das nicht.
Die console-Meldung wird nicht angezeigt. Auch keine Fehlermeldung
Bei mir kommt aber eine Fehlermeldung:
Hostseite: http://127.0.0.1:9000/parent.html
Frameseite: http://127.0.0.1:9001/iframecontent.html
Server: 2 Instanzen von PHP -S
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('http://127.0.0.1:9001') does not match the recipient window's origin ('http://127.0.0.1:9000').
Response-Header vom Parent:
Host: 127.0.0.1:9000
Date: Tue, 24 Jun 2025 15:15:21 GMT
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 687
Response-Header vom iframe:
Host: 127.0.0.1:9001
Date: Tue, 24 Jun 2025 15:15:21 GMT
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 150
Die Lösung ist keine Sache von CORS-Headern, wie behauptet wurde, sondern erfordert eine korrekte Parametrierung der postMessage Methode.
Im Selfwiki und auch bei MDN steht, was zu tun ist. Ich habe das im Wiki-Artikel nochmal betont: Bei einem Cross-Origin Versand muss man explizit angeben, an welchen Origin versendet werden darf. Oder man gibt an, dass einem der Empfänger-Origin egal ist (was aber nicht gut ist, denn man möchte ja nicht unbedingt fremd-geframed werden).
Der targetOrigin ist per Default der Origin der Absende-Seite. Bei mir war das http://127.0.0.1:9001, deshalb steht das als "target origin provided" in der Fehlermeldung.
Lösung für Dich sollte sein:
// In https://shantyfreun.de
window.parent.postMessage( window.outerHeight, "https://shanty-fsd.de");
Rolf
Hallo Rolf,
danke dir. Ich habe soo viel rumprobiert, mal Fehlermeldungen bekommen, mal nicht. Das man beim Senden zusätzlich zu parent
noch eine Domain angeben muss, hat gefehlt.
Aber dies war falsch:
window.parent.postMessage( window.outerHeight, "https://shanty-fsd.de");
Window ist immer gleich groß, richtig ist ganz am Ende des iframe-Dokuments:
window.parent.postMessage( document.querySelectorAll("body")[0].offsetHeight +20, "https://shanty-fsd.de");
Und im empfangenden parent-Dokument:
window.addEventListener("message", function(messageEvent) {
document.getElementById("shantyfreunde").style.height = messageEvent.data +"px";
});
Die messageEvent.origin abzufragen, ist überflüssig.
if (messageEvent.origin == "https://shantyfreun.de") {
document.getElementById("shantyfreunde").style.height = messageEvent.data +"px";
}
geprüft wird scheinbar, denn eine falsche Domain blockiert die Ausführung.
Gruß, Linuchs
Hallo Linuchs,
nein, lass die Abfrage auf message.origin nicht weg. Wenn man schon Origin-übergreifend kommuniziert, sollten beide Seiten sicherstellen, dass der richtige Kommunikationspartner da ist.
Deshalb solltest Du auch bei beiden Sites eine Content-Security-Policy setzen. Bei shanty-sfd sollte frame-src gesetzt werden, hier müssen alle Origins gelistet werden, aus denen Frames eingebunden werden. Und bei shantyfreun.de sollte frame-ancestors gesetzt werden, womit Du festlegst, welche Origins die Seite per iframe einbinden können.
Ich weiß nicht, wie viele Seiten remso einbinden. Wenn es überschaubar ist, solltest Du auch dafür frame-ancestors setzen.
Rolf
Hallo Linuchs,
by the way…
document.querySelectorAll("body")[0].offsetHeight
also, es ist nicht falsch. Aber SOWAS von hinten durch die Brust ins Auge!
Besser:
document.body.offsetHeight
Rolf
@@Rolf B
document.querySelectorAll("body")[0].offsetHeight
also, es ist nicht falsch. Aber SOWAS von hinten durch die Brust ins Auge!
Und zwar SOWAS von, dass ich es ‚falsch‘ nennen würde.
Es verstößt gegen das KISS-Prinzip.
Wenn es document.body
nicht gäbe, sollte man document.querySelector("body")
verwenden.
Gibt es aber. Also:
Besser:
A/k/a ‚richtig‘
document.body.offsetHeight
🖖 Live long and prosper
Hallo Gunnar,
Es verstößt gegen das KISS-Prinzip.
Aber nur halb. Es ist nicht Simple.
Rolf
Zum Gruße,
du solltest deine Architektur unbedingt noch einmal überdenken. Cross browsing context Kommunikation sollte nur bei gleicher Origin genutzt werden. Alles andere ist sicherheitstechnisch höchst bedenklich. Und wenn du es in gleicher Origin hast, dann gibst es mit BroadcastChannel auch genau das richtige Web-Werkzeug, wie man einfach kommuniziert.
Gruß Michael
Hallo Michael,
nein, BroadcastChannel ist hier ungeeignet. Linuchs hat den Grund für die CrossOrigin-Kommunikation genannt, und BroadcastChannel funktioniert nur bei gleichem Origin. Daher ein Minus, nimm's nicht persönlich.
Die Sicherheitsbedenken sind irrelevant, da beide Origins von Linuchs gehostet werden. Ich finde es auch übertrieben, ein crossOrigin-postMessage grundsätzlich zu verdammen. Ja, man muss wissen, was man tut. Aber ein grundsätzliches Nein wäre so, als wolltest Du Linuchs das Autofahren verbieten, nur weil er möglicherweise jemanden überfahren könnte.
BroadcastChannel ist nützlich, wenn man rein per Name kommunizieren will oder wenn man mehr als zwei Teilnehmer im Funkverkehr hat und keinen Messagedispatcher bauen will.
Rolf
Hallo Rolf,
da würde ich dir widersprechen. Nur weil es technisch geht, sollte man es auch nicht machen. Passiv client-seitig an einer "fremden" Quelle lauschen ist überhaupt keine gute Idee, egal mit welcher Begründung. Das ist eine klassische red flag.
Und zudem kauf man sich noch die CSP-Probleme ein, wenn man den Server nicht selbst kontrolliert und einstellen kann. Das csp-Attribut ist ja nicht auf absehbare Zeit in gängigen Browsern verfügbar. Deshalb bleibe ich dabei, cross-browsing context Kommunikation sollte man nur bei gleicher Origin machen und dazu auch das geeignete Werkzeug nutzen.
Gruss Michael
Hallo Michael,
du betreibst Prinzipienreiterei. Stumpf die Kommunikation zwischen zwei Systemen zu verbieten, ohne die zu lösende Aufgabe zu betrachten, ist nicht der richtige Weg. Man muss
Linuchs hat die Aufgabe, zwei Systeme zu integrieren. Dafür muss zwischen den Systemen kommuniziert werden. Und das ist nicht böse. Das ist Systemintegration. Genau dafür ist der targetOrigin-Parameter von postMessage da. Genau dafür kann man im Content-Security-Policy Header frame-src und frame-ancestors setzen, wenn man möchte. Dafür ist die Abfrage auf die Herkunft-Origin da, sofern es denn möglich wäre, die iframe-Quelle zu manipulieren.
Man könnte auf dem shanty-sfd.de Server Server einen Proxy bereitstellen, der serverseitig die Inhalte von shantyfreun.de holt und sie damit unter scheinbar gleichem Origin bereitstellt.
Man könnte den Teil von shantyfreun.de, der für shanty-sfd.de gebraucht wird, auf den Strato-Server kopieren und die Kopie nutzen.
Das ist aufwändig und kostet Ressourcen. Wofür? Um ein Prinzip zu wahren? Wie schon gesagt: die beteiligten Systeme sind nicht beliebig. Sie sind bekannt, sie sollen kooperieren.
Machen wir noch das Risk-Assessment.
Wenn shantyfreun.de von einer falschen Seite eingeframed wird, dann sorgt der targetOrigin-Parameter dafür, dass sie keine Nachrichten bekommt. Das könnte man irgendwie manipulieren (per DevTools oder auf der Leitung) - und was kommt dabei heraus? Die fremde Seite erfährt, wie hoch die Shantyfreun.de Seite ist.
Wenn shanty-sfd.de so manipuliert wird, dass es eine falsche Seite einframed, dann hat diese falsche Seite die Möglichkeit, den targetOrigin nach Bedarf zu setzen. Für diesen Fall ist eigentlich die Abfrage auf message.origin da, die sollte nicht wegbleiben. Alternativ geht auch die frame-src CSP.
Und was kann die falsche eingeframte-Seite damit anrichten? Sie kann ihre Höhe mitteilen. Wenn es aber jemand schafft, den iframe src so zu manipulieren, dass ALLE Besucher von shanty-sfd.de den falschen iframe-Inhalt bekommen und nicht nur der, der gerade auf seinem Browser das src Attribut gefaked hat, dann haben die Shanty-Freunde ein ganz anderes Problem.
Meine Risiko-Beurteilung lautet: gut tragbar.
Wie wäre deine persönlicher Lösungsvorschlag für die Integration der beiden Systeme?
Rolf
Hallo Rolf,
ich teile eben nicht diese Ansicht. Und es ist keine Prinzipienreiterei, wenn man Sicherheit betrachtet. Man kann auch Web-Server und Datenbank-Server auf einer Instanz betreiben, technisch überhaupt kein Problem, und trotzdem sollte man es eben nicht machen.
Und überhaupt sehe ich im vorliegenden Fall gar keine Notwendigkeit, unnötig Sicherheitslücken aufzumachen. Das hier vorliegende Problem kann man einfach lösen, indem der iframe ein load EventListener bekommt und man dann einfach die benötigte Höhe ermittelt und entsprechend setzt.
Gruss
Hallo Michael,
Das hier vorliegende Problem kann man einfach lösen, indem der iframe ein load EventListener bekommt und man dann einfach die benötigte Höhe ermittelt und entsprechend setzt.
Äh, du möchtest vom Host-Dokument auf die contentDocument Eigenschaft des iframe-Objekts zugreifen? Wenn der iframe-Inhalt von einem anderen Origin als das Host-Dokument kommt?
Oder verstand ich Dich miss?
Rolf