jede Webanwendung - SIGS DATACOM GmbH

Werbung
Schwerpunktthema 
Sicherheit von der Stange
Security-Tools und
-Bibliotheken für (fast)
jede Webanwendung
Dominik Schadow
Für die Entwicklung von Java-Webanwendungen steht eine wahre Flut
von nützlichen kleinen Bibliotheken und umfangreichen großen Frameworks zur Verfügung. Im Bereich der sicheren Entwicklung ist das – wenn
auch in kleinerem Maßstab – nicht anders. Gleichzeitig erleichtern verschiedene frei verfügbare Tools die sichere Entwicklung der Webanwendung und ermöglichen das Testen der umgesetzten Security-Features.
anwendung interagiert oder kommuniziert. Und zwar sowohl
die im Rahmen des Projekts neu entwickelten als auch die bereits vorhandenen Systeme, unabhängig davon, ob diese von
den eigenen Entwicklern oder von einer dritten Partei entwickelt wurden. Neben den üblichen Verdächtigen – Dateneinund -ausgabe durch einen Benutzer im Browser, Speichern der
Daten in einer Datenbank – tauchen dabei häufig noch weitere
Systeme auf: Identity-Management-Systeme, weitere Datenbanken, Webservices und viele andere mehr. Hier gilt es, allen
Datenflüssen zu folgen und in das Threat Model aufzunehmen,
also etwa dem Datenfluss vom Benutzer (Eingabe im Browser)
bis hin zur Speicherung in der Datenbank.
Wichtig sind die in den Datenflüssen passierten Trust Boundaries. Dabei handelt es sich um die Stellen, an denen aus gefährlichen Daten (beispielsweise Benutzereingaben) vertrauenswürdige Daten werden müssen. Das ist etwa notwendig,
wenn die Eingabedaten das Backend erreichen und in der
Datenbank gespeichert werden sollen. Oder wenn die Daten
einer Internetanwendung das Intranet erreichen und damit in
eine neue Vertrauenszone gelangen. An diesen Stellen muss
im Code später zumindest eine Validierung der Eingabedaten
durchgeführt werden.
Neben den weithin bekannten und nahezu allumfassenden großen Frameworks Spring Security [SprintSecurity]
und Apache Shiro [Shiro] existieren noch
zahlreiche häufig sehr spezialisierte Bibliotheken. Diese bieten passende Ergänzungen zu dem einen großen Security-Framework einer Webanwendung an und helfen
bei der Lösung spezieller Anforderungen.
Für die sichere Entwicklung einer Webanwendung sind darüber hinaus Tools notwendig, die Entwickler in allen Phasen des
Projekts sinnvoll unterstützen. Mit dem
Threat Modeling und der Prüfung von
Abhängigkeiten sind das Tools, die bereits
vor beziehungsweise noch nach der Implementierungsphase zum Einsatz kommen.
Im Folgenden vorgeschlagen werden
HMicrosoft Threat Modeling Tool 2014
[ThMT],
HOWASP Java Encoder [JEP],
HKeyczar [Keyczar],
HOWASP Zed Attack Proxy Project [ZAP]
Abb. 1: Threat Model einer Webanwendung
H und OWASP Dependency Check [DeCh].
E
Threat Modeling
Was sich bei der Anwendungsarchitektur mit UML-Diagrammen völlig zurecht
längst durchgesetzt hat, steckt bei der Anwendungssicherheit noch in den Kinderschuhen: die Modellierung. Genauso, wie
ein UML-Diagramm das gemeinsame Verständnis im Entwicklungsteam fördert und
zum Beispiel alle Komponenten oder Packages einer Webanwendung visualisiert,
zeigt ein Threat Model alle beteiligten Systeme und die Datenflüsse zwischen ihnen
aus dem Blickwinkel der Sicherheit.
Ein solches Diagramm (s. Abb. 1) wird
idealerweise zeitgleich mit der UML-Modellierung der Architektur erstellt, in jedem
Fall aber vor Beginn der Implementierung.
Im Threat Model enthalten sind alle Systeme, mit denen die zu entwickelnde Web8
Abb. 2: Microsoft Threat Modeling Tool 2014
JavaSPEKTRUM 6/2015

Schwerpunktthema
Ein für das Threat Modeling gerade auch für Java-Anwendungen sehr gut geeignetes Tool ist das Microsoft Threat Modeling Tool 2014 (s. Abb. 2). Mit diesem kostenlosen Tool können
nicht nur Threat Models erstellt werden. Zusätzlich listet die
Anwendung anhand der eingefügten Entity auch typische
Bedrohungen auf, die bei der Entwicklung entsprechend
berücksichtigt werden müssen. Bei einer Datenbank-Entity
ist eine typische Bedrohung etwa die allseits bekannte SQLInjection. Auch wenn die im Tool aufgeführten Bedrohungen
nicht immer exakt zur eigenen Webanwendung passen und
verständlicherweise nicht auf die Java-Besonderheiten eingehen, erhält man dennoch einige hilfreiche Vorschläge auf
mögliche Gefahren.
Je nach Komplexität der Anwendung werden ein oder mehrere dieser Threat Models erstellt (z. B. ein Übersichtsdiagramm und mehrere detaillierte Einzeldiagramme). Mindestens ein solches Diagramm ist zwingende Voraussetzung, um
eine Webanwendung von innen heraus sicher zu entwickeln.
Nur mit einem genauen Überblick über die Datenflüsse, die
beteiligten Systeme und den Trust Boundaries ist es möglich,
sichere Anwendungen zu entwickeln.
Eine umfangreiche Einführung in das Thema Threat Modeling findet sich in [Sho14].
Output Escaping
Mit dem nun verfügbaren Threat Model besitzen alle Entwickler ein genaues Verständnis der Webanwendung. Jetzt gilt es –
neben der Validierung aller eingehenden Daten –, die zur Anzeige im Webbrowser bestimmten ausgehenden Daten zu „escapen“. Dieses Output Escaping (auch Output Encoding) ist notwendig, um die Ausführung von eingeschleustem Code zu
verhindern. Gibt ein Angreifer beispielsweise
<script>alert(document.cookie)</script>
ein und wird dabei nicht von der Eingabevalidierung aufgehalten, führt der Browser nach Verarbeitung der Response diesen
Code mit dem Rest der Webanwendung aus. Auch wenn das
in Abbildung 3 gezeigte Popup-Fenster in dieser Form einem
Angreifer nichts nützt, zeigt es ihm doch, dass die Webanwendung anfällig für Cross-Site-Scripting (XSS) ist und zusätzlich
zur Ausführung des Codes die Session ID des angemeldeten
Benutzers verrät.
XSS hat meist die
Erbeutung der in
Abbildung 3 sichtbaren Session ID eines
Benutzers zum Ziel.
Damit kann ein Angreifer
gegenüber
der Webanwendung
vorgeben, dieser Benutzer zu sein. EbenAbb. 3: Mit XSS ausgelöstes JavaScript-Popup
so kann XSS zum
simplen Verunstalten
einer Webseite (website defacement) eingesetzt werden. Häufig
dient XSS aber als Türöffner für ausgefeiltere Angriffe und
macht diese erst möglich. Eine Webanwendung muss daher
zwingend vor XSS-Angriffen geschützt sein.
Das zugrunde liegende Problem von XSS ist, dass der Browser sämtlichen Code ausführt. Das vom Entwickler eigentlich
erwartete und gewünschte Verhalten ist allerdings die Anzeige
aller Benutzereingaben als normalen Text. Mittels Output Escaping lässt sich nun genau dieses Verhalten erzwingen. Damit
www.javaspektrum.de
stellt das Output Escaping die Gegenmaßnahme Nummer eins
gegen XSS dar.
Komplizierter wird das Output Escaping durch die notwendige Unterscheidung der Kontexte, zum Beispiel HTML, CSS,
URI oder JavaScript. Der HTML-Kontext stellt dabei den verbreitetsten Kontext dar. Dabei werden die vom Benutzer (oder
Angreifer) eingegebenen Daten im HTML-Bereich der Webseite eingefügt. Beim Output Escaping für diesen Kontext ist dazu
unter anderen die bekannte Umwandlung von < und > in <
und > notwendig. Damit zeigt der Browser selbst Code nur
als Text an und führt diesen nicht aus.
Diese Umwandlung mag einfach klingen, ist es in Wirklichkeit aber nicht. Durch Verwendung von Encodings kann ein
Angreifer etwa eingegebenen Code selbst maskieren, oder etwa mit JavaScript-Substring-Befehlen aus einem sinnlosen Text
einen gefährlichen Angriffscode zusammensetzen. Der Einsatz
einer Output-Escaping-Bibliothek mit Unterstützung verschiedener Kontexte ist daher zwingend notwendig.
Herausragend einfach in der Verwendung und gleichzeitig
sehr sicher ist der OWASP Java Encoder. Diese kleine Bibliothek
besitzt keine weiteren Abhängigkeiten und kann ohne Probleme in die eigene Webanwendung integriert werden. Listing 1
zeigt zwei Escapings für die Kontexte HTML und HTML-Attribut und die daraus resultierende sichere (da escapte) Ausgabe.
try (PrintWriter out = response.getWriter()) {
// ...
out.println("<body>");
out.println("<p title='Hello " +
Encode.forHtmlAttribute(name) + "'>Hello ");
Encode.forHtml(out, name);
out.println("</p>");
// ...
} catch (IOException ex) { }
Listing 1: Escaping für HTML und HTML-Attribute
Der Entwickler hat somit nur die Aufgabe, den richtigen
Kontext zu bestimmen und sämtliche Benutzereingaben vor
der Rückgabe an den Browser sicher zu escapen. Wie in Listing 1 gezeigt, bedeutet das bei der Mehrfachverwendung einer Benutzereingabe in verschiedenen Kontexten, dass diese
für den jeweiligen Kontext erneut escaped werden muss. Die
Verwendung eines falschen Kontexts kann dazu führen, dass
zumindest Teile der Eingabedaten nicht korrekt escaped und
vom Browser eventuell dennoch ausgeführt werden.
Kryptografie
Kryptografie ist ein komplexes Thema und bei Verwendung
von plain Java in der Umsetzung alles andere als einfach. Mit
Keyczar steht deswegen eine Bibliothek zur Verfügung, mit der
die Anwendung kryptografischer Operationen – Verschlüsseln, Entschlüsseln, Signieren und Verifizieren – deutlich einfacher wird. Mit Keyczar nimmt man dabei bewusst eine wichtige Einschränkung in Kauf: mit aktuell AES, HMAC-SHA1,
DSA und RSA stehen vergleichsweise wenige Algorithmen zur
Verfügung. Gleichzeitig sind für diese aber sichere Defaultwerte hinterlegt, sodass außer der Entscheidung für einen Algorithmus nichts weiter konfiguriert werden muss (diese Defaultwerte lassen sich bei Bedarf überschreiben).
Wo bei Java üblicherweise das Java KeyTool und der Java KeyStore verwendet werden, setzt Keyczar mit dem KeyczarTool
und den damit generierten Key Sets ebenfalls auf eigene Konzepte. So werden Schlüssel (Keys) und Schlüsselspeicher (Key
9
Schwerpunktthema 
Sets) im JSON-Format gespeichert und haben immer nur eine
einzige kryptografische Aufgabe: Verschlüsseln (und logischerweise Entschlüsseln) oder Signieren (und logischerweise Verifizieren), und sind dabei entweder symmetrisch oder asymmetrisch. Ein Key Set hat so eine exakt bestimmte Aufgabe und
speichert nur Schlüssel dieses einen Typs.
Crypter crypter = new Crypter("key-sets/encrypt/rsa");
String ciphertext = crypter.encrypt(initialText);
String plaintext = crypter.decrypt(ciphertext);
Listing 2: Asymmetrisches Ver- und Entschlüsseln mit Keyczar
Wie in Listing 2 zu sehen, ist auch das Ver- und Entschlüsseln
im Code mit Keyczar sehr einfach.
Soll aus dieser asymmetrischen Verschlüsselung mit RSA eine symmetrische mit AES werden, genügt es, den Key-Set-Pfad
im Crypter-Konstruktor entsprechend auf das passende Key Set
anzupassen. Der Aufruf der Ver- und Entschlüsselungsmethoden im restlichen Code bleibt identisch. Für digitale Signaturen
existieren entsprechend die Klassen Signer und Verifier.
Gleichzeitig vereinfacht Keyczar die Schlüsselverwaltung.
Wie Passwörter sollten auch Schlüssel regelmäßig ausgetauscht werden. Eine Anforderung ist dabei häufig, dass die
bisherigen Schlüssel für die Entschlüsselung alter Nachrichten weiterhin passiv vorgehalten werden müssen. Für aktive
Operationen wie dem Verschlüsseln oder Signieren neuer
Nachrichten sollen allerdings nur noch die neuen Schlüssel
verwendet werden.
Hierzu unterstützt Keyczar die Schlüsselversionierung. In
jedem Key Set können beliebig viele Schlüsselversionen vorliegen. Solange sie aktiv sind, können sie etwa für das Entschlüsseln herangezogen werden. Aktive Operationen werden
immer nur mit dem als Primary gekennzeichneten Schlüssel
durchgeführt.
Testen
Eine typische Webanwendung ist zu diesem Zeitpunkt umfassend gesichert. Die Eingabevalidierung verhindert das Übertragen potenziell gefährlicher Daten, das Output Escaping
macht dennoch eingefügten Code unschädlich. Das Problem
ist nun, dass die Entwickler diese Sicherheitsmaßnahmen nicht
mehr alle testen können. Bereits bei der Eingabe etwa eines
script-Tags lehnt der Browser die ungültigen Daten ab. Getestet – vor allem in Bezug auf die Sicherheit – ist damit außer der
leicht umgehbaren Frontend-Validierung allerdings noch überhaupt nichts.
Damit das Backend nun dennoch mit ungültigen Daten in
Berührung kommt, ist die Verwendung eines Intercepting Proxy
notwendig. Dieses Tool hängt sich als Proxy zwischen den eigenen Browser und die eigene(!) Webanwendung und ermöglicht das Abfangen und Manipulieren aller Requests und Responses zwischen diesen beiden Endpunkten. Da solche Tools
durchaus auch für Angriffe verwendet werden können, ist ihr
legaler Einsatz auf die eigene Webanwendung (idealerweise
auf dem eigenen Rechner) oder auf genehmigte Webanwendungen begrenzt.
Ein auch für Entwickler gut geeigneter Intercepting Proxy
ist OWASP ZAP. In den Browsereinstellungen wird dieses
Tool zunächst als Proxy konfiguriert. Anschließend können
in ZAP Requests und Responses nach Belieben abgefangen
und manipuliert werden. Dieses Abfangen funktioniert per
Breakpoint, analog zu den Debugging-Breakpoints in einer
Entwicklungsumgebung. So lassen sich aus gültigen und im
Browser validierten Daten ungültige und gefährliche Daten
machen. Abbildung 4 zeigt OWASP ZAP beim Anfangen eines Requests.
Die Security-Features des Backends können somit direkt
getestet werden. Anschließend kann ZAP auch die Response
abfangen und ermöglicht die Manipulation dieser, bevor die
Daten im Browser angezeigt werden. Hiermit lässt sich etwa
testen, wie ein Browser auf vermeintlich escapte Daten reagiert.
Neben diesen Intercepting-Fähigkeiten bietet ZAP noch sehr
viel mehr Features. Unter anderen lassen sich alle erreichbaren Seiten einer Webanwendung auflisten und deren Requests
und Responses im Detail untersuchen. Nach dieser notwendigen Voruntersuchung kann der nächste Schritt darin bestehen,
die in Requests enthaltenen Parameterwerte mit bekannten
Angriffsmustern auszutauschen und die Webanwendung beispielsweise per Cross-Site-Scripting der SQL-Injection anzugreifen.
Aktuell bleiben
Abb. 4: Request-Interception mit OWASP ZAP
10
Ein besonders bei Java-Anwendungen
verbreitetes Problem ist das Veralten der
in der Webanwendung eingesetzten Bibliotheken. Webanwendungen beinhalten häufig 15, 20 oder mehr fremde Bibliotheken und lagern dabei mitunter auch sicherheitskritische Aufgaben an diese aus.
Umso wichtiger, diese Bibliotheken aktuell zu halten und bei bekannt gewordenen
Sicherheitsproblemen schnell zu reagieren. Und zwar unabhängig davon, ob es
sich um eine sicherheitsrelevante Bibliothek oder nur um eine Utility-Bibliothek
handelt.
Für diese Aufgabe hervorragend geeignet ist OWASP Dependency Check. Dieses
Tool scannt alle in einer Webanwendung
enthaltenen Bibliotheken und vergleicht
die identifizierten Bibliotheken mit in
JavaSPEKTRUM 6/2015

Schwerpunktthema
Fazit
Gerade bei der Implementierung von sicherheitskritischen Features ist es wichtig, das Rad nicht selbst neu zu erfinden, sondern
auf bewährte Security-Frameworks und -Bibliotheken zu setzen.
Ein umfassendes Threat Modeling vor Beginn der Implementierung stellt sicher, dass diese Bibliotheken an den richtigen Stellen
eingesetzt werden. Anschließende Tests mit einem Intercepting
Proxy helfen, umgesetzte Sicherheits-Features zumindest teilweise zu umgehen, und ermöglichen es so, auch das geschützte System mit gefährlichen Eingaben anzugreifen. Werden dann sämtliche eingesetzten Bibliotheken stets aktuell gehalten, ist schon viel
für die Sicherheit einer typischen Webanwendung gewonnen.
Alle im Artikel verwendeten Code-Beispiele sind im GitHubRepository des Autors (vgl. [GitHub]) verfügbar.
Literatur und Links
Abb. 5: Dependency-Check-Report
[DeCh] OWASP Dependency Check,
https://www.owasp.org/index.php/OWASP_Dependency_Check
[GitHub] JavaSecurity Repository,
der National Vulnerability Database gelisteten bekannten Verwundbarkeiten. Dazu wird Dependency Check entweder per
Maven-Konfiguration ins Projekt integriert oder per manuellem Aufruf über die Kommandozeile gestartet:
https://github.com/dschadow/JavaSecurity
[JEP] OWASP (Open Web Application Security Project) Java
Encoder Project,
https://www.owasp.org/index.php/OWASP_Java_Encoder_Project
[Keyczar]
dependency-check.sh --app JavaSecurity --scan target/dependency
Mit diesem Aufruf wird ein HTML-Report mit identifizierten
Bibliotheken generiert (s. Abb. 5).
Diese Liste ist nicht frei von false positives. Nicht jeder Eintrag bedeutet daher gleich eine verwundbare Bibliothek in der
eigenen Webanwendung. Zweifelsfreie false positives lassen
sich per XML-Konfiguration in zukünftigen Scans ignorieren.
Bei korrekt erkannten Verwundbarkeiten ist der Entwickler gefordert, die verwundbare Bibliothek zeitnah gegen eine neue
Version auszutauschen und die Webanwendung mit der neuen
Version zu testen.
Als nächsten Schritt empfiehlt sich die Integration des Dependency Checks in den Jenkins Build. So kann automatisch
nach jedem erfolgreichen Build ein Scan aller Abhängigkeiten
durchgeführt werden. Neben dem HTML-Report wird für
Jenkins zusätzlich ein Graph generiert, mit dem alle Entwickler auf einen Blick die Anzahl der verwundbaren Bibliotheken erkennen können. Mittels Grenzwerten lässt sich konfigurieren, ab wann ein Build instabil wird oder auch ganz
fehlschlägt.
www.javaspektrum.de
oder https://github.com/google/keyczar
[Shiro] http://shiro.apache.org
[Sho14] A. Shostack, Threat Modeling, Wiley, 2014
[SpringSecurity] http://projects.spring.io/spring-security
[ThMT] Microsoft SDL (Security Development Lifecycle)
Threat Modeling Tool, 2014,
http://www.keyczar.org
http://www.microsoft.com/en-us/sdl/adopt/threatmodeling.aspx
[ZAP] OWASP Zed Attack Proxy Project,
https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project
Dominik Schadow arbeitet als Senior Consultant
beim IT-Beratungsunternehmen bridgingIT. Er ist spezialisiert auf die Architektur und Entwicklung von Java-Enterprise-Applikationen, Enterprise Application Integration
(EAI) und die sichere Softwareentwicklung mit Java.
E-Mail: [email protected]
11
Herunterladen