iframes – der heilige Gral bei verteilten Webanwendungen

Seite 3: iframes – mehr als ein Relikt aus der Vergangenheit?

Inhaltsverzeichnis

Iframes ermöglichen das Einbetten von Inhalten wie einer externen Webanwendung in ein HTML-Dokument. Jeder so eingebundene Kontext wird in ein eigenes HTML DOM (Document Object Model) mit eigener Session-Historie geladen. Die eingebetteten Inhalte laufen vollständig isoliert voneinander, ein Zugriff auf das DOM anderer Elemente ist nicht möglich.

HTML 5 stellt das iframe-Tag zur Verfügung, um Inhalte zu integrieren. Hierbei spezifiziert das src-Attribut die URL der einzubindenden Webseite. Das Styling wie etwa das Ausblenden des Rahmens erfolgt über CSS-Eigenschaften (style="border:none;"). Eine detaillierte Erläuterung der verfügbaren Attribute lässt sich der Mozilla HTML Reference entnehmen. Wie der Inhalt der Website http://example.de mit einer Breite und Höhe von 800x600 Pixeln einbinden lässt, zeigt das folgende Listing:

<iframe src="http://example.de"
id="iframe1"
style="border:none;"
width="800" height="600"
sandbox="allow-scripts">
</iframe>

Ein häufiger Kritikpunkt an iframes ist deren mangelnde Sicherheit. Doch seit Einführung des Sandbox-Modus in HTML 5 lassen sich viele Bedenken entkräften. Das Attribut sandbox aktiviert diverse Sicherheitsrestriktionen für in iframes eingebettete Inhalte. So kann die eingebettete Website beispielsweise keine Skripte mehr ausführen, APIs aufrufen, Formulare abschicken oder Plug-ins durch <embed>, <object> verwenden.

Das Attribut sandbox ermöglicht es hierbei, einzelne Restriktionen freizuschalten. Der Website in Listing 1 ist es beispielsweise erlaubt, Skripte auszuführen. Allerdings ist es nicht empfehlenswert, eine Kombination aus allow-scripts und allow-same-origin zu verwenden. Denn dabei kann es zur Manipulation des HTML DOMs durch eingebettete iframes kommen. Die Web Hypertext Application Technology Working Group (WHATWG) hat dazu eine entsprechende Empfehlung herausgegeben.

Den Einsatz von sandbox als Sicherheitsmaßnahme mit einer möglichst feingranularen Einstellung der Restriktionen empfiehlt auch das Open Web Application Security Project (OWASP). Als zweiter Mechanismus bieten sich die X-Frame-Options im HTTP-Header an, um beispielsweise Clickjacking-Attacken zu verhindern. In den X-Frame-Options lässt sich spezifizieren, welcher fremde Host eine Website einbetten darf. Die Konfiguration muss dabei webserverseitig erfolgen, das Setzen des HTTP-Metadata-Tags (<meta http-equiv="X-Frame-Options" content="deny">) hat keinerlei Effekt.

Die Kommunikation zwischen HTML-Dokument und eingebetteten Inhalten erfolgt über die standardisierte JavaScript-API window.postMessage(). Normalerweise dürfen Skripte verschiedener Websites nur aufeinander zugreifen, wenn sie denselben Ursprung – also Host, Port und Protokoll – haben, auch bekannt als same-origin policy.

Mit window.postMessage() lässt sich ein kontrollierter und sicherer Mechanismus anbieten, um einen ursprungsübergreifenden (cross-origin) Datenaustausch zu ermöglichen. Wie im nachfolgenden Listing zu sehen, ist im ersten Schritt eine Referenz auf das Zielfenster ("iframe1") über die JavaScript-Methode getElementById() zu erstellen. Auf dem zugehörigen contentWindow lässt sich im zweiten Schritt die postMessage()-Methode aufrufen. Die entsprechende Nachricht wird als MessageEvent an das Zielfenster geschickt.

postMessage() erwartet zwei Argumente: den Nachrichteninhalt "message", der durch die Methode automatisch serialisiert wird, und die Zieladresse "URL". Wenn diese nicht mit der Adresse des Zielfensters übereinstimmt, wird die Nachricht nicht ausgeliefert.

const iframe = (<HTMLIFrameElement>document.getElementById("iframe1"));
iframe.contentWindow. postMessage( {"message": "Hello World"},
"http://example.de");

Das Lauschen auf MessageEvents innerhalb der eingebetteten Komponente erfolgt durch Implementierung des EventListenerObject-Interface – wie das nächste Listing zeigt. Der window.addEventListener('message', listener) fügt dem HTML-Dokument ein MessageEventListener hinzu. Das EventListenerObject-Interface erwartet das Überschreiben der handleEvent()-Methode. Diese wird bei jedem eingehenden MessageEvent aufgerufen.

Der MessageEvent hat drei Attribute: das verschickte und wieder deserialisierte Datenobjekt data sowie Quelladresse origin und Referenz auf das Quelldokument source, von welchem die Nachricht verschickt wurde. Die Referenz auf das Quelldokument lässt sich verwenden, um eine wechselseitige Kommunikation aufzubauen. Beim Nachrichtenempfang sind eine regelmäßige Identitätsprüfung des Senders und das Ablehnen der Nachrichten von Unbekannten empfehlenswert. Darüber hinaus ist auch die Syntax der empfangenen Nachricht zu validieren, um Cross-Site-Scripting-Angriffen vorzubeugen.

export class Component implements EventListenerObject {
constructor() {
window.addEventListener('message', this);
}
public handleEvent(event) {
if (isTrustedURL(event.origin) ) {
console.log(message received:' + event.data.message);
}
}
}