JavaScript-Sicherheit

Vom Web zu Windows 8: Security (Sicherheit)

Tim Kulp

 

Vor Jahren dachte ich, es wäre eine gute Idee, Golf spielen zu lernen. Bevor ich mich für Unterricht auf einem Golfplatz in der Nähe anmeldete, hatte ich noch nie zuvor einen Golfschläger in der Hand gehabt. In meiner ersten Stunde fragte mich mein Lehrer, ob ich schon einmal Unterricht gehabt oder versucht hätte, Golf zu spielen. Als ich seine Frage verneinte, war er erleichtert: „Gut, dann müssen Sie sich keine schlechten Gewohnheiten abgewöhnen.“

Webentwickler, die vom Browser zu Windows Store-Apps wechseln, haben doch so einige Gewohnheiten. Auch wenn sie ihre vorhandenen Kenntnisse in JavaScript abrufen können, sind einige Funktionen neu und erfordern ein gewisses Maß an Umdenken. Grundsätzlich anders ist zum Beispiel die Sicherheit. Viele Webentwickler haben es sich angewöhnt, dem Server die Anwendungssicherheit zu überlassen. Hierfür werden Gründe angegeben wie: „Warum soll ich mir die Mühe machen? JavaScript kann sowieso leicht umgangen werden.“ Aus Webclientperspektive dienen Sicherheitsfeatures der Verbesserung der Nutzbarkeit, ohne zur Gesamtsicherheit der Webanwendung einen Mehrwert beizutragen.

Unter Windows 8 spielt JavaScript hinsichtlich der gesamten Sicherheit Ihrer App eine wichtige Rolle, da JavaScript die erforderlichen Tools zum Schutz von Daten, Überprüfen von Eingaben und Isolieren von potenziell unsicheren Inhalten zur Verfügung stellt. In diesem Artikel möchte ich Ihnen zeigen, wie Sie einige Ihrer Gewohnheiten aus der Webentwicklung anpassen können, um sicherere Windows Store-Apps mithilfe von HTML5, JavaScript und den Sicherheitsfeatures von Windows-Runtime zu erstellen.

Eingabeüberprüfung

Webentwickler behaupten, die JavaScript-Überprüfung verbessere die Nutzbarkeit und biete keine Vorteile für die Anwendungssicherheit.

Windows 8-Entwickler behaupten dagegen, dass die Überprüfung mit HTML5 und JavaScript die erste Verteidigungslinie gegen das Eindringen von unsicherem Inhalt in eine App sei.

Für herkömmliche Webanwendungen ist JavaScript häufig nur ein Gateway für den Server. Alle wichtigen Datenaktionen, wie die Eingabeüberprüfung und Speicherung, finden auf dem Server statt. Böswillige Angreifer können JavaScript im Browser oder direkt durch Übermitteln manuell erstellter HTTP-Anforderungen deaktivieren und so clientseitige Schutzmaßnahmen umgehen. In einer Windows Store-App können sich Entwickler nicht auf einen Server zum Säubern von Benutzereingaben vor der Behandlung der Daten verlassen, weil einfach kein Server vorhanden ist. Hinsichtlich der Eingabeüberprüfung sind JavaScript und HTML5 vollkommen auf sich gestellt.

In der Softwaresicherheit ist die Eingabeüberprüfung eine zentrale Voraussetzung für die Datenintegrität. Ohne Eingabeüberprüfung stellt jedes Eingabefeld eine potenzielle Sicherheitslücke in der Windows Store-App dar, die Angreifer ausnutzen können. In der zweiten Ausgabe von „Writing Secure Code“ (Microsoft Press, 2003) beschreiben die Autoren Michael Howard und Steve Lipner das Mantra zum Verwalten von Eingaben: „Alle Eingaben sind bösartig, sofern kein Beweis für das Gegenteil vorliegt.“

Trauen Sie nur Daten, von denen Sie wissen, dass sie „bekannten gültigen“ Daten entsprechen. Ein Entwickler weiß beim Erstellen einer App, wie Daten aus einem bestimmten Feld aussehen sollen (= Zulassungsliste), oder zumindest weiß er, wie sie nicht aussehen dürfen (= Verweigerungsliste). In der Welt der Eingabeüberprüfung sollten Sie nach Möglichkeit immer eine Zulassungsliste verwenden, um die Eingabe auf bekannte gültige Daten zu beschränken. Indem Sie nur bekannte gültige Daten zulassen, reduzieren Sie die Gefahr, dass Sie neue oder unbekannte Methoden der Darstellung fehlerhafter Daten übersehen.

Beschränken, Ablehnen und Bereinigen

Wie reduzieren Entwickler das Risiko für ihre Benutzer, indem sie die Eingabe auf bekannte gültige Daten beschränken? Die Reduzierung des Risikos, dass schädliche Inhalte in die App eindringen, erfolgt in einer dreistufigen Eingabeüberprüfung (siehe Abbildung 1).

Input Validation (Image Based on Figure 4.4 from Chapter 4, “Design Guidelines for Secure Web Applications,” of “Improving Web Application Security: Threats and Countermeasures” at bit.ly/emYI5A)Abbildung 1: Eingabeüberprüfung (Das Bild basiert auf Abbildung 4.4 aus Kapitel 4 „Entwerfen von Richtlinien für sichere Webanwendungen“ aus „Erhöhen der Sicherheit von Webanwendungen: Bedrohungen und Gegenmaßnahmen“ unterbit.ly/emYI5A.)

Die Eingabeüberprüfung beginnt mit dem Einschränken der Daten auf „bekannte gültige“ Daten. Webentwickler, die mit HTML5 vertraut sind, können mithilfe vorhandener Kenntnisse hinsichtlich der neuen Eingabetypen und -attribute eingehende Daten einschränken. Der Hauptunterschied zwischen dem Web und Windows 8 besteht darin, dass eine Windows Store-App auf keinen Server zurückgreifen kann, der im Hintergrund die Eingaben überprüft. Das Einschränken der Daten muss in HTML5 oder JavaScript geschehen.

Mit HTML5 kann jedes Feld einfach auf bekannte gültige Daten eingeschränkt werden. Um die Beispiele in diesem Artikel zu illustrieren, verwende ich die fiktive Contoso Health-App, die persönliche medizinische Daten für Benutzer speichert. Auf der Profilseite dieser App werden der Name, die E-Mail-Adresse, das Gewicht und die Größe des Benutzers erfasst. Zudem enthält sie ein Hinweisfeld für allgemeine Informationen. Als Entwickler weiß ich (im Allgemeinen), wie für jedes dieser Felder gültige Daten aussehen:

  • Name: Buchstaben mit ein paar Sonderzeichen dürfen 45 Zeichen insgesamt nicht übersteigen. Die Namenskriterien basieren auf dem Zielmarkt der App, zum Beispiel dem US-amerikanischen Markt.
  • E-Mail-Adresse: Die Eingabe muss ein gültiges E-Mail-Adressformat aufweisen.
  • Gewicht und Größe: Zahlen mit zugeordneten Sprungmarken, die anzeigen, dass die Daten in Fuß, Zoll und Pfund angegeben werden.
  • Hinweise: HTML-Inhalt, der den standardmäßigen Contoso-HTML-Editor verwendet.

Für das Eingabeelement „Name“ muss ich die für das Feld gültigen Zeichen sowie die Länge des Werts beschränken. Hierfür kann ich zwei neue Attribute des Eingabetags verwenden: „pattern“ und „title“.

„pattern“ ist ein regulärer Ausdruck, dem die eingegebenen Daten entsprechen müssen. MSHTML (das für HTML5-Apps in Windows 8 verwendete Renderingmodul) überprüft, ob die in das Feld eingegebenen Daten dem regulären Ausdruck entsprechen. Wenn der Benutzer Daten eingibt, die nicht dem Muster für reguläre Ausdrücke entsprechen, treten beim Übermitteln des Formulars Fehler auf, und der Benutzer wird angewiesen, das ungültige Feld zu korrigieren. Beispielsweise kann das Feld „Name“ Alphazeichen und Leerzeichen enthalten. Außerdem muss es 3 bis 45 Zeichen lang sein. Der folgende pattern-Wert unterstützt dies:

<input type="text" id="txtName" name="txtName"
  pattern="^[A-Za-z ]{3,45}$" title="" />

Mit „title“ wird der Benutzer über die Erwartungen an die Eingabe informiert. In diesem Fall würde zum Beispiel ein Hinweis, dass der Name 3 bis 45 Zeichen lang sein und Buchstaben oder Leerzeichen enthalten muss, das erwartete Muster erklären. Nichts ist für Benutzer frustrierender, als ohne erklärende Hinweise eine Meldung über eine ungültige Eingabe zu erhalten. Gestalten Sie Ihre Meldungen benutzerfreundlich, und weisen Sie darauf hin, was zulässig ist. Das title-Attribut erfüllt genau diese Anforderung: Es ist eine Meldung mit einer Erläuterung zur erwarteten Eingabe für das Feld.

Muster für Datenfelder, die akzeptable Zeichen- und Längenangaben umfassen, lassen sich nicht immer ganz einfach festlegen. Viele hervorragende Onlineressourcen enthalten Beispiele für reguläre Ausdrücke. Sie sollten aber immer mit dem Sicherheitsteam Ihrer Organisation Rücksprache halten, um zu erfahren, ob Sie vorgegebene Standards erfüllen müssen. Falls Sie kein Sicherheitsteam haben oder Ihr Sicherheitsteam keine Standards besitzt, bieten Ressourcen wie RegExLib.com eine großartige Bibliothek mit regulären Ausdrücken, die Sie für die Datenüberprüfungen verwenden können.

Einige Felder sind bestimmte Datentypen, wie Zahlen, Daten und E-Mail-Adressen. HTML5 kommt mit zahlreichen neuen Eingabetypen erneut zu Hilfe, darunter „email“, „phone“, „date“, „number“ und viele mehr. Mithilfe dieser Dateneingabetypen überprüft MSHTML, ob die vom Benutzer eingegebenen Daten gültig sind, ohne dass reguläre Ausdrücke oder JavaScript-Code erforderlich sind. Das Typattribut des Eingabeelements behandelt die neuen Datentypen. (Weitere Typen und ihre Verwendung finden Sie unter bit.ly/OH1xFf.) Um beispielsweise eine E-Mail-Adresse für die Profilseite zu erfassen, würde ich das type-Attribut wie im folgenden Beispiel auf „email“ setzen:

<input type="email" id="txtEmail" name="txtEmail" />

In diesem Feld werden nur Werte akzeptiert, die dem Format einer gültigen E-Mail-Adresse entsprechen. Falls von MSHTML die Eingabe nicht als gültige E-Mail-Adresse erkannt wird, wird ein Überprüfungsfehler angezeigt, wenn der Benutzer versucht, das Formular zu übermitteln. Durch die Verwendung der neuen HTML5-Eingabetypen werden die Daten auf die erwarteten Daten beschränkt, ohne dass eine aufwendige JavaScript-Überprüfung erforderlich ist.

Einige der neuen Eingabetypen lassen auch Bereichsbeschränkungen mithilfe der neuen min- und max-Attribute zu. Beispiel: Aufgrund von Geschäftsregeln müssen die Benutzer der App zwischen 3 und 8 Fuß groß sein. Für das Größenfeld können die folgenden Bereichsbeschränkungen verwendet werden:

<input type="number" id="txtHeight" name="txtHeight" min="3" max="8" />

In den dargestellten Beispielen werden die vier Techniken zum Einschränken von Daten mithilfe des HTML5-Eingabetags verwendet. Durch die Überprüfung der Länge (mithilfe eines Musters), des Formats (auch mithilfe eines Musters), des Datentyps (mithilfe der neuen Eingabetypen) und des Bereichs (mithilfe von min/max) können Sie die Daten auf bekannte gültige Daten beschränken. Sie werden nicht von allen Attributen und Typen vor der Übermittlung zur Korrektur aufgefordert. Stellen Sie sicher, dass Sie die Inhalte des Formulars mit der checkValidity-Methode überprüfen (bit.ly/SgNgnA), wie bei Page.IsValid in ASP.NET. Sie fragen sich vielleicht, ob Sie Daten auf diese Weise mithilfe von JavaScript einschränken können. Ja, dies ist möglich. Durch die Verwendung von HTML5-Attributen wird jedoch der vom Entwickler zu verwaltende Gesamtcode reduziert, indem die Hauptarbeit auf das MSHTML-Modul übertragen wird.

„Reject“ verweigert die Eingabe bekannter ungültiger Daten (entspricht einer Verweigerungsliste). Ein gutes Beispiel von „reject“ besteht in dem Erstellen einer Verweigerungsliste von IP-Adressen, die keine Verbindung mit der Webanwendung herstellen können. Verweigerungslisten sind nützlich, wenn Sie einen einigermaßen festgelegten Bereich für zu blockierende Elemente definiert haben. Beispiel: Sie senden eine E-Mail an eine Gruppe wie Ihr Entwicklungsteam und entfernen dann einzelne Personen aus der E-Mail-Liste des Entwicklungsteams. In diesem Beispiel wissen Sie, welche E-Mail-Adressen aus der Entwicklungsteamliste Sie verweigern möchten. Für sichere Software sollten Sie das Einschränken (Zulassungsliste) gegenüber dem Ablehnen (Verweigerungsliste) priorisieren. Beachten Sie, dass sich bekannte ungültige Daten konstant ändern, da Angreifer immer kreativere Möglichkeiten zum Umgehen von Softwareschutzmaßnahmen finden. Stellen Sie sich vor, wie im vorangehenden Beispiel neue Entwickler im Entwicklungsteam prüfen müssen, ob sie in die E-Mail aufgenommen werden sollen. Einschränkungen und die entsprechenden Listen können langfristig erheblich einfacher verwaltet werden als die vielen Elemente einer Verweigerungsliste.

Es kann auch vorkommen, dass Daten bekannte gültige sowie bekannte ungültige Daten enthalten, wie zum Beispiel bei HTML-Inhalt. Einige Tags sind für die Anzeige zugelassen, andere aber nicht. Das Filtern oder Deaktivieren bekannter ungültiger Daten und das Zulassen genehmigter Daten wird auch als „Bereinigen“ der Eingabe bezeichnet. Das Hinweisfeld in der Contoso Health-App ist hierfür ein gutes Beispiel. Die Benutzer können HTML-Tags mithilfe eines HTML-Editors eingeben. Es werden jedoch nur bestimmte Tags gerendert, wenn die Eingabe in der App angezeigt wird. Bei der Bereinigung der Eingabe wird unsicherer Inhalt von möglicherweise schädlichen Daten entfernt, und nicht explizit genehmigter Inhalt wird in einen inaktiven Zustand versetzt. Setzen Sie hierfür in den Windows Store-Apps den Wert eines HTML-Elements auf innerText (anstatt innerHTML). Dadurch wird der HTML-Inhalt als Text gerendert und nicht als HTML interpretiert. (Beachten Sie, dass ausführbares Skript erstellt wird, wenn innerText eines script-Tags auf JavaScript gesetzt wird.) JavaScript bietet ein weiteres nützliches Tool zur Bereinigung: toStaticHTML.

Hier sehen Sie den Beispielcode vom btnSave_Click-Handler der Profilseite:

function btnSave_Click(args) {
  var taintedNotes = document.getElementById("txtNotes").value;
  var sanitizedNotes = window.toStaticHTML(taintedNotes);
  document.getElementById("output").innerHTML = sanitizedNotes;
}

Wenn der Benutzer die Zeichenfolge

<strong>testing!</strong><script>alert("123! ");</script>

in txtNotes eingibt, wird das script-Tag durch die window.toStaticHTML-Methode entfernt, und es wird nur das genehmigte strong-Tag beibehalten. Durch die Verwendung von toStaticHTML wird jedes Tag, das sich nicht auf der genehmigten sicheren Liste befindet (ein weiteres Beispiel der Verwendung einer Zulassungsliste), sowie jedes unbekannte Attribut entfernt. Nur bekannte gültige Daten werden in der Ausgabe der toStaticHTML-Methode aufbewahrt. Eine vollständige Liste genehmigter Tags, Attribute, CSS-Regeln und Eigenschaften finden Sie unter bit.ly/KNnjpF.

Durch die Eingabeüberprüfung wird das Risiko reduziert, dass schädliche Inhalte in das System eindringen. Mithilfe von HTML5 und toStaticHTML kann die Eingabe auf bekannte gültige Daten beschränkt werden, und potenziell schädlicher Inhalt kann ohne Servereingriff entfernt werden.

Da Contoso Health nun gültige Daten empfängt, stellt sich die Frage, wie mit sensiblen Daten wie medizinischen oder Finanzinformationen umgegangen werden soll.

Speichern sensibler Daten

Webentwickler behaupten, dass sensible Daten niemals auf dem Client gespeichert werden dürften, weil kein sicherer Speicher verfügbar sei.

Windows 8-Entwickler behaupten, dass sensible Daten verschlüsselt und mithilfe von Windows-Runtime sicher gespeichert werden könnten.

Im vorherigen Abschnitt wurden von der Contoso Health-App allgemeine Profilinformationen abgerufen. Im weiteren Verlauf der Entwicklung wird ein Formular für eine Krankengeschichte vom Unternehmenssponsor angefordert. In diesem Formular werden medizinische Ereignisse, wie der letzte Arztbesuch, im Leben eines Benutzers erfasst. Nach den traditionellen Regeln für die Webentwicklung sollten keine sensiblen Informationen wie die Krankengeschichte eines Benutzers auf dem Client gespeichert werden, weil die Daten offengelegt werden könnten. In der Windows Store-App-Entwicklung können sensible Daten mithilfe der Sicherheitsfeatures von Windows-Runtime lokal gespeichert werden.

Zum Schutz der Krankengeschichte des Benutzers wird die WinRT-Datenschutz-API verwendet. Die Verschlüsselung sollte nicht der einzige Bestandteil Ihrer Datenschutzstrategie sein (denken Sie an eine Tiefenverteidigungsstrategie: mehrere Sicherheitsebenen anstatt eines einfachen Schutzes wie der ausschließlichen Verschlüsselung). Verfolgen Sie außerdem weitere bewährte Methoden im Umgang mit sensiblen Daten. Dazu gehört es, nur auf die Daten zuzugreifen, wenn es wirklich erforderlich ist, und sensible Daten nicht im Cache zu behalten. Eine nützliche Ressource, die viele Aspekte zu sensiblen Daten auflistet, ist der Artikel in der MSDN-Bibliothek: „Erhöhen der Sicherheit von Webanwendungen: Bedrohungen und Gegenmaßnahmen“ unter (bit.ly/NuUe6w). In Mittelpunkt des Artikels stehen zwar bewährte Methoden der Webentwicklung, er enthält jedoch auch viele ausgezeichnete Grundlageninformationen, die Sie auf jeden beliebigen Entwicklungstyp anwenden können.

Die Seite „Medical History“ (Krankengeschichte) in der Contoso Health-App besitzt eine Schaltfläche mit der Bezeichnung „btnAddItem“. Wenn der Benutzer auf „btnAddItem“ klickt, werden die in das Formular „Medical History“ eingegebenen Daten verschlüsselt. Zum Verschlüsseln der „Medical History“-Daten wird die integrierte WinRT-Datenschutz-API verwendet. Mithilfe dieses einfachen Verschlüsselungssystems können Entwickler Daten schnell ohne den Aufwand der Schlüsselverwaltung verschlüsseln. Starten Sie mit einem leeren Ereignishandler für das btnAddItem-Klickereignis. Anschließend werden durch Contoso Health die Formularinformationen gesammelt und in einem JSON-Objekt gespeichert. Im Ereignishandler füge ich den Code hinzu, um schnell das JSON-Objekt auszubauen:

var healthItem = {
  "prop1": window.toStaticHTML(document.getElementById("txt1").value),
  "prop2": window.toStaticHTML(document.getElementById("txt2").value)
};

Das healthItem-Objekt repräsentiert den Datensatz von „Medical History“, die der Benutzer in das Formular eingegeben hat. Die Verschlüsselung von healthItem beginnt mit dem Instanziieren von DataProtectionProvider:

var dataProtectionProvider =
  Windows.Security.Cryptography.DataProtection.DataProtectionProvider(
  "LOCAL=user");

Der DataProtectionProvider-Konstruktor (zur Verschlüsselung) nimmt ein Zeichenfolgenargument an, das festlegt, womit Data Protection verknüpft ist. In diesem Fall verschlüssele ich Inhalt für den lokalen Benutzer. Anstatt den lokalen Benutzer könnte ich den Computer, einen Satz an Webanmeldeinformationen, ein Active Directory-Sicherheitsprinzip oder ein paar andere Optionen wählen. Sie können eine Liste von Schutzbeschreibungsoptionen im Entwicklungscenter unter „Schutzdeskriptoren“ (bit.ly/QONGdG) abrufen. Die Auswahl eines bestimmten Schutzdeskriptors hängt von den Anforderungen Ihrer App ab. Jetzt ist Data Protection Provider bereit, die Daten zu verschlüsseln, sie müssen jedoch leicht geändert werden. Verschlüsselungsalgorithmen funktionieren mit Puffern, nicht mit JSON. Folglich besteht der nächste Schritt im Umwandeln von healthItem in einen Puffer:

var buffer =
  Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(
    JSON.stringify(healthItem),
    Windows.Security.Cryptography.BinaryStringEncoding.utf8);

CryptographicBuffer besitzt viele Objekte und Methoden zum Arbeiten mit Puffern, die beim Verschlüsseln und Entschlüsseln verwendet werden. Die erste dieser Methoden ist convertStringToBinary. Sie verwendet eine Zeichenfolge (in diesem Fall die Zeichenfolgeversion des JSON-Objekts) und konvertiert sie in einen codierten Puffer. Die verwendete Codierung wird mit dem Windows.Security.Cryptography.Binary­StringEncoding-Objekt festgelegt. In diesem Beispiel verwende ich UTF8 als Codierung für meine Daten. Die convertStringToBinary-Methode gibt einen Puffer auf Grundlage der Zeichenfolgedaten und der angegebenen Codierung zurück. Wenn der Puffer für die Verschlüsselung bereit ist und Data Protection Provider instanziiert ist, kann ich die protectAsync-Methode zum Verschlüsseln des Puffers aufrufen:

dataProtectionProvider.protectAsync(buffer).then(
  function (encryptedBuffer) {
     SaveBufferToFile(encryptedBuffer);
});

Das encryptedBuffer-Argument ist die Ausgabe der protectAsync-Methode und enthält die verschlüsselte Version des Puffers. Anders gesagt: Hierbei handelt es sich um die verschlüsselten, für die Speicherung bereiten Daten. Nun wird encryptedBuffer an die SaveBufferToFile-Methode übergeben, die verschlüsselte Daten in eine Datei im lokalen Ordner der App schreibt.

Die Verschlüsselung für healthItem läuft im Prinzip auf drei Codezeilen hinaus:

  1. Instanziieren von Data Protection Provider.
  2. Konvertieren der Daten in einen Puffer.
  3. Aufrufen von protectAsync zum Verschlüsseln der Daten.

Das Entschlüsseln der Daten ist genauso einfach. Die einzigen Änderungen bestehen in der Verwendung eines leeren Konstruktors für DataProtectionProvider und der unprotectAsync-Methode anstatt der protectAsync-Methode. Die GetBufferFromFile-Methode lädt die encryptedBuffer-Variable aus der Datei, die in der SaveBufferToFile-Methode erstellt wurde:

function btnLoadItem_Click(args) {
  var dataProtectionProvider =
    Windows.Security.Cryptography.DataProtection.DataProtectionProvider();
  var encryptedBuffer = GetBufferFromFile();
  dataProtectionProvider.unprotectAsync(encryptedBuffer).then(
    function (decryptedBuffer) {
      // TODO: Work with decrypted data
    });
}

Können Entwickler die Verschlüsselung mit Nicht-WinRT-JavaScript verwenden? Ja! Ist dies so einfach wie drei Codezeilen, die einen hervorragenden Datenschutz bieten? Nein! Bewährte Methoden für die Verschlüsselung im Browser müssen stets überdacht werden. Zu den zahlreichen Herausforderungen gehören das Geheimhalten des geheimen Schlüssels sowie das Verwalten der für eine qualitative Verschlüsselung erforderlichen Dateigröße der Algorithmen. Die WinRT-Datenschutz-API und andere im Windows.Security.Cryptography-Namespace bereitgestellten Tools vereinfachen den Schutz Ihrer Daten. Entwickler können mithilfe der Sicherheitsfeatures von Windows-Runtime sensible Daten sicher in der Windows Store-App speichern und gleichzeitig die kryptografischen Schlüssel einfach verwalten.

Lokaler Kontext im Vergleich zum Webkontext

Webentwickler behaupten, dass Web-Apps externe Skriptverweise im selben Ursprung der Anwendung ausführten, von der die Skripte aufgerufen werden.

Windows 8-Entwickler behaupten, dass Windows Store-Apps das lokale App-Paket von den externen Skriptverweisen trennten.

Web 2.0 hat Entwickler so geschult, dass Inhalt von Ihrer Website, der Website einer anderen Person (über Kombinationen) oder Benutzerinteraktionen stammen kann. Im Web ist Inhalt für alle virtuell und gratis, und Entwickler nutzen Skriptverweise und API-Daten von Drittanbietern. Aufgrund von Netzwerken für die Inhaltsübermittlung (Content Delivery Networks, CDNs) und Onlinediensten wie Bing Maps entfällt der Aufwand der Verwaltung von Codebibliotheken oder großen Datenrepositorys. Hierdurch wird ein einfaches Snap-In von Funktionen durch Webanwendungen ermöglicht. Während ein geringerer Aufwand vorteilhaft sein kann, entstehen durch diesen Vorteil auch einige Risiken.

Einer der Partner von Contoso in der Gesundheitssoftwarebranche ist beispielsweise Litware Inc. Litware veröffentlicht eine neue Übungs-API und hat Contoso Health-Entwicklern die Schlüssel zum Nutzen eines täglichen Übungsdatenfeeds zur Verfügung gestellt. Wenn Contoso Health eine Webanwendung wäre, könnte das Entwicklungsteam die Übungs-API mithilfe eines Skriptverweises wie dem folgenden implementieren:

<script src="https://api.litware.com/devkey/exercise.js"></script>

Entwickler bei Contoso vertrauen darauf, dass Litware ausgezeichneten Inhalt bietet, und sind sich der herausragenden Sicherheitspraktiken bewusst. Leider wurden die Server von Litware von einem verärgerten Entwickler manipuliert. Infolgedessen enthält exercise.js nun ein Startskript, das ein Popup mit der Meldung anzeigt, dass Contoso Health gewartet werden muss und der Benutzer die angezeigte Wartungsanwendung herunterladen soll. Der Benutzer ging davon aus, dass diese Meldung legitim ist und wurde dazu verleitet, Malware herunterzuladen. Die Entwickler von Contoso waren bestürzt: Litware setzt umfassende Überprüfungen ein. Wie kam diese Lücke zustande?

Im Web werden Skripts, auf die wie oben beschrieben verwiesen wird, mit demselben Ursprung wie ein Skript auf derselben Website ausgeführt. Dadurch hat exercise.js (als JavaScript ausgeführt) uneingeschränkten Zugriff auf die DOM-Baumstruktur sowie auf jedes Skriptobjekt. Wie oben gezeigt, können dadurch ernste Sicherheitsprobleme entstehen. Um dieses Risiko zu reduzieren, werden unter Windows 8 App-Ressourcen in zwei Kontexte aufgeteilt (siehe Abbildung 2).

Local vs. Web Context Features (Mashed from “Features and Restrictions by Context” [bit.ly/NZUyWt] and “Secure Development with HTML5” [bit.ly/JOoMOS])Abbildung 2: Lokales Kontextfeature im Vergleich zu einem Webkontextfeature (Kombination aus „Features und Einschränkungen nach Kontext“ [bit.ly/NZUyWt] und „Sichere Entwicklung mit HTML5” [bit.ly/JOoMOS])

Im lokalen Kontext kann der Zugriff auf Windows-Runtime sowie auf jede beliebige Ressource erfolgen, die im App-Paket enthalten ist (wie HTML-, Skript-, CSS- und App-Daten, die in den App-Statusbibliotheken gespeichert sind). Der Zugriff auf Remote-HTML, -JavaScript oder -CSS ist jedoch nicht möglich (wie im obigen exercise.js-Beispiel). Die App der obersten Ebene in Windows 8 wird immer im lokalen Kontext ausgeführt. In Abbildung 2 wird ms-appx:// zum Auflösen von Inhalt im lokalen Kontext verwendet. Das Schema wird zum Verweisen auf Inhalt im App-Paket beim Ausführen im lokalen Kontext verwendet. Häufig wird ein dritter Schrägstrich (ms-appx:///) zum Verweisen auf den vollständigen Namen des Pakets eingefügt. Für Webentwickler ist diese Herangehensweise dem Verwenden des file://-Protokolls ähnlich. Hier weist ein dritter Schrägstrich auf das lokale Dateisystem hin (setzt file://END USER’s COMPUTER/ voraus anstatt file://REMOTE COMPUTER/).

Der Webkontext ermöglicht Entwicklern, Remoteinhalt über einen IFrame in die Windows Store-App einzufügen. Wie bei IFrames in einem Webbrowser ist der Zugriff des im IFrame ausgeführten Inhalts auf externe Zugriffsressourcen eingeschränkt, wie Windows-Runtime und einige Features der Windows-Bibliothek für JavaScript. (Eine vollständige Auflistung finden Sie unter bit.ly/PoQVOj.) Mithilfe des Webkontexts soll Entwicklern das Verweisen auf APIs von Drittanwendern wie Bing Maps oder das Ziehen einer Bibliothek aus einem CDN in die App ermöglicht werden.

Indem http:// oder https:// als Quelle eines IFrames verwendet wird, werden die Inhalte des IFrames automatisch in den Webkontext übertragen. Ein IFrame kann auch eine Ressource im App-Paket sein, wenn Sie ms-appx oder ms-appx-web verwenden. Wenn die Quelle eines IFrames auf das ms-appx://-Schema verweist, wird der Inhalt des IFrames im lokalen Kontext ausgeführt. Dadurch können Entwickler App-Paketressourcen in einen IFrame einbetten und gleichzeitig Zugriff auf die Features des lokalen Kontexts haben (wie Windows-Runtime, Windows-JavaScript-API usw.). Darüber hinaus steht das ms-appx-web://-Schema zur Verfügung, mit dem lokaler App-Paketinhalt im Webkontext ausgeführt werden kann. Das Schema ist praktisch, wenn Sie Remoteinhalt in Ihr Markup einbetten müssen. Das betrifft zum Beispiel das Hinzufügen von Suchergebnissen aus Bing (aus der Such-API in Bing) zu lokalen Krankenhäusern basierend auf dem Standort des Benutzers in der Contoso Health-App. Nebenbei bemerkt: Wenn IFrames mit HTML5 erwähnt werden, können Sie das sandbox-Attribut als zusätzlichen Schutz für Ihre App verwenden, indem Sie die Skriptausführung des Inhalts innerhalb des IFrames einschränken. Weitere Informationen zum sandbox-Attribut erhalten Sie unter bit.ly/Ppbo1a.

Abbildung 3 zeigt die verschiedenen im lokalen Kontext und im Webkontext verwendeten Schemas zusammen mit Verwendungsbeispielen.

Abbildung 3: Schemas mit Kontextbeispielen

Schema Inhaltsort Kontext Beispiel Verwendung
ms-appx:// App-Paket Lokal

<iframe

 src="ms-appx:///1.html"

></iframe>

Laden von Inhalt in einen IFrame, der auf Windows-Runtime oder die vollständige Windows-JavaScript-API zugreifen muss.
ms-appx-web:// App-Paket Web

<iframe

 src="ms-appx-web:///2.html"

></iframe>

Verwenden von Inhalt aus einer Remotequelle als Teil der Windows Store-App-Benutzeroberfläche, wie das Anzeigen eines Mapping-Widgets oder von Suchergebnissen.
http:// Remote Web

<iframe

 src="http://host/3.html"

></iframe>

Verweisen auf Remoteinhalt wie eine Webseite oder Skriptdatei auf einem anderen Server.

Der zu einem IFrame gehörende Kontext basiert auf der Art und Weise, wie auf den enthaltenen Inhalt verwiesen wird. Anders gesagt, das Schema bestimmt den Kontext. Weitere Informationen zu den in Windows 8 verwendeten Schemas finden Sie unter bit.ly/SS711o.

Erinnern Sie sich an das Litware-Hackerszenario am Anfang dieses Abschnitts? Durch die Trennung der Kontexte in Windows 8 wird der siteübergreifende Skriptingangriff auf den Webkontext eingeschränkt, wo kein Zugriff auf Windows-Runtime oder die App-Daten von Contoso Health möglich ist. Im Webkontext ist das Ändern von lokalem Inhalt keine Option. Die Kommunikation zwischen Kontexten ist möglich, Sie haben jedoch Kontrolle über die Art der stattfindenden Kommunikation.

Kommunizieren zwischen Kontexten

Wie kommuniziert ein Dokument oberster Ebene mit einem im Webkontext ausgeführten IFrame? Mithilfe der postMessage-Features von HTML5 können in Windows Store-Apps Daten zwischen Kontexten übergeben werden. Dadurch können Entwickler die Kommunikation der beiden Ursprünge strukturieren und nur bekannte gültige Anbieter (siehe Zulassungsliste) im lokalen Kontext zulassen. Auf Seiten, die im Webkontext ausgeführt werden müssen, wird mithilfe eines IFrames verwiesen, in dem das src-Attribut auf http://, https:// oder ms-appx-web:// gesetzt ist.

Für die Contoso Health-App werden Fitnesstipps aus der Litware-Übungs-API gezogen. Das Entwicklungsteam von Contoso Health hat die litwareHelper.html-Seite erstellt. Sie wird für die Kommunikation mit der Übungs-API über das jQuery $ajax-Objekt verwendet. Wegen der Remoteressource (exercise.js) muss litwareHelper.html im Webkontext, also in einem IFrame, ausgeführt werden. Der IFrame wird genauso wie in anderen Webanwendungen eingerichtet. Nur die Art, wie auf die Seite verwiesen wird, unterscheidet sich. Da die litwareHelper.html-Seite Teil des lokalen App-Pakets ist, aber im Webkontext ausgeführt werden muss, können Sie sie mit ms-appx-web laden:

<iframe id="litwareHelperFrame” src="ms-appx-web:///litwareHelper.html"></iframe>

Das Entwicklungsteam fügt die folgende Funktion der lokalen Kontextseite hinzu, von der die Datenanforderung an das Web gesendet wird.

function btnGetFitTips_Click() {
  var msg = {
    term: document.getElementById("txtExerciseSearchTerm").value,
    itemCount: 25  }
  var msgData = JSON.stringify(msg);
  var domain = "ms-appx-web://" + document.location.host;
  try {
    var iframe = document.getElementById("litwareHelperFrame");
    iframe.contentWindow.postMessage(msgData, domain);
  }
  catch (ex) {
    document.getElementById("output").innerText = "Error has occurred!";
  }
}

Die receiveMsg-Methode verarbeitet die Meldung aus dem lokalen Kontext. Das Argument von receiveMsg sind die für das postMessage-Ereignis bereitgestellten Daten (in diesem Fall die msgData-Variable) sowie das Meldungsziel, der Meldungsursprung und weitere Informationen (siehe Abbildung 4).

Abbildung 4 Verarbeiten mit receiveMsg

function receiveMsg(e) {
  if (e.origin === "ms-appx://" + document.location.host) {
    var output = null;
    var parameters = JSON.parse(e.data);
    var url = "https://api.litware-exercise.com/data/" 
      + parameters.term +
      "/count/" + parameters.itemCount;
    var options = {
      dataType: "jsonp",
      jsonpCallback: "jsonpCallback",
      success: function (results) {
        output = JSON.stringify(results.items);
        window.parent.postMessage(output, "ms-appx://" 
        + document.location.host);
      },
      error: function (ex) {
        output = ex;
      }
    };
    $.ajax(url, options);
  }
}

Im ersten Schritt von receiveMsg wird der Ursprung von postMessage überprüft. Dabei handelt es sich um eine kritische Sicherheitsüberprüfung, um sicherzustellen, dass die Meldung tatsächlich aus dem angegebenen Ursprung stammt. Denken Sie daran, dass durch e.origin die Domäne und das Schema derjenigen überprüft wird, die postMessage gesendet haben. Aus diesem Grund führen Sie eine Überprüfung auf ms-appx durch (die lokale Kontextadresse). Nach dem Sammeln von JSON-Daten aus der Litware-API werden die Ergebnisse mithilfe eines postMessage-Befehls zurück an window.parent übergeben. Beachten Sie in receiveMsg, dass die Domäne auf ms-appx gesetzt ist. Das ist die „An“-Adresse, an die die Meldung gesendet wird. Sie zeigt, dass die Daten an den lokalen Kontext zurückgegeben werden. Daten aus dem IFrame müssen von Ressourcen im lokalen Kontext genutzt werden. Das Entwicklungsteam fügt die processResult-Funktion hinzu, um die Daten aus dem Webkontext zurück im lokalen Kontext zu nutzen:

function processResult(e) {
  if (e.origin === "ms-appx-web://" + document.location.host) {
    document.getElementById("output").innerText = e.data;
  }
}

Auch hier gilt es, immer den Ursprung des Meldungsereignisses zu überprüfen, um sicherzustellen, dass nur Daten von genehmigten Orten (d. h. Orten, die in der Zulassungsliste registriert sind) verarbeitet werden. Der Ursprung ist das Webkontextschema: ms-appx-web in der processResult-Methode. Der Wechsel zwischen Schemas kann ein Problem darstellen, das Entwickler übersehen können. Sie wundern sich dann, wohin ihre Meldung während des Debuggings verschwunden ist.

Um letztendlich Daten aus dem Webkontext zurück auf der lokalen Kontextseite zu empfangen, fügen Sie einen Ereignishandler für das Meldungsereignis hinzu. Fügen Sie in der app.onactivated-Methode dem Fensterobjekt den Ereignislistener hinzu:

window.addEventListener('message', processResult, false);

Durch die standardmäßige Trennung von lokalem Kontext und Webkontext wird das Risiko des versehentlichen Ausführens von Code aus einer Quelle außerhalb der Windows Store-App reduziert. Entwickler können mithilfe von postMessage einen Kommunikationskanal zwischen externem Skript und den lokalen Skripts bieten, die eine App zusammenstellen.

Vom Web zu Windows 8: Neue Tools für alte Gewohnheiten

Webentwickler haben jetzt Zugriff auf bekannte Tools und neue Tools, mit denen sie sichere Windows Store-Apps erstellen können. Die Verwendung vorhandener Funktionen wie die HTML5-Eingabeüberprüfung stellt die Integrität der eingehenden Daten in der App sicher. Neue Tools wie die Datenschutz-API (neu für Windows-Runtime) schützen die vertraulichen Daten von Benutzern mit leistungsstarker Verschlüsselung, die einfach zu implementieren ist. Mithilfe von postMessage können Apps auch die vielen JavaScript-Bibliotheken und Legacycode im Web nutzen und Benutzer gleichzeitig vor unbeabsichtigter Codeinjizierung schützen. Alle diese Elemente zusammen statten JavaScript mit etwas aus, was häufig abgetan wird: die Sicherheit.

Windows 8 gibt Webentwicklern die Chance, einige ihrer alten Gewohnheiten zu überdenken. JavaScript ist nicht mehr nur eine Fassade für den Server, die lediglich als Verbesserung der Nutzbarkeit anerkannt und ansonsten ignoriert wird. JavaScript, Windows-Runtime und MSHTML stellen die erforderlichen Tools zum Erstellen von Sicherheitsfeatures in den Windows Store-Apps zur Verfügung. Und zwar ohne Server. Als Webentwickler können wir auf eine Bandbreite an Fähigkeiten zurückgreifen. Wir müssen jedoch unsere alten Gewohnheiten im Auge behalten und sie in Chancen verwandeln, etwas über die neue Welt in Windows 8 zu lernen.

Tim Kulp ist Leiter des Entwicklungsteams bei FrontierMEDEX in Baltimore, Md. Sie können seinen Blog unter seccode.blogspot.com lesen oder ihm unter Twitter.com/seccodeinfo auf Twitter folgen, wo er über Code, Sicherheit und Restaurants in Baltimore informiert.

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Scott Graham