XSS Prävention bei modernen JavaScript Frameworks

Die meisten modernen JS-Frameworks wie ReactVue, oder Angular bringen von Haus aus bereits viele Sicherheitsfeatures mit, die es vorher nicht in der Form gab. Trotzdem kann man auch hier noch Fehler machen, die sich direkt auf die Sicherheit auswirken. Die Gefahr ist also nach wie vor, dass man aus Unwissenheit Schwachstellen verursacht. Deshalb ist es wichtig, diese Schwachstellen zu kennen, um sie dann auch vermeiden zu können.

Als Beispiel zeige ich hier einen klassischen Fall von Cross Site Scripting (XSS), der auch heute noch sehr real ist. Wir konstruieren uns dazu das folgende Szenario.

Nehmen wir an, wir wollten einen Benutzer mit seinem Namen ansprechen, indem wir ihn über eine Marketing-E-Mail verknüpfen. Das Hinzufügen von ?name=Julian zum Query-String und das anschließende Hinzufügen zum DOM wäre eine schnelle Möglichkeit, dies zu tun.

Zum Beispiel:

document.querySelector('.tagline').innerHTML = nameFromQueryString

Dadurch würde „Julian“ direkt namentlich angesprochen werden auf der Seite. Die Filterung auf den Request-Parameter wird vom JS-Framework hier nicht gemacht werden.

Die Verwendung von Code wie dem oben genannten bedeutet, dass jeder Angreifer Code in Deine Webanwendung einfügen und übernehmen kann. Allein durch Ändern des Namens in <script src="my.malicious.site"> kann man eine URL kreieren, die eine gefälschte Zahlungsseite so aussehen lässt, als würde sie von Deiner SSL-verschlüsselten Website geliefert.

Aus diesem Grund ist es ratsam, Daten von Requestparametern immer vorher zu prüfen und zu filtern, und sie niemals einfach so zu übernehmen. Nur so kann man XSS wirksam vermeiden.

Jackson-Databind und das Problem mit CVE-2017-7525

Wird Jackson-Databind als 3rd-Party-Lib in einem Projekt eingebunden, oder es ist über eine transitive Abhängigkeit mit im Projekt, dann melden Analysetools umgehend ein Finding. Aber in welchem Fall ist Jackson-Databind tatsächlich gefährlich?

Hintergrund

Jackson-Databind wird verwendet, wenn Json Strings deserialisiert werden. Die Deserialisierung ist etwas komplizierter als die Serialisierung, was daran liegt, dass beim Serialisieren die Klassen noch bekannt sind. Werden abstrakte Klassen oder Interfaces verwendet, ist das beim Serialisieren egal – der Json String ist immer der gleiche. Anders herum muss beim Deserialisieren, wenn der Json String wieder in reale Objekte gemappt wird, eine Entscheidung für konktete Klassen gefällt werden, die auch instantiiert werden können.

Damit Jackson bei der Deserialisierung konkrete Klassen ermitteln kann, wird mit Annotations gearbeitet, über die die Klassen angegeben werden können:

{ "phone" : {
"@class" : "package.InternationalNumber",
"areaCode" : 555,
...
}
}

Auf Seite der Java-Klasse wird als Gegenstück z.B. mit @JsonTypeInfo gearbeitet, damit Jackson die richtige Klasse findet. Es gibt hier eine Vielzahl an Annotations, die bei komplexeren Strukturen helfen sollen.

Die Gefahr

Die Sicherheitslücke besteht dann, wenn der Json String so manipuliert werden kann, dass bei der Deserialisierung eine Klasse instanziiert wird, die Schaden anrichten kann (Denial of Service, Sensitive Data Exposure, Data Manipulation, …). Solche Klassen werden in diesem Kontext als „Gadgets“ bezeichnet.

Eine Gadget-Klasse muss allerdings im Klassenpfad der Anwendung liegen, weshalb zunächst unlogisch erscheint, dass damit Schaden angerichtet werden kann. Es gibt aber verschiedene polymorphe Klassen, über die generischer Code eingeschleust werden kann, der dann zur Ausführung kommt. Jackson hat deshalb bereits eine Blacklist an bekannten Gadget-Klassen, die bei der Deserialisierung nicht ausgeführt werden. Allerdings kommen immer neue kreative Varianten dazu, so dass naturgemäß eine Blacklist kein vollkommener Schutz sein kann.

Voraussetzungen für erfolgreichen Angriff

  1. Die Anwendung akzeptiert Json von Clients, das manipuliert werden kann. 
    • Bei der Kommunikation zwischen 2 Anwendungen, die sich in einer Trustzone befinden, sollte diese Gefahr nicht gross sein, da darauf vertraut wird, dass keine bösartigen und manipulierten Json Strings verwendet werden.
    • Wurde die Trustzone allerdings kompomittiert, dann fällt dieses Argument, so dass man auch bei interner Kommunikation weitere Maßnahmen vorsehen sollte.
  2. Die Anwendung beinhaltet im Classpath mindestens 1 Gadget-Klasse, mit der ein Angriff ausgeführt werden kann.
    • Da in einer Anwendung meist sehr viele Klassen über transitive Abhängigkeiten enthalten sind, sind auch viele bekannte Gadget-Klassen verfügbar. Selbst im JDK existieren Klassen, die als Gadgets missbraucht werden können.
    • Aus diesem Grund trifft auch diese Voraussetzung streng genommen immer zu.
  3. Die Anwendung hat aktives polymorphes Typehandling für Felder mit dem Type Object aktiviert (oder andere allgemeine Typen wir Serializable, Comparable, …)
    • Dies wird im Code über die Methode org.codehaus.jackson.map.ObjectMapper.enableDefaultTyping() aktiviert
  4. Die Anwendung verwendet Jackson-Databind in einer Version, die (noch) keine fragwürdige Gadget-Klassen blockiert via Blacklisting.
    • Ist die Jackson-Version aktuell, dann ist es sehr schwer, aber nicht ausgeschlossen, Gadget-Klassen zu finden, die einen Angriff zulassen.

Da (1) und (2) nie komplett ausgeschlossen werden können, sollten wir uns auf (3) und (4) fokussieren.

Folgendes ist noch festzustellen für die beiden Ausprägungen:

  1. Polymorphie: Anhand des Parameters valueType wird über die Annotation JsonTypeInfo definiert, welche „Zielklasse“ bei der Deserialisierung verwendet werden soll. Das ist entweder diese übergebene Klasse valueType selbst oder wird wiederum durch Annotationen dieser Klasse bestimmt. Durch die Annotation JsonTypeInfo kann definiert werden, dass die tätsächlich instanzierte Klasse, durch einen Parameter innerhalb des JSON-Textes vorgegeben wird, was bedeutet, dass der Sender des JSON-Textes die Entscheidung trifft. Die Entscheidung ist nicht völlig frei: die instanzierte Klasse, muss eine Erweiterung der Klasse valueType sein. Jackson bietet dazu mehrere Möglichkeiten. Die Kritische ist die, bei der Klassenname, bzw. ein Teil des Klassennamens, als JSON-Inhalt definiert/ausgewertet wird.
  2. DefaultTyping: unbestimmte/generische Attribute – beispielsweise von Type Tattr Object – können bei eingeschaltetem DefaultTyping mit Objekten befüllt werden, deren konkreter Typ Tconc durch den JSON-Inhalt bestimmt wird. Im Falle des Attributstyps Tattr Object unterliegt Tconc lediglich der Einschränkung, dass Tconc im Klassenpfad zu finden sein muss.


Ein Beispiel für eine gefährliche Codestelle ist folgende:

public class Person {
@JsonTypeInfo(use = Id.CLASS)
public Object phone;
}

Hier wird über @JsonTypeInfo der Klassenname angegeben, so dass dieser in der Json Struktur über die @class Annotation angegeben werden kann. Ist DefaultTyping aktiviert, dann kann an Stelle des Typs Object eine Gadget-Klasse treten, die der Angreifer angibt.

Prävention

  1. Immer die neueste Jackson-Databind Version verwenden
    • denn diese enthält die vollständigste Liste der gefährlichen Gadget-Klassen in der Blacklist
    • das ist kein perfekter Schutz, aber das mindeste was man tun sollte
  2. Default Typing vermeiden
    • statt dessen explizit die Klassen angeben, die bei der Deserialisierung verwendet werden sollen
  3. Allgemeine Klassen wie Object, Serializable, … vermeiden in den Objekten, die übertragen werden
    • dadurch wird vermieden, dass beliebige Klassen für den Angriff verwendet werden können
  4. Möglichst „type name“ verwenden und nicht classname als Type-Id
    • @JsonTypeInfo(use = Id.NAME)  anstatt  @JsonTypeInfo(use = Id.CLASS)

Referenzen

Sicherheitslücke durch Unwissenheit?

Was da gerade bei den Freien Wählern in Bayern passiert ist, sind gleiche mehrere kapitale Fehler, die entweder durch Schlamperei oder einfach durch Unwissenheit entstehen konnten. Wie heise security am 16.10.2018 berichtete, kam es auf der Webseite der Freien Wählern zu einer Überlastung durch zuviel Besucher nach der Landtagswahl. In Folge wurde die maximal mögliche Anzahl der Datenbankverbindungen erreicht, so dass das Content Management System Typo3 nur noch eine Fehlerseite für neue Besucher zeigte. Verhängnisvollerweise waren auf dieser aber die Zugangsdaten zur MySQL DB zu sehen, was Angreifern Tür und Tor öffnete.

https://api.heise.de/svc/embetty/tweet/1051507700616650753-images-0

Bei näherem Hinsehen wurden gleich mehrere Fehler gemacht, die das Ausmaß der Katastrophe unnötig erweitert haben. So wurde zunächst nicht auf den aktuellen Stand der Software geachtet, so dass anscheinend veraltete und ungepatchte Versionen von PHP, Typo3 und MySQL eingesetzt wurden. Dies allein ist eine Sicherheitslücke, die in den OWASP Top-10, der am meisten ausgenutzten Schwachstellen auf Platz 9 gelistet sind. „Using Components with Known Vulnerabilities“ heißt dieser Punkt, der darauf hinweist, dass man stets darauf achten sollte, keine Komponenten mit bekannten Schwachstellen zu verwenden. Öffentlich verfügbare Exploits machen es Angreifern sehr leicht, diese Schwachstellen auszunutzen.

Der weitaus schlimmere Fehler war aber der, dass die Betreiber der Webseite den Debugmodus bei Typo3 aktiv gelassen haben, was dazu führe, dass die Zugangsdaten zur Datenbank in der Fehlermeldung veröffentlicht wurden. In den OWASP Top-10 wird dieser Fehler auf Platz 6 gelistet unter dem Titel „Security Misconfiguration“. Der Debugmodus ist ausschließlich für Testumgebungen gedacht und darf auf keinen Fall auf einer Produktivumgebung aktiv sein. Mit Kenntnis der Zugangsdaten zur Datenbank können mit etwas Geschick alle Daten der Webseite ausgelesen und auch manipuliert werden.

Was aber dann noch oben drauf kommt ist der kapitale Fehler, dass diese veröffentlichten Zugangsdaten nicht nur für die Datenbank gültig waren, sondern auch für das Content Management System, so dass sich jeder, der die Administrations-Seite findet, dort einloggen und bequem sämtliche Inhalte verändern und manipulieren kann, sowie auch in nicht öffentliche Bereiche vordringen kann und Zugriff auf geheime Informationen hat. Dies ist ein Verstoß der Sicherheitsregeln, die in den OWASP Top-10 auf Platz 2 gelistet sind mit „Broken Authentication“. Es ist leider eine sehr verbreitete Praxis, dass man Zugangsdaten wie Benutzername und Passwort nicht nur exklusiv für ein System verwendet, sondern gleich für mehrere Systeme. Die große Gefahr dabei ist, dass wenn diese Zugangsdaten veröffentlicht werden, nicht nur das eine System kompromittiert ist, sondern auch die anderen, auf denen sie gelten.

Folgende Fehler wurden nach den vorliegenden Informationen mindestens gemacht:

  • Veraltete, ungepatchte Software (PHP, Typo3, MySQL)
    • hat in diesem Fall nicht direkt zu dem Angriff beigetragen, ist aber immer eine angreifbare und oft ausgenutzte Schwachstelle
  • Debugmodus aktiv bei Typo3
    • dadurch Preisgeben von geheimen Informationen, in diesem Fall der Zugangsdaten zur DB, nach Eintreten eines Fehlerfalls über die Fehlermeldung
  • Verwenden der gleichen Zugangsdaten für CMS und DB
    • dadurch Kompromittierung nicht nur der Datenbank, sondern auch des CMS Systems – obwohl dies eh als kompromittiert gilt, sobald dessen DB kompromittiert ist. Aber Dadurch ist die Webseite noch um einige Faktoren leichter zu manipulieren, insbesondere für unerfahrene Angreifer.

Webanwendungen abzusichern ist nicht immer einfach. Durch die öffentlich zur Verfügung stehenden Informationen und Checklisten kann man aber durch relativ wenig Aufwand zumindest einen passablen Grundschutz erreichen. Organisationen wie die OWASP-Stiftung helfen den Entwicklern und Betreibern von Webseiten sehr. Voraussetzung dabei ist, dass man die Gefahren kennt – und auch die Abwehrmaßnahmen.

Für Softwareentwickler biete ich bei meinem Arbeitgeber EXXETA auf Basis der OWASP Top-10 eine zweitätige Secure Coding Schulung an, bei der wir ausführlich jeden einzelnen der 10 Punkte besprechen, Übungen dazu durchführen, sowie deren Präventionen erläutern, damit Fälle wie dieser nicht passieren, zumindest nicht an der eigenen Webanwendung. Darüber hinaus bieten wir an, unser Wissen im Feld der IT-Security zu teilen, um Anwendungen auf ihre Sicherheit hin zu überprüfen, sowie nachhaltige Sicherheit in den Softwareentwicklungsprozess zu bringen.

Datenschutz
Ich, Bernhard Hirschmann (Wohnort: Deutschland), verarbeite zum Betrieb dieser Website personenbezogene Daten nur im technisch unbedingt notwendigen Umfang. Alle Details dazu in meiner Datenschutzerklärung.
Datenschutz
Ich, Bernhard Hirschmann (Wohnort: Deutschland), verarbeite zum Betrieb dieser Website personenbezogene Daten nur im technisch unbedingt notwendigen Umfang. Alle Details dazu in meiner Datenschutzerklärung.