Alle Neuerungen auf einen Blick

Apache Tomcat 8.5: Das gibts Neues!

Frank Pientka

Um Applikationsserver im Allgemeinen und damit auch um Apache Tomcat ist es etwas ruhiger geworden. Die kommende Java-EE-8-Version bietet die Gelegenheit, auf Neuerungen und bisher verborgen gebliebene Änderungen bei Apache Tomcat einzugehen.

Seit Jahrzehnten gilt der Apache Tomcat als treuer Begleiter beim Entwickeln von Webanwendungen mit Java. Dabei erfüllt er die gestiegenen Anforderungen an einen modernen Webapplikationsserver, wie Skalierbarkeit, Integrierbarkeit, Ausfallsicherheit, Sicherheit, Bedienbarkeit und Überwachbarkeit.

Abb. 1: Anforderung an einen Webapplikationsserver

Nachdem die am meisten verbreitete 6er-Version Ende letzten Jahres in Rente geschickt wurde, arbeiten die Committer verstärkt an der 8.5er-Version. Sie ersetzt die bisherige 8er-Version und enthält, wie die Nummer andeutet, auch einige funktionale Erweiterungen aus der noch in der Entwicklung befindlichen 9er-Version. Erst die Version 9 wird die für die Webentwicklung relevanten Java-EE-8-Standards Servlet 4.0, JSP 2.4, EL 3.1 und WebSocket 1.2 enthalten. Der JASPIC-1.1-Standard wird bereits in Apache Tomcat 8.5 unterstützt. Als minimale Java-Version wird eine Runtime der Version 7 oder höher benötigt. Die unterstützten Spezifikationen sind in Tabelle 1 dargestellt.

JRE JSP Servlet EL WebSocket JSAPIC JDBC HTTP
Tomcat 8.5.x 1.7 2.3 3.1 3.0 1.1 1.1 4.1 1.x
Tomcat 9.0.x 1.8 2.4 4.0 3.1 1.2 1.1 4.1 1.x

Tabelle 1: Die unterstützten Standards für die Apache-Tomcat-Versionen 8.5.x und 9.0.x

Neben den aktuellen Java-Standards wurden die Connectors und die SSL-Konfiguration umgebaut, um die leistungsfähigen nichtblockierenden Verbindungen sicher über das HTTP/2-Protokoll anbieten zu können. Wegen der Verzögerungen von Java EE 8 entschied das Tomcat-Team, einige bereits fertige Verbesserungen in die 8er-Version einfließen lassen und deshalb die Versionsnummer auf 8.5 hochzusetzen. Eine dieser Neuerungen ist die Unterstützung des Java Authentication Service Provider Interface for Containers (JASPIC). Damit ist es z. B. möglich, zusätzliche Authentifizierungsprovider einzubinden. Sie müssen nur die JAR-Datei des GoogleOAuthServerAuthModule (SAM) in das $CATALINA_BASE/lib-Verzeichnis kopieren und $CATALINA_BASE/conf/jaspic-providers.xml ergänzen.

<provider name="google-oauth"
className="org.apache.catalina.authenticator.jaspic.SimpleAuthConfigProvider" layer="HttpServlet"
appContext="Catalina/localhost /contextPath"
description="Google OAuth test">
<property name="org.apache.catalina.authenticator.jaspic.ServerAuthModule.1" value="com.idmworks.security.google.GoogleOAuthServerAuthModule" />
<property name="oauth.clientid"
  value="obtained-from-Google-console" />
<property name="oauth.clientsecret"
 value="obtained-from-Google-console" />
<property name="ignore_missing_login_context"
  value="true" />
</provider>

Wie bisher, benötigt Tomcat 8.5 eine Java-Runtime-Umgebung, mindestens Version 7. Für 32-Bit-/64-Bit-Windows wird bereits die passende DLL- und OpenSSL-Bibliothek mitgeliefert. Es wird jedoch kein JULI-Adapter für Log4j 1.x mehr angeboten, da diese alte Version nicht mehr unterstützt wird.

HTTP/2 kommt

HTTP/2 kann man entweder mit Java 9 oder OpenSSL 1.0.2 verwenden. Neben dem ALPN-Protokoll wird dafür von den meisten Browsern eine mit HTTPS verschlüsselte Verbindung verlangt. Des Weiteren wird der Tomcat Native Connector benötigt. Da alle Browser HTTP/2 nur verschlüsselt unterstützen, müssen wir noch ein Zertifikat verwenden. Eine Konfiguration für das HTTP/2-Upgradeprotokoll mit der Apache-Portal-Runtime-Bibliothek (APR) und OpenSSL sieht wie in Listing 2 aus.

<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" maxThreads="150" SSLEnabled="true">
  <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
  <SSLHostConfig honorCipherOrder="true" ciphers"HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA" protocols="TLSv1.2">
  <Certificate certificateKeyPassword="test" certificateKeyFile="bin\key.pem" certificateFile="bin\cert.pem"
  type="RSA" />
  </SSLHostConfig>
</Connector>

Die korrekte Funktionsweise können Sie mit curl –http1.1 –tlsv1.2 -k https://localhost:8443/
testen. Welche Chiffrensammlungen in welcher Reihenfolge verwendet werden, können Sie sich über https://localhost:8443/manager/text/sslConnectorCiphers anzeigen lassen. Dadurch, dass mit Tomcat 8.5 ein neues SSLHostConfig-Element eingeführt wurde, sind die meisten Attribute der folgenden alternativen Konfiguration mit Standard Java Secure Socket Extension (JSSE) identisch (Listing 3).

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" server="Apache"
  maxThreads="150" SSLEnabled="true" scheme="https" secure="true"> 
<SSLHostConfig honorCipherOrder="true" ciphers="HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA" protocols="TLSv1.2"> 
  <Certificate certificateKeystoreFile="conf/.keystore" certificateKeyPassword="changeit"
  type="RSA"  />
    </SSLHostConfig>
</Connector>

Aber sicher!

Um nicht zu viele Informationen preiszugeben und dadurch Angriffe zu erleichtern, sollte die Tomcat-Version nicht im Header oder bei Fehlerseiten angezeigt werden. Dazu setzen Sie bei den verwendeten Connector das Attribut server auf einen festen Text, z. B. auf Apache:

<Connector port="8080" ... server="Apache" />

Um die Weitergabe der Produktversion im Fehlerbericht zu deaktivieren, fügen Sie folgende Valve ein:

<Valve className="org.apache.catalina.valves.ErrorReportValve" showReport="false" showServerInfo="false"/>

Um das Ausspähen der Produktinformation zu vermeiden, sollte man in der Datei ServerInfo.properties die Zeilen mit der server.info=Apache und server.number=0.0.0.0 anpassen. Nach dem Editieren wird die Datei wieder an ihre Ursprungsstelle mit folgenden Schritten gepackt:

cd CATALINA_HOME/server/lib
jar xf catalina.jar org/apache/catalina/util/ServerInfo.properties
vi ServerInfo.properties server.info=Apache server.number=0.0.0.0
jar uf catalina.jar org/apache/catalina/util/ServerInfo.properties

Mit dem Java-8-Update 121 und weiteren für 2017 geplanten Updates werden einige unsichere Verschlüsselungs- oder Hash-Verfahren deaktiviert. So werden SHA-1-Zertifikate ab 2017 in vielen Browsern (IE, Firefox), aber auch in der aktuellen JRE 8 nicht mehr für signierte JARs akzeptiert. In Tomcat sind für TLS mit dem Parameter -Djdk.tls.ephemeralDHKeySize=2048 nur Schlüssel mit einer Länge von mindestens 2048 Byte für den Diffie-Hellman-Algorithmus erlaubt. Zusätzlich kann man mit -Djdk.tls.rejectClientInitiatedRenegotiation=true die Auswirkungen eines DoS-Angriffs mit TLS minimieren.

Passwort bitte!

Lange Zeit konnten in den Tomcat-Konfigurationsdateien Passwörter entweder nur im Klartext oder einfach gehasht verwendet werden. Deswegen haben einige Administratoren die Passwörter zur Laufzeit beim Starten aus einer separaten Datei ausgelesen und in den parametrisierten Feldern ersetzt. Mit der Picketbox-Erweiterung von Red Hat für Tomcat geht das ohne eigene Skripte. Alternativ kann man jetzt auch gesalzene Passwörter verwenden oder statt der einfachen Hash-Verfahren (MD5, SHA1, SHA2) auch Algorithmen, die ein Passwort von einem Schlüssel ableiten, wie PBKDF2 (Password-based Key Derivation Function 2) oder bcrypt. Diese sind sicherer gegenüber Angriffsmethoden mit Passworttabellen. Mit dem von Tomcat mitgelieferten Werkzeug digest kann man gehashte Passwörter erzeugen.

digest.[bat|sh]
Usage: RealmBase [-a <algorithm>] [-e <encoding>] [-i <iterations>] 
[-s <salt-length>] [-k <key-length>] [-h <handler-class-name>] <credentials>

Ein Beispielaufruf für das zu verschlüsselnde Passwort sieht wie folgt aus:

digest -a SHA-256 -i 1 -s 18 -h org.apache.catalina.realm.MessageDigestCredentialHandler Passwort

Um z. B. das Erraten von Passwörtern bei der Tomcat-Manager-Anwendung zu erschweren, kopiert man dann die mit digest erstellten Passwörter in die die tomcat-users.xml-Datei.

<user username="tomcat" password="7a3d31f118f6355fda2c25ef6815777d7529$1$cbe1fde0825b946373491d69f2c46801844a4a93e6586ebd917e29d96a325cab"
roles="manager-status,manager-gui,manager-script"/>

Als Nächstes müssen Sie das verwendete Verfahren im CredentialHandler des entsprechenden Realms bekannt machen, indem Sie in der server.xml-Datei Folgendes eingeben:

<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase">
<CredentialHandler className="org.apache.catalina.realm.MessageDigestCredentialHandler" algorithm="SHA-256" iterations="1" saltLength="18" /> 
</Realm>

Wenn Sie statt des Hash-Verfahrens den bcrypt-Algorithmus verwenden wollen, müssen Sie dazu eine eigene Klasse implementieren, die Sie in der Konfiguration angeben.

<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase">
  <CredentialHandler
    className="my.package.BCryptCredentialHandler"
  logRounds=”12” />
</Realm>

Zu Protokoll bitte!

Um Anmeldeversuche besser überwachen und auditieren zu können, können Sie die Protokolleinstellungen in der logging.properties-Datei um einen weiteren Handler ergänzen. Dieser gibt alle Anmeldeversuche in einer separaten Datei mit dem Präfix auth.yyyy-mm-dd.log aus:

handlers = 1catalina.org.apache.juli.AsyncFileHandler, 5auth.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler

5auth.org.apache.juli.AsyncFileHandler.level = FINE
5auth.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
5auth.org.apache.juli.AsyncFileHandler.prefix = auth.

org.apache.catalina.realm.handlers = 5auth.org.apache.juli.AsyncFileHandler
org.apache.catalina.realm.level = FINE

Standardmäßig kann Tomcat zwar Protokolldateien nach bestimmten Kriterien erstellen, wie dem Tagesdatum. Für eine Rotation der Dateien muss man aber entweder ein externes Werkzeug verwenden oder die Protokollbibliothek austauschen.

Für Log4j 2 müssen Sie die benötigten Log4j-2-Bibliotheken zusammen mit einer log4j2.xml-Datei in den Klassenpfad aufnehmen und Log4j 2 statt JUL als Protokollsystem registrieren. Wichtig ist, dass die Log4j-2-Bibliotheken über die JUL-Bridge direkt geladen wird und deswegen im Klassenpfad und nicht, wie bei Log4j 1 üblich, aus dem lib-Verzeichnis geladen wird (Listing 4).

set CLASSPATH=.;$CATALINA_BASE\bin;$CATALINA_BASE\bin\log4j-core-2.6.2.jar;$CATALINA_BASE\bin\log4j-api-2.6.2.jar;$CATALINA_BASE\bin\log4j-jul-2.6.2.jar"
set JAVA_OPTS=-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager
set LOGGING_CONFIG=-DnoOpp
set LOGGING_MANAGER=-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager

Eine einfache log4j2.xml-Datei sieht dann wie in Listing 5 gezeigt aus.

<Configuration status="warn" name="catalina" packages="">
  <Appenders>
    <Console name="console" target="SYSTEM_OUT">
      <PatternLayout pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"/>
    </Console>
    <File name="catalina" fileName="../logs/catalina.log">
      <PatternLayout>
        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
      </PatternLayout>
    </File>
    <Async name="Async">
      <AppenderRef ref="catalina"/>
    </Async>
  </Appenders>
  <Loggers>
    <Root level="INFO">
      <AppenderRef ref="Async"/>
      <AppenderRef ref="console"/>
    </Root>
  </Loggers>
</Configuration>

Kleinere Verbesserungen

Tomcat 8.5 bringt weitere Verbesserungen bei virtuellen Hosts (TLS, SNI, Zertifikate), IPv6 oder RFC 6265 Cookie Processor mit. Insgesamt wurden die Performance und die Sicherheit weiter optimiert. Bei einem Versionswechsel müssen jedoch einige Dinge angepasst und sollten auch ausgiebig getestet werden. Weitere Informationen zu einer Umstellung finden Sie auf http://tomcat.apache.org (Migration auf Tomcat 8.5, Tomcat 8,5-Änderungen, Tomcat 8,5-Deprecated). Etwas schade ist, dass das Tomcat-Maven-Plug-in wohl bei Tomcat 7 stehen geblieben ist, sodass man hier auf andere Alternativen angewiesen ist.

Abschied muss sein

Nachdem Tomcat sich über die Jahrzehnte kontinuierlich weiterentwickelt hat, ist es mit Tomcat 8.5 und spätestens 9 Zeit, sich von einigen Altlasten zu befreien. Nachdem die Connector-Architektur komplett umgebaut wurde, werden die blockierenden Connectoren BIO HTTP und BIO AJP nicht mehr unterstützt. Gleiches gilt für das nicht standardisierte Comet-Protokoll, das durch den WebSocket-Standard abgelöst wurde. Ebenso wird Log4j 1 nicht mehr unterstützt und deshalb kein Adapter mehr dafür zur Verfügung gestellt.

Die größten Änderungen betreffen die Konfiguration von HTTPS-Verbindungen. Hier haben sich die Attribute für die beiden unterstützten Varianten JSSE und OpenSSL angeglichen. Spätestens mit dem Erscheinen von Java 9 (JEP 229) wird das Java-KeyStore-Format (JKS) durch das auch von OpenSSL verwendete PKCS12-Format (Public Key Cryptography Personal Information Exchange Syntax) ersetzt.

Wer sich für die genauen Abweichungen interessiert, kann sich entweder online [5] die Änderungen der wichtigsten Tomcat-Konfigurationsdateien logging.properties, server.xml, web.xml und context.xml anzeigen lassen oder seine eigenen mit denen einer Neuinstallation vergleichen. Da die neueren Konfigurationsdateien bereits Parameter mit sinnvollen Standardwerten setzen, sollten sie als Basis für eigene Ergänzungen genommen werden, statt immer wieder Konfigurationsdateien mit veralteten Werten zu verwenden.

Fazit

Das Thema Sicherheit und HTTP/2 wird uns auch dieses Jahr weiter begleiten. Deswegen ist jeder gut beraten, hier seine Hausaufgaben beim Betrieb von Webanwendungen zu machen. Durch lange Supportzyklen und gute Abwärtskompatibilität ist ein Wechsel auf die neuste Tomcat-Version ohne große Probleme möglich. Wer von älteren Tomcat-Versionen wechselt, sollte seine Konfigurationen mal entrümpeln [5], da sich inzwischen einige Werte geändert haben und nützliche Erweiterungen für einen sicheren und schnellen Betrieb ergänzt wurden. Vor allem die Nutzer der 6er-Version sollten auf eine neuere Version wie 8.5 wechseln [5], um weiterhin Fehlerkorrekturen zu erhalten. Doch auch die Tage der sehr weit verbreiteten 7er-Version sind spätestens mit dem finalen Erscheinen der Version 9 gezählt.

Apache Tomcat zählt noch lange nicht zum alten Eisen. Selbst wenn andere Applikationsserver inzwischen vom Markt verschwunden sind, so erfreut sich Tomcat erstaunlicher Gesundheit, nicht nur als eingebetteter Webserver bei Microservices. Auch bei Java-Cloud-Anwendungen ist Tomcat als Laufzeitumgebung beliebt. Für Zukunftsthemen, wie asynchrone Verarbeitung, HTTP/2 und Java EE 8 ist er gut vorbereitet.

Verwandte Themen:

Geschrieben von
Frank Pientka
Frank Pientka
  Frank Pientka ist Senior Architect bei der MATERNA GmbH in Dortmund. Er ist seit mehreren Jahren im Bereich Java EE tätig. Seine Schwerpunkte sind Applikationsserver, Portalserver und Datenbanken. Dazu hat er auch schon mehrere Fachartikel und ein Buch über Geronimo veröffentlicht.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.