Vom Software- zum Security-Architekten

J2EE Security
Kommentare

Die deklarative Security trat mit dem hohen Anspruch an, die Entwickler von nahezu allen Belangen der Zugriffsberechtigung zu befreien, inklusive der Anbindung bestehender Legacy-Systeme. Damit sollte die volle Konzentration auf die Implementierung der Fachlichkeit gelenkt werden. Versprechungen dieser Art gab es bisher viele – und oft wurde die gewünschte Vereinfachung nur durch neue Komplexität erkauft. Ein simples Anwendungsszenario aus dem Versicherungsbereich soll die Prinzipien der J2EE Security im Folgenden veranschaulichen und prüfen, inwieweit die Sicherung von Enterprise-Applikationen durch die Verwendung dieses Konzeptes wirklich einfacher geworden ist.

Die Erstellung einer Applikation zur Verwaltung der Partner- und Bestandsdaten eines Versicherungsunternehmens dient als theoretisches Beispiel zur Diskussion verschiedener Aspekte der J2EE Security. Dieser Anwendungsbereich ist besonders sicherheitskritisch. Es soll Kunden sowie intern und extern arbeitenden Mitarbeitern des Versicherungsunternehmens einerseits möglichst einfach und flexibel Zugriff auf die eigenen Daten gegeben werden. Andererseits wird hier mit ganz besonders schützenswerten Informationen umgegangen. Daher muss unter allen Umständen vermieden werden, dass Unberechtigte diese Daten lesen oder gar verändern können.

Rollenmodellierung Ein simples Beispiel soll aus den idealtypischen Rollen „Kunde“ (KD), „Angestellter Außendienst“ (AD) und „Sachbearbeiter“ (SB) bestehen, wobei Rollen eine Gruppierung von Rechten innerhalb verschiedener Anwendungen darstellen, die zur Erfüllung von Funktionen oder Arbeitsprozessen notwendig sind. Die fachliche Welt ist aber deutlich komplexer: Weder gibt es „den Außendienstler“ noch „den Sachbearbeiter“. Der AD ist oft in größeren Agenturen hierarchisch organisiert, wobei höhere Ebenen Zugriff auf Daten der unteren Ebenen haben und über mehr Rechte verfügen. Noch komplexer ist es beim Innendienst der Versicherung. SB gibt es in vielfacher Typisierung, unterschieden nach Sparte (Leben, Kranken, diverse Sachversicherungen), Vollmachtsstufen, Hierarchiestufen mit Zusatzrechten, Spezialbearbeitungsrechten auf VIP- oder Mitarbeiterverträge. Wie sehen mögliche Prozesse der einzelnen Rollen aus? Ein Kunde sollte die Möglichkeit haben, über Internet seine vertraglichen (Bestandsdaten) und persönlichen Nutzerdaten (Partnerdaten) zu sehen und teilweise zu ändern (etwa Nachname und Adressdaten). Änderungen können aber weitere interne Benachrichtigungen zur Folge haben, etwa die Datenanpassung in anderen Systemen oder die Information von speziellen SB oder des Kundenvertreters (Bsp.: Kunde ändert die Adresse und besitzt eine Hausratversicherung: Gibt es jetzt neue Risiken?). Der Außendienst darf eine größere Anzahl Partner- und Vertragsdaten neu anlegen, lesen, ändern, zusammenführen und löschen. Vor Übertrag in die Host-Systeme müssen aber Konsistenzprüfungen und teilweise weiterführende Prozesse angestoßen werden. Die Zugriffsrechte der Sachbearbeiter auf Partner und Bestände sollten einschränkbar hinsichtlich Region, Status des Kundendatensatzes, Bearbeitungsvollmacht (z.B. Regulierungshöhe) und Zugriffsart (lesen, ändern, neu anlegen, zusammenführen, löschen/stornieren …) sein. Letztlich ist es durch eine Kombination von Rollen möglich, jede fachliche Aktivität damit durchzuführen, teilweise sind Rollen aber voneinander abhängig oder aber auch nicht miteinander vereinbar (4-Augen-Prinzip, „Separation of duties“-Paradigma).

Aus der kurzen Diskussion im Kasten “Rollenmodellierung” wird deutlich, dass die korrekte Konzipierung der Rollen kein triviales Thema ist und einen deutlichen Einfluss auf die Sicherheitsarchitektur einer Anwendungslandschaft hat. Diese Modellierung muss individuell und frühzeitig in der Analyse betrachtet und detailliert entworfen werden. Um das Beispiel übersichtlich zu halten, reichen die drei genannten Rollen aber vollständig aus. Alle technischen Aspekte der J2EE Security lassen sich mit ihnen beschreiben und es sollte problemlos möglich sein, die Konzepte auf größere Projekte zu übertragen.

Architektur einer Versicherungsanwendung

Abbildung 1 zeigt eine typische Systemarchitektur. Ziel der hier geplanten Lösung ist es, den genannten Rollen einen flexiblen Zugriff auf die verschiedenen Altsysteme über eine moderne webbasierte Enterprise-Applikation zu ermöglichen. Die Aufgabe des J2EE-Entwicklers bzw. -Architekten ist die Konzeptionisierung und Umsetzung der logischen Sicherheit auf Applikationsebene. Zur Implementierung der geforderten Funktionalität existieren im J2EE-Umfeld verschiedene Authentifizierungs- und Autorisierungsmethoden [Sun Java Platform, Enterprise Edition Specification, Sun Java Platform, Standard Edition Specification 1.4]. Die teilweise über Jahrzehnte gewachsenen Legacy-Systeme enthalten eine komplexe Anwendungslandschaft für die persönlichen Kundendaten (“Partner”) und die Vertragsdaten (“Bestand”) und werden von proprietären Berechtigungssystemen verwaltet.

Authentifizierung

Der erste Schritt zur Sicherung von Webanwendungen ist die sichere Authentifizierung des Benutzers. Prinzipiell sind eine ganze Reihe unterschiedlicher Authentifizierungsmethoden möglich. Diese reichen von wissensbasierten (z.B. über die Eingabe von User ID und Passwort) über schlüsselbasierte (z.B. SmartCard) bis hin zu biometrischen (z.B. Iris-Scan) Verfahren. Für einen Kunden-Login sind schlüsselbasierte oder biometrische Verfahren für das hier vorgestellte Beispiel (noch) nicht praktikabel, sodass die Entscheidung auf die Eingabe von User ID und Passwort fällt. Die J2EE-Spezifikation definiert dafür drei Typen von Authentifizierung:

  • HTTP-Basic-Authentifizierung: Eingabe von User ID und Passwort in einem vom System bereitgestellten Anmeldefenster
  • Form-based Authentification: User-ID- und Passworteingabe über ein selbst erstelltes Formular
  • Authentifizierung über Client-Zertifikate: Datenübergabe durch ein Client-Zertifikat

Die Authentifizierungsmethode der Webanwendung wird im Deployment Descriptor (DD), also in der web.xml unter dem Element innerhalb des Elements angegeben. Die jeweiligen Werte sind BASIC, FORM beziehungsweise CLIENT-CERT. Für ein ansprechendes Kunden-Login wäre eigentlich eine formularbasierte Authentifizierung die Lösung der Wahl. Der Einfachheit halber soll hier nun aber die unkomplizierteste der Authentifizierungsmethoden, die HTTP-Basic-Authentifizierungsmethode, genutzt werden. Dazu wird neben der eigentlichen Authentifizierungsmethode im DD auch noch ein so genannter Realm angegeben, der innerhalb des Application Server für eine richtige Zuordnung der Anwendung zu dem passenden Benutzerverzeichnis (hier: LDAP) benötigt wird. Die folgende Quellcodepassage zeigt, wie der entsprechende Eintrag für das Login im DD aussehen kann.

...
BASICdefault
...

Da die Login-Informationen bei der HTTP- Basic-Authentifizierung quasi im Klartext übertragen werden, sollte die Verbindung gesichert werden – beispielsweise über SSL. Weitere Informationen über die Authentifizierungsmethoden und auch über das JAAS Framework (Java Authentication and Authorization Service) finden sich im Sun Java Authentication and Authorization Service Reference Guide.

Verfügbare Sicherheitsmechanismen

Nach erfolgreicher Authentifizierung am Application Server erhält der Benutzer seine Zugriffsrechte. Die J2EE-Spezifikation beschreibt zur Autorisierung zwei Ansätze: die deklarative und die programmatische Security. Bei der programmatischen Security werden die Sicherheitsprüfungen in das Programm in aller technischen Detailtiefe integriert, während bei deklarativer Security der Container alle Sicherheitsabfragen übernimmt. Für beide Ansätze sind die benötigten Rollen vom Application Component Provider in den DDs der jeweiligen Komponenten (EJB oder Web) zu definieren. Dazu werden entsprechende Security-Role- Einträge im DD hinterlegt (Listing 1 und 2). Diese applikationsspezifischen Rollen werden vom Deployer bzw. Systemadministrator auf die realen Benutzergruppen der zugrunde liegenden Benutzerverwaltung abgebildet.

Listing 1


... 
KundeSachbearbeiterAussendienst 
...
Listing 2 


.. 
KundeSachbearbeiterAussendienst 
...
Deklarative Security

Die deklarative Security delegiert die Sicherheitsprüfungen an den Web- bzw. EJB- Container. Hierbei hat der Entwickler bereits beim Design der Anwendung festzulegen, auf welcher Ebene die Prüfungen durchgeführt werden. Im Falle einer Webanwendung wird der Zugriff im DD per Security Constraint festgelegt. Eine solche Sicherheitsrestriktion besteht aus einer oder mehreren Web Resource Collection (Listing 3). Mittels Patterns können einzelne Seiten bzw. Seitenmengen anhand einer URL definiert werden. Die im Auth Constraint angegebenen Rollen erhalten Zugriff auf die Webressourcen.

Listing 3 


... 
EingabeDefiniert die Eingabemasken/input/*GETPOSTBerechtigte BenutzergruppenSachbearbeiterKundeAussendienst 
...

Im Falle einer EJB kann der Zugriff entweder auf alle oder auf ausgewählte Methoden der Bean gestattet werden. Dies geschieht mittels der Method-Permission-Abschnitte innerhalb des Assembly-Descriptor-Abschnitts im DD (Listing 4). Dieser Abschnitt beschreibt, welche Rollen auf welche Methoden einer Bean zugreifen dürfen. Bei nicht vorhandener Zugriffsberechtigung erzeugt der Container eine Security Exception.

Listing 4 


... 
 
... 
KundeSachbearbeiterAussendienstPartnerlesePartnerSachbearbeiterPartner* 
... 
...

Hier werden schon Schwächen dieser Art von Zugriffskontrolle deutlich: Erst durch den Zugriff auf eine Methode kann geprüft werden, ob eine Berechtigung vorhanden ist. Das fehlerfreie Zusammenspiel von Application Assembler, Systemadministrator und Gruppenadministrator ist die Voraussetzung für eine erfolgreiche Realisierung der Sicherheitsarchitektur! Die eindeutigen Vorteile dieses Ansatzes liegen in der hohen Flexibilität bei Änderungen und der relativ hohen Transparenz der Security-Struktur. Über die deklarative Security lässt sich mit geringem Aufwand eine Grundsicherung der Anwendungslandschaft erreichen.

Schematische Darstellung des Role Mapping
Programmatische Security

Die programmatische Security ermöglicht eine flexiblere Kontrolle über den Zugriff auf geschützte Ressourcen. Mittels der beiden Methoden isCallerInRole() und getCallerPrincipal() kann der Entwickler einer EJB prüfen, ob der aktuelle Benutzer sich in einer bestimmten Rolle befindet, bzw. er erhält die Security Principals des aktuellen Nutzers aus dem EJB Context. Die Methoden isUserInRole() und get UserPrincipal() stellen die gleiche Funktionalität für Servlets aus dem HttpServletRequest zur Verfügung.

Listing 5 


public class PartnerDatenBean implements SessionBean 
{ 
private SessionContext ctx; 
... 
public Object getPersonalData() 
{ 
// ...
// Prüfung, ob Aufrufer "Customer" ist
if( ctx.isCallerInRole("Customer")
{
Principal user = ctx.getCallerPrincipal();
if( user != null)
{
String name = user.getName(); 

// Holen der Partnerdaten des Kunden
// ...
}
}
}
...
}

Listing 5 zeigt, wie innerhalb einer EJB geprüft wird, ob der aufrufende Nutzer die Rolle “Customer” ausübt. Falls dies so ist, wird der Name des Nutzers bestimmt und mit diesem können dann anschließend die Partnerdaten aus dem Legacy-System gelesen werden. Der Entwickler benennt die in der Applikation genutzten Rollen im DD der zu erstellenden Komponente. Für die hier beschriebene Session Bean wird im DD dazu unter Session ein Abschnitt Security Role Ref mit einem Role Name angelegt. Der Application Assembler muss diesen referenzierten Rollen der Bean-Rollendefinitionen der Anwendung zuordnen. Dazu fügt er unter der Rollenreferenz Security Role Ref einen entsprechenden Link zu der Applikationsrolle (hier: Kunde) hinzu (Listing 6).

Listing 6


... 
PartnerDaten 
... 
...CustomerKunde 
...

...
 
... 
Kunde 
... 
 
...

Beim Deployment der Anwendung auf einen Application Server weist der Systemadministrator diese Rollen einer oder mehreren administrierten Benutzer oder Benutzergruppen zu. Beim Design der programmatischen Security ist darauf zu achten, dass es Fälle geben kann, in denen ein Benutzer mehrere Rollen einnimmt. Dies kann beabsichtigt, aber auch unbeabsichtigt geschehen. Beabsichtigt, wenn ein Benutzer wirklich mehrere Aufgaben wahrnimmt, die wiederum mehrere Rollen erfordern und unbeabsichtigt zum Beispiel durch eine versehentlich falsche Administration der Benutzer. Der Entwickler der Komponente muss danach diese Kombinationen berücksichtigen, auch wenn aus seiner Sicht die Rollen nicht zur gleichen Zeit erfüllt werden dürfen. Durch die konkrete Implementierung der Prüfungen im Programmcode nimmt der Entwickler eine Priorisierung der Rollen vor. Dies geschieht sowohl hinsichtlich der Reihenfolge der Abfragen (hier: Kunde, Außendienst, Sachbearbeiter oder umgekehrt: Sachbearbeiter, Außendienst, Kunde) als auch hinsichtlich deren Exklusivität, das heißt, es werden z.B. mehrere einfache if- Abfragen hintereinander gestellt oder es wird eine geschachtelte if-else- Abfrage erstellt. Somit sind die Rollenrechte im Rahmen der programmatischen Security im Gegensatz zur deklarativen Security nicht unbedingt additiv. Man kann nicht davon ausgehen, dass zwei Benutzer, denen neben bereits vorhandenen Rollen zusätzlich die gleiche Rolle zugewiesen wurde, auch dieselben (Mindest-)Rechte erhalten. Die Gewährung von zusätzlichen Rechten kann demnach sogar dazu führen, dass einem Benutzer effektiv Rechte entzogen werden, beispielsweise, wenn eine exklusive Abfragereihenfolge Kunde, Außendienst, Sachbearbeiter implementiert wurde und einem Anwender zusätzlich zur Sachbearbeiterrolle auch noch die Kundenrolle zugewiesen. wird. In diesem Fall übt der Benutzer effektiv nur die Kundenrolle aus, weil sie zuerst gefunden wurde und die Suche dann abgebrochen wird. Sind einem Benutzer mehrere Rollen zugewiesen, kann es passieren, dass der User über unterschiedliche Rollen für die gleiche Anwendung sich ausschließende Rechte erhält, z.B. “nur lesen” und gleichzeitig “ändern”, “Auszahlung” und gleichzeitig “Kontrolle der Auszahlung”. Um hier keine technischen, fachlichen oder gesetzlichen Vorgaben zu verletzen, müsste ein automatisiertes Regelwerk (Rules Engine) Prioritätenkonflikte oder Abhängigkeiten bzw. Unvereinbarkeiten auflösen. Derartige, sehr granular einstellbare Funktionalitäten inklusive eines Admin Workflow finden sich in IdM-Systemen (Identity Management). Diese Werkzeuge ermöglichen außerdem eine zentrale Verwaltung von Usern und Rollen über Systemgrenzen hinweg. Die Problematik programmatischer Sicherheitsprüfungen liegt in der Verflechtung der Sicherheitsabfragen mit der Business-Logik und in der fehlenden Trans- parenz der gewährten Zugriffe. So führen Änderungen in den fachlichen Vorgaben an die Security direkt zu einer neuen Applikationsversion und damit zu einem Redeployment aller betroffenen Anwendungen. Der eigentliche Programmcode wird durch diese Verflechtung schwerer lesbar und die benötigten Sicherheitsabfragen stören den Programmfluss. Dieses Aufbrechen des Paradigmas “Separation of concerns” verschlechtert die Qualität des Designs und die Wartbarkeit der gesamten Architektur. Die Nachvollziehbarkeit der Zugriffsgewährung – also die Revisionssicherheit – ist nicht ganz ohne weiteres sicherzustellen. Jedoch erst durch den Einsatz der programmatischen Security kann vor dem Zugriff auf geschützte Komponenten eine Prüfung durchgeführt werden, zum Beispiel beim dynamischen Seitenaufbau.

Host-Anbindung

Bisher laufen alle Teile des entwickelten Systems im gleichen Sicherheitskontext ab, d.h., der Zugriff erfolgt im Application Server mittels der gleichen Sicherheitsattribute. Um aber die im Beispiel bestehenden Host-Systeme anzubinden, reicht dies nicht mehr aus. Im speziellen Fall besitzt jeder Sachbearbeiter und Mitarbeiter im Außendienst eine Benutzerkennung im Partner- bzw. Bestandssystem mit entsprechenden Rechten. Da nicht für alle Kunden eine Benutzerkennung im Host-System bereitgestellt werden kann und ein direkter Zugriff nicht vorgesehen ist, muss er auf andere Weise bereitgestellt werden. Die J2EE-Spezifikation sieht dafür die Java 2 Connector Architecture (J2C) vor [Sun J2EE Connector Architecture Specification, 1.5]. Hier soll nur ein kurzer Einblick gegeben werden, da dies eine sehr komplexe Problematik ist und den Rahmen dieses Artikels sprengen würde. Es bestehen verschiedene Möglichkeiten, den Zugriff auf diese Fremdsysteme abzusichern. Zum einen kann der Zugriff komplett über einen technischen User abgewickelt werden, unabhängig davon, welcher Benutzer die Bean aufruft. Dies geschieht mittels eines Security-Identity-Abschnitts innerhalb der EJB-Beschreibung des DD. Die dort angegebene Rolle im run-as-Abschnitt ist diejenige, unter der der Zugriff auf die Bean realisiert wird (Listing 7).

Listing 7 


... 
 
... 
PartnerdatenBackendsystem 
... 
PDTechUser 
... 
 
... 
 
...

In diesem Fall ist es nicht mehr erforderlich, dass für alle Kunden ein Benutzer-Account auf dem Legacy-System angelegt werden muss. Problematisch dabei ist aber, dass alle Zugriffe auf dieses System unter dem gleichen Account ausgeführt werden und nicht mehr nachvollziehbar ist, welcher reale Nutzer die Änderungen getätigt hat. Sollen nun bestehende Accounts weiter genutzt werden, so müssen dann die Anmeldeinformationen zum Fremdsystem weitergeleitet werden. Dies kann auf zwei Arten geschehen: container- oder anwendungsverwaltet. Dazu muss im DD der Anwendung der Authentifizierungstyp in der Ressourcenreferenz angegeben werden. Dort sind die Werte Container beziehungsweise Application anzugeben.

Listing 8 


... 
eis/partnerDatenConnection 
... 
Application 
... 

Listing 8 zeigt, wie eine applikationsverwaltete Verbindung im DD konfiguriert wird. So ist es möglich, mittels programmatischer Security zu prüfen, ob der Nutzer die Rolle Kunde einnimmt und dann den Zugriff mittels technischer User zu realisieren.

if ( isUserInRole("Kunde")
   // greife auf Hostsystem mit technischen User zu
else
   // nimm aktuellen/aktiven User

Außendienstler und Sachbearbeiter greifen direkt mit ihrem bestehenden Account auf die Ressource zu.

Fazit und Ausblick

Bereits bei den vereinfachten fachlichen Zusammenhängen fällt auf, dass Sicherheitsaspekte schon frühzeitig in der Designphase mit einbezogen werden müssen und dass die J2EE-Sicherheitsinfrastruktur für den Entwickler offene Probleme hinterlässt. Weiterhin wird deutlich, dass die bestehenden Konzepte der J2EE Security eine Basis für sichere Anwendungen bilden, aber trotzdem noch nicht zur Sicherung komplexerer Umgebungen ausreichen. Auch ist die Administration der Rollen-Rechte-Zuordnungen sehr komplex und fehleranfällig und wird zurzeit nicht ausreichend durch geeignete Tools unterstützt. Identity-Management-Systeme bieten hier eine deutliche Erleichterung auf fachlicher Administrationsebene, weisen aber im technischen Zusammenspiel mit der Anwendungsinfrastruktur noch Mängel auf.

J2EE-Plattformrollen Die J2EE-Plattform-Beschreibung definiert sechs Rollen, die alle zusammen die Sicherung einer Applikationslandschaft sicherstellen müssen. Der Tool Provider und der Container Provider stellen mit ihren Tools die Umsetzung der J2EE Security sicher. Der Application Assembler und der Deployer legen die Sicherheitsrichtlinien der Anwendung fest und definieren die benötigten Rollen zur Ausführung. Der Systemadministrator legt eine Abbildung zwischen Anwendungsrollen und den Gruppen des Benutzerverzeichnisses fest. Der Application Component Provider, also der Entwickler der Bean, sollte sich eigentlich nur noch um die fachliche Umsetzung der Business-Logik kümmern müssen. Er kann allerdings immer noch mittels programmatischer Security die Sicherstellung des korrekten Zugriffs auf Ressourcen beeinflussen.

Eines der größten Mankos der J2EE Security ist aber die fehlende Revisionssicherheit. Zur Erfüllung diverser Gesetze und Normen (Compliance) muss zu jeder Zeit feststellbar sein, wer wann welche Zugriffsrechte auf welche Daten hatte und wer sie vergeben hat. Ein erster Ansatz wäre beispielsweise ein erweiterter LDAP-Server, der die Administrationsaktivitäten revisionssicher protokolliert oder die Entitätenzustände historisiert (Rollen, Gruppen und User sind z.B. Entitäten). Ein weiterer Schritt ist die Entkopplung der Business-Logik von der im Programmcode hinterlegten Security und den daraus resultierenden Rechten. Unter diesen Bedingungen könnten dann Änderungen durch fachlich und organisatorisch Verantwortliche auf einer Business-(Präsentations-)Ebene vorgenommen sowie transparent nachvollzogen werden. Hinsichtlich der Anforderungen scheinen auch die neuen Spezifikationen von Enterprise JavaBeans 3.0 und J2EE 5.0 im Bereich Security nichts Neues zu bringen – außer natürlich, dass durch den Wegfall des DD die entsprechenden Einträge zur Sicherheit in den Annotations der Bean aufgehen werden. Inhaltlich ändert sich aber nichts daran, dass das Thema Sicherheit in einer heterogenen Systemumgebung auch zukünftig eine weite Spielwiese für Innovationsansätze bietet.

Marco Bohne ist als Fachberater für das Umfeld Rollen- & Rechtekonzeption sowie Identity Management verantwortlich. Rainer Gregulla ist als IT-Berater seit mehreren Jahren im Umfeld Enterprise Java tätig und beschäftigt sich zurzeit schwerpunktmäßig mit dem Thema J2EE Security und SOA. Jörg Kohmann ist als IT-Berater für Enterprise Java für Entwicklung, QM/QS und Testautomatisierung zuständig. Die drei Autoren arbeiten für die in Köln ansässige FSP Consulting & IT-Services. Wir freuen uns auf Anregungen und Kommentare ( J2EE-security@fsp-gmbh. com ).
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -