Skip to content

HTML5 Security - postMessage() sicher nutzen

Wie bereits erwähnt lehnt sich diese kleine Serie zur Sicherheit von HTML5 an meinen Vortrag auf der WebTech Conference 2012 an. Womit auch schon das aktuelle Thema vorgegeben ist: Die mit HTML5 eingeführte Methode postMessage().

postMessage()

Die Methode postMessage() dient dem Austausch von Daten zwischen Skripten aus verschiedenen Origins. postMessage() wird mit den zu übertragenden Daten und der Origin des Ziels aufgerufen und überträgt die Daten zwischen den betroffenen Fenstern beziehungsweise Frames, sofern die Origin des Ziels mit der angegebenen Origin übereinstimmt:

zielfenster.postMessage("Nachricht", "Ziel-Origin");

Das ist zum Beispiel sehr nützlich, wenn eine Seite mit eingebundenen Widgets kommunizieren soll oder muss. Bisher hatten Sie beim Einbinden von Widgets nur die Wahl zwischen zwei Möglichkeiten mit mehr oder weniger großen Nachteilen: Entweder Sie sperrten das Widget in einen iframe und konnten von Ihrer eigenen Seite aus nur schwer damit interagieren, oder Sie luden es über ein script-Tag ins DOM Ihrer Seite und öffneten damit möglicherweise enthaltenem Schadcode Tür und Tor.

postMessage() kombiniert diese beiden Möglichkeiten: Sie haben die Sicherheit des iframes (ggf. ergänzt durch den zusätzlichen Schutz durch das sandbox-Attribut von HTML5), verbunden mit den Kommunikationsmöglichkeiten der direkten DOM-Einbindung.

Passen Sie auf, mit wem Sie reden!

Wie üblich, müssen Sie auch beim Einsatz von postMessage() auf die Sicherheit achten (sonst würde ich die Methode hier gar nicht erwähnen). Und zwar müssen Sie darauf achten, mit wem Sie kommunizieren.

Der Browser liefert die Daten nur aus, wenn die Origin des Ziels mit der angegebenen Origin übereinstimmt, es kann also nicht zu einem unerwünschten Datenleck kommen. Jedenfalls nicht, wenn Sie die Origin genau angeben. Die Kommunikation funktioniert auch, wenn Sie den Wildcard '*' als Zielorigin eingeben. Aber dann liefert der Browser die Nachricht an den Code im angegebenen zielfenster aus, egal von welcher Origin der darin laufende Code geladen wurde.

Ob die empfangenen Daten von der erwarteten Origin stammen und nicht zum Beispiel von einem bösartigen Skript von einer anderen Origin gesendet werden, müssen Sie selbst überprüfen. Dazu können Sie das vom Browser gesetzte origin-Attribut verwenden. Ausnahmsweise dürfen Sie dieser Information vertrauen, da das Attribut vom Browser gesetzt wird und vom JavaScript-Code nicht manipuliert werden kann (wie üblich mit der Einschränkung, dass es keine entsprechende Schwachstelle im Browser gibt).

Die Prüfung könnte zum Beispiel so aussehen:

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event) {
   if (event.origin == "http://erwartete-origin.example") {
      // alles OK
   } else {
      // Nachricht von falscher Origin
   }
}

Vorsicht vor XSS!

Ein Problem lässt sich mit der Prüfung des origin-Attributs und der genauen Angabe der Ziel-Origin im postMessage()-Aufruf nicht lösen: Wurde in eine der beteiligten Seiten über XSS Schadcode eingefügt, kann der von der jeweils anderen Seite nicht erkannt werden.

Nehmen wir als Beispiel eine Website A, die ein Widget W von einer anderen Website in einen iframe einbindet und über postMessage()-Aufrufe mit ihm kommuniziert. Dann gibt es vier Möglichkeiten:

  1. Weder A noch W enthalten XSS-Schwachstellen, alles funktioniert so, wie es soll.
  2. Sowohl A als auch W enthalten XSS-Schwachstellen, und in beide Seiten wurde JavaScript-Schadcode eingeschleust. Das ist im Grunde der Worst Case. Natürlich müssen sämtliche XSS-Schwachstellen korrigiert werden. Aber der Gedanke, dass da zwei Cyberkriminelle sich gegenseitig falsche Daten unter schieben ist doch etwas erheiternd. Jedenfalls solange dabei nicht zum Beispiel im Rahmen einer Drive-by-Infektion Schadcode auf dem Rechner des Benutzers installiert oder anderweitig Schaden angerichtet wird.
  3. Die Website A enthält eine XSS Schwachstelle. Der darüber eingeschleuste Schadcode kann dann das Vertrauen des Widgets in die Website ausnutzen und Daten ausspähen oder einschleusen.
  4. Das Widget W enthält eine XSS Schwachstelle. Der darüber eingeschleuste Schadcode kann dann das Vertrauen der Website in das Widget ausnutzen und Daten ausspähen oder einschleusen.

Eine theoretische Lösung des Problems wäre das Signieren der Daten. Das müsste dann aber auf dem Server erfolgen, da beim Signieren durch den JavaScript-Code auf dem Client der dafür benötigte Schlüssel vom eingeschleusten Schadcode ausgespäht bzw. die Signatur-Funktion von ihm missbraucht werden könnte.

Da man aber sowieso keine XSS-Schwachstellen auf seinen Seiten haben möchte, kann man auf diesen Ansatz i.A. verzichten.

Weihnachtspause!

Sofern nichts außergewöhnliches mehr passiert, ist dies der letzte Grundlagen-Artikel für dieses Jahr. Im nächsten Jahr geht es dann mit Angriffen auf bzw. über HTML5 weiter.

Ich wünsche Ihnen ein frohes Fest, einen guten Rutsch ins neue Jahr und ein erfolgreiches 2013!

Carsten Eilers


Übersicht über alle Artikel zum Thema

HTML5 Security - Eine Einführung
HTML5 Security - SVG und Resident XSS
HTML5 Security - Formulare auf Abwegen
HTML5 Security - Gift für den Application Cache
HTML5 Security - Der Local Storage
HTML5 Security - Die SQL-Datenbank
HTML5 Security - Cross Origin Requests
HTML5 Security - Gefährliche WebSockets
HTML5 Security - postMessage() sicher nutzen

Trackbacks

Keine Trackbacks