Zertifikate – warum und wofür
Gegenüber der überwiegend verwendeten Passwort-Authentifizierung bietet die Authentifizierung mit Client-Zertifikaten mehrere Vorteile:- Es gibt keine schwachen Passwörter mehr.
- Die Weitergabe der Login-Information wird erschwert.
- Mit einem Zertifikat kann der Zugang zu vielen Diensten ermöglicht werden (Single Sign-on).
- Diese Form der Authentifizierung lässt sich sehr gut auch auf andere Dienste wie z.B. Web Services übertragen.
Kartenleser Bei der Auswahl von Kartenlesern, Karten und Software für die Einbindung in den Browser ist es ratsam, alles aus einer Hand zu beziehen, um Kompatibilitätsprobleme zu vermeiden. Es gibt verschiedene Klassifikationen von Kartenlesern: Das Mindeste, was ein Kartenleser mitbringen muss, ist eine eigene Tastatur (oft als Kartenleser Klasse 2 bezeichnet), um ein Ausspähen der PIN durch Keylogger o.Ä. auszuschließen. Wird serverseitig ein erneutes Handshake gestartet (z.B. nach Ablauf der Session bei Inaktivität), so ist es nicht selbstverständlich, dass ein Benutzer zur erneuten PIN-Eingabe aufgefordert wird, solange der Browser nicht geschlossen wird. Dieses PIN-Caching birgt im nicht privaten Bereich Sicherheitsrisiken, falls der User den Arbeitsplatz verlässt und weder den Browser schließt noch die Karte aus dem Leser entfernt. Außerdem sollten Browser und Plattformunterstützung beim Hersteller erfragt werden.
Zertifikate – auch für Clients
Im Falle der Kommunikation über HTTPS weist sich das Serversystem gegenüber dem Nutzer mit einem Zertifikat aus. So kann der Nutzer sicher sein, mit dem entsprechenden System, z.B. der Bank, zu kommunizieren. Die Authentifizierung des Nutzers erfolgt dann aber meistens über den so gesicherten Kanal mittels Username und Passwort. Der Server kann auch vom Client verlangen, sich beim Verbindungsaufbau (SSL Handshake) ebenfalls mit einem Zertifikat auszuweisen. Dieses Zertifikat ist idealerweise auf einer Smartcard gespeichert und mit einer PIN geschützt und verlässt so niemals die Karte; vielmehr wird auf dem Kartenleser der SSL-Session-Key signiert.Zertifikate – die Praxis
Zum Entwickeln und Testen werden weder Kartenleser noch Smartcards benötigt: Beteiligt sind ein Browser mit SSL-Client-Zertifikat und ein Application Server (unsere Beispiele beziehen sich auf Tomcat in der Version 5.5.7). Die Umstellung auf den produktiven Einsatz (etwa mit Apache2/mod_ssl/mod_jk und tatsächlichen Kartenlesern) ist dann mit wenigen Handgriffen erledigt. Das Aufsetzen einer CA zu Entwicklungszwecken und die Erzeugung der Zertifikate sind im Textkasten beschrieben. Mit dem Import der CA- und Client-Zertifikate in den Browser ist auf Nutzerseite die Umstellung erledigt. Zum Testen mit mehreren Accounts ist es ratsam, im Browser die Option zu aktivieren, jedes Mal bei der SSL-Authentifizierung nachzufragen, welches Zertifikat vorgewiesen werden soll. Serverseitig müssen erst einmal der HTTPS Connector aktiviert und ein Server-Zertifikat erzeugt werden. Diese beiden Schritte sind in der server.xml des Tomcat und hier erklärt. Damit der Server ein Zertifikat vom Client verlangt, muss die Option clientAuth= „ true „ in der Tomcat-Konfiguration gesetzt werden, sodass die Konfiguration des SSL Connector wie in Listing 1 aussieht. Dann fragt Tomcat das Zertifikat ab.Programmatische vs. deklarative Sicherheit
Deklarative Sicherheit bedeutet, dass Authentifizierung und Autorisierung mit den im Application Server enthaltenen Mitteln gelöst und ausschließlich in Konfigurationsdateien eingestellt werden (Container Managed Security). Bei programmatischer Sicherheit hingegen übernimmt die Anwendung selbst diese Aufgaben. Beide Ansätze haben Vor- und Nachteile: Deklarative Sicherheit spart Code und regelt alles an einer Stelle. Eine Designentscheidung, die so oder so bewertet werden kann: Durch die typische Aufgabentrennung zwischen Entwickler und Administrator bzw. Hoster gibt der Entwickler die Kontrolle über die Authentifizierung und Autorisierung ab. Abhängig von den benutzten Features kann deklarative Sicherheit aber die Portierbarkeit einschränken und eine Anwendung auf einen Application Server oder eine bestimmte Version des Servers oder der Servlet-Spezifikation festlegen. Beide Ansätze können sich gut ergänzen. Tomcat kennt SSL-Client-Zertifikate als Authentifizirungsmechnismus; dieses Verfahren kann im Deployment Descriptor ( web.xml ) der Anwendung eingestellt werden:CLIENT-CERTDeklarative Sicherheit stützt sich im Tomcat auf so genannte Realms [s. „Literatur“]. Diese sehen eine Authentifizierung auf Basis von Username und Passwort vor. Werden sie zusammen mit Client-Zertifikaten eingesetzt, so ersetzt der Distinguished Name des Zertifikats den Usernamen; das Passwort wird ignoriert. Ein Usereintrag in der tomcat-users.xml für die Memory-Realm sähe z.B. so aus:
<user username="EMAILADDRESS=mustermann@tembit.de, CN=Markus Mustermann, O=Tembit, L=Berlin, S=Berlin, C=DE" password="null" roles="admin"/>Bis einschließlich Version 5.5.4 funktioniert das jedoch nur mit der sehr einfachen und recht unflexiblen MemoryRealm. Erst ab Version 5.5.5 sind die Probleme im Zusammenspiel mit JDBC- und DatasourceRealms behoben (vgl. Bug 30352). Mit einer auf obiger Lösung aufbauenden Konfiguration kann eine Authentifizierung mit Client-Zertifikaten in aktuellen Tomcat-Versionen inzwischen schnell und einfach realisiert werden. Die Kompatibilität zu älteren Versionen, die Flexibilität sowie der geringe Aufwand einer eigenen Implementierung lassen aber auch den im Folgenden beschriebenen programmatischen Sicherheitsansatz sinnvoll erscheinen.
Serverseitige Zertifikatsextraktion und -analyse
In einem Servlet wird auf die Zertifikatsinformation wie in Listing 2 zugegriffen.//get certificates from request Object o = request.getAttribute("javax.servlet.request.X509Certificate"); java.security.cert.X509Certificate clientcert = null; java.security.cert.X509Certificate[] certificates = null; if(o != null) { certificates = (java.security.cert.X509Certificate[]) o ; clientcert = certificates[0]; } else { //error: no client cert in request }Zu beachten ist hier die Unterscheidung zwischen den Klassen java.security.cert.X509Certificate , javax.security.cert.X509Certificate und dem Attribut javax.servlet.request.X509Certificate . Hier gilt: Beim Arbeiten mit Zertifikaten wird stets die Klasse X509Certificate aus dem Paket java.security.cert benutzt. Aus diesem Zertifikatsobjekt können eine Reihe Informationen abgefragt und zur Authentifizierung und Autorisierung eingesetzt werden:
- Distinguished Name (DN) des Inhabers: getSubjectDN()
- Seriennummer des Zertifikats: getSerial-Number()
- Gültigkeitszeitraum des Zertifikats: checkValidity()
- verschiedene Informationen zum Aussteller: getIssuerDN()
- öffentlicher Schlüssel bzw. Fingerprint: getSignature() Informationen zu den zulässigen Verwendungszwecken, Signaturalgorithmen und Protokollversionen des Zertifikats
Integration in die Anwendung
Wird eine bestehende Anwendung komplett auf die Authentifizierung mittels Zertifikaten umgestellt (gibt es keine User-Name-/Passwortabfrage mehr), so kann – wie bei deklarativer Sicherheit mit Realms – der SubjectDN den User-Namen ersetzen. Zusätzlich kann die SerialNumber als Passwort benutzt werden, um Probleme mit erneuerten und somit doppelt ausgestellten Zertifikaten für die gleiche Person zu umgehen. Die Datenstrukturen selbst und die Prüfung der Zugriffsrechte bleiben von dieser Änderung unberührt. Bei neuen Projekten sollte analog vorgegangen werden. Integriert werden kann die programmatische Zertifikatsprüfung an einer zentralen Stelle der Applikation. Dazu bieten sich verschiedene Möglichkeiten an:- Valve bzw. Filter: Für Code, der jeden Request behandelt, bietet Tomcat schon lange das Valve-Konzept. Ein Beispiel für eine spezielle SSLCertAccessValve wird im nächsten Abschnitt entwickelt. Ein Filter lässt sich analog implementieren.
- Ersetzen der User-Name/Passwort-Prüfung: Wurde in einer bestehenden Anwendung eine programmatische Login-Prozedur implementiert, so kann der Code an genau dieser Stelle ausgetauscht werden.
- zentrale Codestelle: Existieren Codestellen, die von jedem Request durchlaufen werden (wie etwa ein RequestProcessor im Struts-Framework), so kann der Zertifikatstest hier eingebaut werden.
- Ein manueller Aufruf entsprechender Prüfroutinen aus verschiedenen Stellen der Anwendung heraus ist zwar möglich, aber nicht empfehlenswert.
Grenzstation – eine AccessValve
Um eigene Valves komfortabel zu implementieren, bietet Tomcat mit org.apache.catalina.valves.ValveBase eine abstrakte Klasse, in der nur noch die Methode in voke(…) überschrieben werden muss:package com.tembit.example; //import declarations public class SSLCertAccessValve extends org.apache.catalina.valves.ValveBase { void invoke(Request request, Response response) throws java.io.IOException, javax.servlet.ServletException { //check certificate here } }Eingebunden wird die Valve durch einen Eintrag im Engine-, Host- oder Context-Abschnitt der Konfigurationsdatei server.xml : <Valve className= „ com.tembit.example.SSLCertAccessValve „ /> . Innerhalb dieser Valve kann entweder auch gleich die Rechteprüfung erfolgen oder aber für Legacy-Anwendungen mit bestehender Rechtestruktur ein entsprechender Parameter wie die User-ID im Request gesetzt werden, um bestehende Strukturen weiter zu nutzen.
Web Services
Zum Schluss noch ein kurzer Exkurs zu Web Services mit Apache Axis. Serverseitig ist die Integration des Zertifikatcodes anhand von AccessValve ideal, da an bestehenden Web Services kein Code verändert bzw. in neuen Projekten kein Code eingefügt werden muss.
Development CA mit OpenSSL Zum Entwickeln und Testen einer Smartcard-Anwendung kann die dafür benötigte CA durch das bei OpenSSL mitgelieferte Skript CA.pl simuliert werden.
Die OpenSSL-Pakete für Linux/Unix finden sich unter www.openssl.org, für Windows empfiehlt sich die Binärdistribution von www.slproweb.com. Initialisierung und CA-Zertifikat Zur Erzeugung wird CA.pl -newca aufgerufen. Das Skript fragt die nötigen Daten ab und erzeugt ein selbst signiertes CA-Zertifikat. Server-Zertifikat für Tomcat Zunächst wird ein Keystore für den Server erzeugt, wobei zu beachten ist, dass der Common Name (CN) des Serverzertifikats auf den Servernamen (z.B. www.example.com ) ausgestellt wird:
keytool -genkey -keystore tomcat.keystore -alias mykey -storepass change_me -keyalg RSADamit Tomcat Client-Zertifikate validieren kann, muss der auch die TrustStore-Rolle übernehmen, dafür wird das CA-Zertifikat binär kodiert
openssl x509 -in demoCAcacert.pem -outform DER -out CA-cert.cerund dann in den Keystore importiert:
keytool -keystore tomcat.keystore -storepass change_me -alias ca -import -file CA-cert.cerAnschließend wird ein Certificate Signing Request (CSR) erzeugt, von der CA signiert und wieder in den Keystore importiert:
keytool -certreq -keystore tomcat.keystore -storepass change_me -keyalg RSA -alias mykey -file newreq.pem CA.pl -signreq openssl x509 -in newcert.pem -outform DER -out newcert.cer keytool -keystore tomcat.keystore -storepass change_me -alias mykey -import -file newcert.cerNutzerzertifikate Nutzerzertifikate für Browser und Smartcards werden dann mit dem CA-Skript erzeugt und im PKCS#12- Format exportiert:
CA.pl -newreq CA.pl -signreq CA.pl -pkcs12Auf der Client-Seite wird ein Java-Keystore generiert (analog zum Tomcat-Server-Keystore, siehe Kasten). Werden in der WSDL die entsprechenden URLs so geändert, dass sie das HTTPS-Protokoll benutzen und dann die Stubs daraus generiert, so kann Axis Client-Zertifikate automatisch benutzen. Lediglich die Dateinamen und Passwörter des Keystore für den eigenen Schlüssel und des Trust-store für das Server- bzw. CA-Zertifikat muss in diesen System.properties angegeben werden:
javax.net.ssl.keyStore javax.net.ssl.keyStorePassword javax.net.ssl.trustStore javax.net.ssl.trustStorePasswordAlles Weitere erledigt Axis automatisch. Für Web-Services-Frameworks, die SSL nicht unterstützen, gibt es als Workaround die Möglichkeit, stunnel auf der Client-Maschine einzusetzen und in der web Services Description Language die URLs der Services auf <a href=“http://localhost:/“ class=“elf-external elf-icon“ rel=“nofollow“>http://localhost:/… zu ändern. In der Konfiguration des stunnel werden dann der Server und das Zertifikat eingetragen. Die Verwendung von Chipkarten ist in diesem Falle nicht ganz so einfach. Diese als Zertifikatsquelle nutzen kann ebenfalls stunnel (mit einigen Erweiterungen). Alternativ wäre dann eine Integration in die Client-Stubs mithilfe eines entsprechenden Karten-Framework in Java zu nennen. Eine Lösung für dieses Szenario würde aber den Rahmen dieses Artikels sprengen.
Produktives System
Sowohl aus Performance- als auch aus Sicherheitsgründen empfiehlt es sich für den produktiven Einsatz, einen umfassend auditierten und erprobten Webserver wie z.B. Apache2 mit mod_ssl als Frontend vor dem Application Server zu betreiben. Die beiden Server werden dann über das Protokoll AJP verbunden. Das dazu eingesetzte mod_jk muss die Zertifikatsdaten von mod_ssl an den Application Server weiterreichen; das neuere mod_jk2 verursacht an dieser Stelle noch Probleme. CA-Zertifikat und Server-Zertifikat werden Apache-typisch an den entsprechenden Stellen installiert. Für den Export der Daten und das Abfragen des Client-Zertifikats werden in der Datei httpd.conf (oder je nach Distribution auch ssl.conf ) des Apache diese Zeilen eingefügt:SSLOptions +ExportCertData +StdEnvVars +CompatEnvVars SSLVerifyClient requireIm Abschnitt zur Konfiguration des mod_jk sind diese Optionen wichtig:
JkExtractSSL On JkHTTPSIndicator HTTPS JkSESSIONIndicator SSL_SESSION_ID JkCIPHERIndicator SSL_CIPHER JkCERTSIndicator SSL_CLIENT_CERTDiese Konfiguration sorgt dafür, dass Zertifikatsinformationen transparent an den Application Server durchgereicht werden und der Anwendung ohne Unterschiede zu obigem Beispielcode zur Verfügung stehen.