Java Magazin   3.2024 - Cloud-Exit

Preis: 9,80 €

Erhältlich ab:  Februar 2024

Umfang:  100

Autoren / Autorinnen: 
Marius Nied ,  
Tam Hanna ,  
Torsten Bøgh Köster ,  
Robin de Silva JayasingheMichael HofmannFalk SippachWolfgang WeigendGeorg BerkyIngo Küper ,  
Elena Bochkor ,  
Christian Wörz ,  
Matthias KochThomas Kloppe ,  
Boris Fresow ,  
Michael Simons ,  
Yves Fauser ,  
Robin de Silva Jayasinghe ,  
Marco Schulz ,  
Dr. Veikko Krypczyk ,  
Alexandra Windisch ,  
Lars Kölpin-Freese ,  
Nicolai Mainiero ,  
Sandra Parsick ,  
Frank Delporte ,  

In diesem Monat widmen wir uns in unserem Schwerpunkt einem Thema, das im Java Magazin so bisher nicht zur Sprache gekommen ist, und zwar dem Thema Cloud-Exit. Fraglos hat die Cloud-Technologie in den vergangenen Jahren die Art und Weise revolutioniert, wie Unternehmen Daten speichern, verarbeiten und nutzen – auch wenn es in Deutschland, wie unser Leitartikler Torsten Bøgh Köster konstatiert, etwas länger gedauert hat als in anderen Ländern, bis das Konzept Cloud in größerem Stil adaptiert wurde. Und dennoch lässt sich mit Fug und Recht sagen, dass es zu einem Cloud-Hype gekommen ist.

Aber kein Hype ohne Schattenseiten: Über die Begeisterung hinweg – auch wenn es immer außer Frage stand, dass die Cloud-Kosten im Blick behalten werden müssen – verstummte die Frage danach, wie die Kosten sich eigentlich unter on-Prem-Bedingungen gestalten würden. Eben diese Frage und auch die Frage nach einem Cloud-Exit („Wo geht’s hier raus?“) beantworten wir in unserem Leitartikel, der eine Zeitenwende nach dem Cloud-Hype konstatiert – aber dennoch keineswegs die große Relevanz des Themas Cloud auch in der Zukunft in Frage stellt.

Doch das ist natürlich bei weitem nicht alles, was diese Ausgabe Ihnen zu bieten hat! Zunächst wäre da vor allem unser Expertencheck: Nachdem das Jahr 2023 mit Java 21 einen LTS-Release voller Highlights zu bieten hatte, ist es mehr als nachvollziehbar, dass unsere Experten dazu, aber auch zu anderen Entwicklungen unserer Branche einiges zu sagen haben. Passend zu Java 21 vertieft Christian Wörz in seinem Artikel zu Virtual Threads, die er als nichts Geringeres als einen Quantensprung bezeichnet, unser Wissen zu diesem Thema, und auch Boris Fresow nimmt sich in seinem Beitrag Project Loom und den Virtual Threads an.

Nicolai Mainiero wiederum geht in seinem Artikel auf das Webframework Hilla ein, das das Versprechen in sich trägt, nie wieder REST-Endpunkte selbst schreiben zu müssen. Darüber hinaus starten in der aktuellen Ausgabe drei neue Serien zu den Themen „Netzwerkdesigns für Microservices-Architekturen“, zum „Cloud Application Programming Model“ und darüber, wie Automatisierungen dabei helfen können, die eigene Software auf dem neuesten Stand zu halten.

Wer angesichts dieser Fülle wider Erwarten den Ausgang sucht und die eingangs gestellte Frage trotzdem beantwortet haben möchte, der sei mit der in unserem Fall recht einfachen Antwort beschieden: hinter dem Impressum.

Auf dem Weg dorthin wünschen wir Ihnen wie immer eine informative Lektüre mit hoffentlich hohem Erkenntnisgewinn.

Das Einschleusen von Schadcode über eine fremde Domäne lässt sich mit einer Content Security Policy (CSP) erheblich einschränken. Erfahren Sie, wie Sie Ihre Webapplikation gegen Cross-site-Scripting-(XSS-)Attacken härten können.

Formulare in Webapplikationen sind für so manche Hackerattacke ein geeignetes Einfallstor. Ganz gleich, ob es ein Angriff auf die Datenbank mit einer SQL Injection ist, oder ob schädliches JavaScript per XSS [1] nachgeladen und zur Ausführung gebracht wird.

Gefahr durch Eingaben

Sicherlich ist der erste und wichtigste Schritt, sämtliche Variablen, die durch Formularfelder befüllt werden, auf eine gültige Eingabe hin zu prüfen. Ein gängiges Mittel ist die Validierung über reguläre Ausdrücke, die sicherstellen, dass nur gültige Zeichen und ein korrektes Format zugelassen werden. Möchte man aber beispielsweise formatierte und umfangreiche Artikel ermöglichen, wie es bei einem Content-Management-System der Fall ist, haben die gängigen Schutzmaßnahmen durchaus ihre Schwächen. Denn das Prinzip, möglichst die Eingabe zu beschränken und gefährliche Zeichen herauszufiltern, hat bei formatiertem Text seine Grenzen.

Wollen wir beispielsweise ein Zitat in Anführungszeichen setzen, können wir die beiden Zeichen und nicht einfach aus dem Text entfernen, da diese ja Bestandteil des Inhalts sind. In der Vergangenheit nutzte man bei dieser Problematik einen zusätzlichen Mechanismus, um Schutz vor Cyberangriffen sicherzustellen. Hierfür werden sämtliche kritische Zeichen wie spitze Klammern, Anführungszeichen und Backslashes über ihre HTML Escapes ersetzt. Damit gelten diese als problematisch klassifizierten Sonderzeichen nicht mehr als Quellcode, da aus > ein &gr; wird. Daher sind die soeben beschriebenen Maßnahmen besonders wirkmächtig und bieten bereits einen effektiven Schutz.

Die Schutzwirkung lässt sich allerdings über den Mechanismus CSP erheblich verbessern, da dieser weit über das Prüfen von Nutzereingaben hinausgeht. Sämtliche in einer Webapplikation geladene Ressourcen wie Bilder, CSS und JavaScript lassen sich dank dieser Technologie steuern.

Die Content Security Policy ist ein Projekt des W3C und greift als Bestandteil des Browsers – es sind keine zusätzlichen Plug-ins oder Ähnliches zu installieren. Für aktuelle Browser gilt CSP Level 3. Auf der entsprechenden Webseite des W3C [2] finden Sie eine vollständige Übersicht aller Versionen einschließlich der unterstützenden Webbrowser.

In Umgebungen, die erhöhte Sicherheitsanforderungen erfordern, beispielsweise Onlinebanking, kann die Browserversion des Clients abgefragt werden und bei erheblich veralteten Varianten des Browsers somit der Zugriff verweigert werden.

Listing 1: Auslesen der Browserversion

String userAgent = request.getHeader("user-agent");
String browserName = "";
String  browserVer = "";
if(userAgent.contains("Chrome")){
  String substring=userAgent.substring(userAgent.indexOf("Chrome")).split(" ")[0];
  browserName=substring.split("/")[0];
  browserVer=substring.split("/")[1];
} else if(userAgent.contains("Firefox")) {
  String substring=userAgent.substring(userAgent.indexOf("Firefox")).split(" ")[0];
  browserName=substring.split("/")[0];
  browserVer=substring.split("/")[1];
}

Listing 1 zeigt die Möglichkeit, über den request die Identifikation des Browsers auszulesen. Anschließend demonstrieren die beiden Beispiele, wie die Versionsnummer aus dem Text für Chrome und Firefox extrahiert wird. Bei dieser Strategie sollte man sich aber bewusst sein, dass es für Schwindler recht einfache Möglichkeiten gibt, die Nutzung eines anderen Browsers vorzugaukeln.

Damit wird uns noch einmal vor Augen geführt, dass Web Application Security als ganzheitliches Konzept zu verstehen ist, in dem mehrere Maßnahmen als Verbund wirken – denn einzelne Techniken lassen sich durchaus umgehen. Schauen wir uns daher nun den Wirkmechanismus von CSP im Detail an.

Beginnen wir mit einer reinen HTML-Ausgabe, die CSS, Google Fonts, CDN JavaScript, ein YouTube iFrame und Grafiken enthält. Listing 2 dient uns als Ausgangspunkt, ohne den Einsatz von CSP.

Listing 2: HTMP Seite ohne CSP

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    
    <title>Content Security Policy Demo</title>
    
    <link rel="stylesheet" href="style.css" />
    
    <link
      href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
      rel="stylesheet"
    />
    
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
      integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
      crossorigin="anonymous"
    />
  </head>

  <body>
    <main>
      <div class="box">
        <div id="vue"></div>
      </div>

      <div class="box">
        <div class="embed">
          <iframe width="100%" height="500px" frameborder="0"
            src="https://www.youtube.com/embed/3nK6rcAbuzo"
            allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
            allowfullscreen></iframe>
        </div>
      </div>

      <div class="box">
        <div class="grid">
          <img src="https://images.unsplash.com/photo-1535089780340-34cc939f9996?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80" />
          <img src="https://images.unsplash.com/photo-1587081917197-95be3a2d2103?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=80" />
          <img src="https://images.unsplash.com/photo-1502248103506-76afc15f5c45?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80" />
        </div>
      </div>
    </main>

    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js"></script>
    <script nonce="rAnd0m">
      new Vue({
        el: '#vue',
        render(createElement) {
          return createElement('h1', 'Hello World!');
        },
      });
    </script>
  </body>
</html>
schulz_csp_1

Abb. 1: HTML ohne CSP

Wie wir in Abbildung 1 sehen können, handelt es sich hierbei um eine einfache HTML-Seite, die verschiedenen Content lädt. Dazu gehört zum Beispiel auch, das JavaScript-Framework Bootstrap extern über das Content Delivery Network (CDN) jsDelivr zu laden. Wer mit dem Thema CDN noch nicht vertraut ist, findet dazu einen sehr informativen Artikel auf Wikipedia [3]. Stellen wir uns nun einmal ein realistisches Szenario aus der Praxis vor.

Es könnte nun sein, dass die von uns verwendete Bootstrap-Bibliothek eine bekannte Sicherheitslücke für XSS-Angriffe enthält. Der Content des CDN von jsDelivr ist durchaus vertrauenswürdig. Ein Angreifer könnte nun aber versuchen, von einem Webspace eine eigens präparierte JavaScript-Datei über die Bootstrap-Sicherheitslücke einzuschleusen. Ich möchte an dieser Stelle natürlich kein Hackertutorial an die Hand geben und erklären, wie ein solcher Angriff ausgeführt werden kann; ebensowenig möchte ich Ideen verbreiten, welcher Unfug sich über XSS anstellen lässt. Mir geht es darum, eine zuverlässige Methode vorzustellen, die den Angriff wirkungsvoll verhindern kann. Also richten wir unser Augenmerk nun auf die Prävention von XSS.

Schutz durch CSP

Mittels CSP werden nun Meta-Header-Attribute gesetzt, mit denen bestimmt werden kann, was zuverlässige Quellen sind. Das erlaubt es jedem Contenttyp (Ressource, also Bild, CSS und so weiter), explizite, vertrauenswürdige Quellen (Domains) zuzuweisen. Damit lassen sich JavaScript-Dateien so einschränken, dass sie nur vom eigenen Server geladen werden und beispielsweise von CDN jsDelivr. Findet ein Angreifer nun einen Weg, eine XSS-Attacke auszuführen, bei der er versucht, von einer anderen Domain als von den erlaubten Domains Schadcode einzuschleusen, blockiert CSP das Skript von der nicht freigegebenen Domain.

Dazu ein einfaches Beispiel: Wenn wir im <head> in Listing 2 gleich nach dem meta-Tag für die Seitencodierung die Zeile <meta http-equiv="Content-Security-Policy" content="default-src 'self'" /> einfügen und die Datei ausführen, bekommen wir eine Ausgabe wie in Abbildung 2.

schulz_csp_2

Abb. 2: Blocked Content

Der Teil content="default-src 'self'" sorgt dafür, dass sämtliche Inhalte, die nicht von der eigenen Domäne stammen, über CSP im Browser blockiert werden. Wollen wir zusätzlich für JavaScript das jsDelivr CDN zulassen, müssen wir den meta-Tag wie in folgt formulieren:

<meta http-equiv="Content-Security-Policy"
  content="default-src 'self';
  script-src 'nonce-rAnd0m' https://cdn.jsdelivr.net; />

Auf der offiziellen Webseite für Content Security Policy [4] finden Sie eine vollständige Auflistung sämtlicher Attribute und eine umfangreiche Liste an Beispielen. So bewirkt der Ausdruck nonce-rAnd0m dass Inline-Skripte geladen werden dürfen. Dazu muss das zugehörige JavaScript mit dem Attribut <script nonce="rAnd0m"> gekennzeichnet werden. Damit unser Beispiel aus Listing 2 vollständig funktioniert, benötigen wir für den CSP-meta-Tag folgenden Eintrag (Listing 3).

Listing 3: Vollständige Definition der CSP Ressourcen

<meta http-equiv="Content-Security-Policy"
  content="default-src 'self';
  script-src 'nonce-rAnd0m' https://cdn.jsdelivr.net;
  img-src https://images.unsplash.com;
  style-src 'self' https://cdn.jsdelivr.net;
  frame-src https://www.youtube.com;
  font-src https://fonts.googleapis.com;" />

Für Java-Webapplikationen können die Headerinformationen zu den Beschränkungen der CSP über den response hinzugefügt werden. Die Zeile response.addHeader ("Content-Security-Policy", "default-src 'self'"); bewirkt wie zu Beginn, dass sämtliche Inhalte, die nicht von der eigene Domäne stammen, blockiert werden.

Zentrale Regelung über Servlet-Filter

Nun ist das applikationsweite manuelle Hinzufügen von CSP-Regeln für jede eigene Seite recht mühselig und zudem noch sehr fehleranfällig. Eine zentrale Lösung für den Einsatz von Java-Servern ist die Verwendung von Servlet-Filtern (Listing 4).

Listing 4: CSP-Servlet-Filterklasse

public class CSPFilter implements Filter {

  public static final String POLICY = "default-src 'self'";

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  throws IOException, ServletException {
    if (response instanceof HttpServletResponse) {
      ((HttpServletResponse)response).setHeader("Content-Security-Policy", CSPFilter.POLICY);
    }
  }

  @Override
  public void init(FilterConfig filterConfig) throws ServletException { }

  @Override
  public void destroy() { }
}

Um den Filter dann zum Beispiel im Apache Tomcat zu aktivieren, wird noch ein kleiner Eintrag in der web.xml benötigt (Listing 5).

Listing 5: Aktivierung des Filters

<filter>
  <filter-name>CSPFilter</filter-name>
  <filter-class>com.content-security-policy.filters.CSPFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>CSPFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Sicher könnte man für sämtliche Applikationen in einem vorgeschalteten Proxyserver wie dem Apache-2-HTTP-Server oder NGNIX alle CSP-Regeln zentral verwalten. Davon ist allerdings aus zwei Gründen abzuraten: Zum einen verlagert sich so die Verantwortlichkeit von der Entwicklung hin zum Betrieb, was zu erhöhtem Kommunikationsaufwand und einem Flaschenhals in der Entwicklung führt. Zum anderen werden die so entstehenden Regeln sehr komplex und entsprechend schwieriger zu lesen beziehungsweise zu warten. Der hier vorgeschlagene Servlet-Filter ist daher eine gute Option, um die Sicherheitsregeln applikationsweit zentral für exakt die entwickelte Anwendung zu verwalten. Zudem passt das auch hervorragend in ein agiles DevOps-Konzept, denn die notwendige Konfiguration ist Bestandteil des Source Codes und über die Versionsverwaltung unter Konfigurationsmanagement zugänglich.

Fazit

Wie ich in diesem Artikel zeigen konnte, ist das Thema Web-Application-Security nicht immer gleich ein Fall für Spezialisten. Persönlich empfinde ich es als eine große Errungenschaft der letzten Jahre, wie das Härten von Webanwendungen kontinuierlich einfacher wird. CSP halte ich auf diesem Weg für einen Schritt in die richtige Richtung. Natürlich gilt es weiterhin, stets ein Auge auf aktuelle Entwicklungen zu haben, denn die bösen Buben und Mädels ruhen sich nicht auf ihren Lorbeeren aus und lassen sich ständig neue Gemeinheiten einfallen. Der gerade populär gewordene breite Einsatz von künstlichen neuronalen Netzen wie ChatGPT lässt im Moment nur grob erahnen, was uns künftig noch an Cyberangriffen aus den Tiefen des weltweiten Netzes erwarten wird.