J2EE-Sicherheit: Container versus benutzerdefiniert

Seit dem ersten Hinzufügen einer Anmeldeseite zu einer Webanwendung war die Sicherheit immer eine der Schlüsselkomponenten für den Erfolg von Anwendungen im Web. Historisch gesehen wurde alles von Hand codiert. Jede Webanwendung verfügte über eine benutzerdefinierte Methode zum Authentifizieren und anschließenden Autorisieren von Benutzern. Entwickler haben auch Komponenten für die Registrierung, Verwaltung und alle anderen erforderlichen Funktionen integriert. Dieser Ansatz war zwar ziemlich aufwändig, ermöglichte jedoch eine große Flexibilität.

Mit dem Aufkommen von JAAS, dem Java-Authentifizierungs- und Autorisierungsdienst, erhielten Anwendungen eine Reihe von Schnittstellen und eine Konfiguration, die sie zur Standardisierung dieser Aufgaben nutzen konnten. Selbst mit dem Hinzufügen von JAAS zur Spezifikation muss J2EE noch einige Probleme lösen, bevor Anwendungsentwickler die Erstellung benutzerdefinierter APIs beenden können. Um zwischen der Verwendung der J2EE-Standards oder der Erstellung einer benutzerdefinierten Lösung wählen zu können, müssen Sie die Kompromisse der einzelnen und natürlich die Anforderungen Ihrer Anwendung kennen.

Dieser Artikel enthält alle Informationen, die für die Entscheidung zwischen benutzerdefinierter Sicherheit oder Containersicherheit erforderlich sind. Ich diskutiere die gängigsten Sicherheitsfunktionen für Anwendungen, um den erforderlichen Hintergrund für die Sicherheit bereitzustellen. Im Anschluss an diese Diskussion finden Sie eine detaillierte Erläuterung der in den Spezifikationen bereitgestellten J2EE-Sicherheitsimplementierungen sowie der gängigsten Methoden zur Implementierung der benutzerdefinierten Sicherheit. Nachdem Sie die einzelnen Methoden besser verstanden haben, sollten Sie über genügend Informationen verfügen, um die Methode auszuwählen, die den Anforderungen Ihrer Anwendung am besten entspricht.

Was ist ein Container?

Bevor wir die verschiedenen Sicherheitstypen und Bedenken hinsichtlich der Sicherheitsimplementierung erörtern, überprüfen wir, was ein Container istist. Ein Container ist eine Umgebung, in der eine Anwendung ausgeführt wird. Es ist auch gleichbedeutend mit einem J2EE-Anwendungsserver. In Bezug auf J2EE-Container wird eine J2EE-Anwendung innerhalb des Containers ausgeführt, die bestimmte Verantwortlichkeiten in Bezug auf die Anwendung hat. Es gibt viele verschiedene Arten von J2EE-Containern und verschiedene Ebenen der J2EE-Unterstützung. Tomcat von Apache ist ein Webcontainer, der nur die Servlet-Teile (Webanwendung) der J2EE-Spezifikation implementiert. BEAs WebLogic ist ein vollständig kompatibler J2EE-Anwendungsserver, dh er unterstützt alle Aspekte der J2EE-Spezifikation und hat die J2EE-Zertifizierungstests von Sun bestanden. Wenn Sie sich nicht sicher sind, welchen Support Ihr Anwendungsserver bietet, wenden Sie sich an den Anbieter, um weitere Informationen zu erhalten.

Anwendungssicherheit

Ein weiteres Thema, das wir behandeln müssen, bevor wir beginnen, ist die Unterscheidung zwischen Anwendungssicherheit und anderen Sicherheitsarten. Anwendungssicherheit ist Sicherheit, die direkt von einer Anwendung oder indirekt von einem Framework oder Container für eine Anwendung in Bezug auf die Benutzer dieser Anwendung ausgeführt wird. Ein Beispiel für einen Anwendungsbenutzer ist jemand, der sich bei einem Online-Buchladen anmeldet und einige Java-Bücher kauft. Es gibt andere Arten von Sicherheit, z. B. Netzwerksicherheit und JVM-Sicherheit. Ein Beispiel für diese Sicherheitstypen ist der Benutzer, der einen Java-Prozess auf einem Computer startet. Im weiteren Verlauf dieses Dokuments meine ich immer dann, wenn ich über Sicherheit spreche, Anwendungssicherheit. Die anderen Arten von Sicherheit liegen außerhalb des Rahmens dieser Diskussion.

Der Schwerpunkt liegt hier speziell auf der J2EE-Sicherheit, einer Art von Anwendungssicherheit, da sie sich mit den Benutzern einer J2EE-Anwendung (dh Anrufern) befasst. Ein Benutzer kann jemand sein, der den Online-Buchladen verwendet, oder eine andere Anwendung, die die Einkaufsservices der Buchhandlungsanwendung nutzt, z. B. ein anderer Online-Händler.

Sicherheitsfunktionen von Anwendungen

Bei der Betrachtung der Anwendungssicherheit gibt es fünf Hauptfunktionen: Authentifizierung, Autorisierung, Registrierung, Kontoführung (Aktualisierungen) und Löschen / Inaktivieren des Kontos. Obwohl nur eine kleine Teilmenge aller möglichen Funktionen einer Anwendung vorhanden sein kann, sind diese für alle Anwendungen die grundlegendsten und fairsten. Weniger formal kennen diese Funktionen den Benutzer (Authentifizierung), wissen, was der Benutzer tun kann (Autorisierung), erstellen neue Benutzer (Registrierung), aktualisieren Benutzerinformationen (Kontoführung) und entfernen einen Benutzer oder verhindern, dass ein Benutzer auf die Anwendung zugreift (Konto löschen).

In den meisten Anwendungen können entweder der Benutzer oder ein Administrator diese Funktionen ausführen. Wenn Benutzer diese Funktionen ausführen, tun sie dies für sich. Administratoren führen diese Funktionen immer im Auftrag anderer Benutzer aus.

Wie noch dargestellt werden wird, können alle diese Funktionen auch zur Authentifizierung nicht ohne eine benutzerdefinierte Lösung ausgeführt werden. Wir werden jedes einzelne kurz durchgehen, um die Konzepte und die Mängel von J2EE, die speziell angefertigt werden müssen, weiter zu veranschaulichen.

Authentifizierung

Bei der Authentifizierung wird ein Benutzer identifiziert, der mit einer Anwendung interagiert. Zum Zeitpunkt dieses Schreibens konnte die J2EE-Authentifizierung mithilfe einer Vielzahl von Lösungen implementiert werden, die jeweils als Teil der J2EE-Spezifikation (Version 1.0-1.4) definiert sind. Die Authentifizierung ist das Hauptkonzept dieser Diskussion und wird später ausführlicher behandelt. Es ist wichtig zu wissen, dass die Authentifizierung die Sicherheitsfunktion ist, die innerhalb der J2EE-Spezifikation am meisten unterstützt wird. Für die Implementierung der J2EE-Authentifizierung (auch als Containerauthentifizierung bezeichnet) ist jedoch normalerweise ein benutzerdefinierter Code oder eine benutzerdefinierte Konfiguration erforderlich.

Genehmigung

Bei der Autorisierung wird überprüft, ob ein Benutzer berechtigt ist, eine bestimmte Aktion auszuführen. J2EE behandelt dieses Thema, ist jedoch auf die rollenbasierte Autorisierung beschränkt. Dies bedeutet, dass die Aktivität basierend auf den Rollen, die dem Benutzer zugewiesen wurden, eingeschränkt werden kann. Beispielsweise können Benutzer in der Manager-Rolle möglicherweise Inventar löschen, Benutzer in der Mitarbeiter-Rolle jedoch möglicherweise nicht.

Darüber hinaus können Anwendungen zwei verschiedene Arten von Autorisierungen in Betracht ziehen: Java Runtime Environment (JRE) / Container- und Anwendungsautorisierung. Bei der JRE / Container-Autorisierung wird ermittelt, ob der Benutzer, der die Anforderung stellt, über die entsprechenden Berechtigungen verfügt. Die JRE / der Container bestimmt dies, bevor Code ausgeführt wird. Ein Beispiel ist ein J2EE-Container, der zunächst prüfen muss, ob der aktuelle Benutzer über Berechtigungen zum Ausführen eines Servlets verfügt (über eine Ressourcen-URL-Einschränkung), bevor das Servlet ausgeführt wird. Diese Art der Autorisierung wird auch als deklarative Sicherheit bezeichnetweil es in den Konfigurationsdateien für die Webanwendung deklariert ist. Die deklarative Sicherheit kann zur Laufzeit nicht geändert werden, es sei denn, sie wird vom Container unterstützt. Deklarative Sicherheit kann auf viele Arten verwendet werden, um Benutzer von J2EE-Anwendungen zu autorisieren. Dieses Thema reicht jedoch außerhalb des Bereichs dieser Diskussion. (Siehe Servlet 2.3-Spezifikation, Kapitel 12. Abschnitt 2 behandelt die deklarative Sicherheit, und 8 ist ein guter Ausgangspunkt für Sicherheitsbeschränkungen.)

Wie bereits erwähnt, kann der Benutzer eine andere Anwendung oder einfach ein Anwendungsbenutzer sein. In beiden Fällen wird bei jeder Anforderung eine JRE / Container-Autorisierung durchgeführt. Diese Anforderungen können HTTP-Anforderungen von einem Browser an eine Webanwendung oder Remote-EJB-Aufrufe (Enterprise JavaBeans) sein. In beiden Fällen kann der JRE / Container, sofern er den Benutzer kennt, eine Autorisierung basierend auf den Informationen dieses Benutzers durchführen.

Die Anwendungsautorisierung ist der Prozess der Autorisierung während der Ausführung der Anwendung. Die Anwendungsautorisierung kann weiter in rollenbasierte und segmentbasierte Autorisierung unterteilt werden. Ein Beispiel für eine rollenbasierte Anwendungsautorisierung ist, wenn eine Anwendung unterschiedliche Markup-Ebenen anwendet, je nachdem, ob ein Benutzer ein Mitarbeiter oder ein Besucher ist (dh ein Mitarbeiterrabatt). J2EE bietet APIs, die als programmatische Sicherheit bezeichnet werden , um eine rollenbasierte Autorisierung durchzuführen (weitere Informationen finden Sie in der Servlet 2.3-Spezifikation, Kapitel 12, Abschnitt 3).

Segmentbasierte Autorisierung ist eine Autorisierung, die auf anderen Attributen eines Benutzers basiert, z. B. Alter oder Hobbys. Die segmentbasierte Autorisierung wird als solche bezeichnet, da Benutzer anhand bestimmter Attribute in Segmente gruppiert werden. J2EE verfügt über keine Methode zum Implementieren einer segmentbasierten Autorisierung. Ein Beispiel für eine segmentbasierte Autorisierung ist, ob eine Schaltfläche in einem Formular für Benutzer über 40 Jahre sichtbar ist. Bestimmte Anbieter bieten möglicherweise diese Art der Autorisierung an, dies würde jedoch in allen Fällen eine Lieferantenbindung garantieren.

Anmeldung

Bei der Registrierung wird der Anwendung ein neuer Benutzer hinzugefügt. Anwendungsbenutzer können möglicherweise neue Konten für sich selbst erstellen oder die Anwendung kann diese Aktivität auf Anwendungsadministratoren beschränken. Die J2EE-Spezifikation verfügt nicht über eine API oder Konfiguration, mit der Anwendungen neue Benutzer hinzufügen können. Daher wird diese Art der Sicherheit immer speziell angefertigt. J2EE ist nicht in der Lage, dem Container mitzuteilen, dass sich ein neuer Benutzer registriert hat und dass seine Informationen während der Sitzung beibehalten und gepflegt werden müssen.

Instandhaltung

Bei der Kontoführung werden Kontoinformationen wie Kontaktinformationen, Anmeldungen oder Kennwörter geändert. In den meisten Anwendungen können sowohl Anwendungsbenutzer als auch Administratoren Wartungsarbeiten durchführen. Der J2EE-Spezifikation fehlt auch eine API oder Konfiguration für die Kontoführung. Es fehlt ein Mechanismus, um den Container darüber zu informieren, dass sich Benutzerinformationen geändert haben.

Streichung

Das Löschen eines Kontos ist normalerweise nur Administratoren vorbehalten. In seltenen Fällen können Benutzer in einigen Anwendungen ihre eigenen Konten löschen. Die meisten Anwendungen löschen tatsächlich niemals Benutzer. Sie deaktivieren einfach das Konto, sodass sich der Benutzer nicht mehr anmelden kann. Hartes und schnelles Löschen ist normalerweise verpönt, da die Kontodaten bei Bedarf viel schwieriger wiederzubeleben sind. J2EE bietet keine Möglichkeit, Benutzer aus Anwendungen zu entfernen oder zu inaktivieren. Es fehlt ein Mechanismus, um dem Container mitzuteilen, dass ein bestimmter Benutzer inaktiviert oder entfernt wurde. J2EE fehlt auch ein Mechanismus zum sofortigen Abmelden eines Benutzers von der Anwendung, wenn sein Konto gelöscht wurde.

Was ist Containerauthentifizierung?

Bei der Containerauthentifizierung wird dem Container die Identität des Benutzers mitgeteilt, der die aktuelle Anforderung stellt. Bei den meisten Containern umfasst dieser Prozess das Zuordnen des aktuellen ServletRequestObjekts, des aktuellen Ausführungsthreads und einer internen Sitzung zur Identität des Benutzers. Durch Zuordnen einer Sitzung zur Identität kann der Container sicherstellen, dass die aktuelle Anforderung und alle nachfolgenden Anforderungen desselben Benutzers derselben Sitzung zugeordnet werden können, bis die Sitzung dieses Benutzers abläuft. Dieses Sitzungsobjekt ist normalerweise nicht dasselbe wie das HttpSessionObjekt, obwohl das erstere zum Erstellen und Verwalten des letzteren verwendet wird. Jede nachfolgende Anforderung desselben Benutzers wird der Sitzung entweder mithilfe einer URL-Umschreibung oder eines Sitzungscookies gemäß der Servlet 2.3-Spezifikation, Kapitel 7, zugeordnet.

Wie oben in unserer Diskussion über die Autorisierung erwähnt, werden jede Aktion, die der Container ausführt, sowie jede Aktion, die die JRE im Namen dieses Benutzers ausführt, sorgfältig geprüft, um sicherzustellen, dass der Benutzer die Berechtigung zum Ausführen der Aktion hat. Um unser vorheriges Beispiel zu wiederholen: Wenn der Container ein Servlet im Namen des Benutzers ausführt, wird überprüft, ob der Benutzer zu den Rollen gehört, denen die Berechtigung zum Ausführen dieses Servlets erteilt wurde. JRE 1.4 führt diese Überprüfungen auch für viele Aktionen durch, einschließlich beim Öffnen einer Datei oder eines Sockets. Die JRE-Authentifizierung ist ein leistungsstarkes Konzept und kann sicherstellen, dass jede Anforderung an einen Container im Wesentlichen sicher ist.

Derzeit bietet J2EE einige verschiedene Mechanismen zum Implementieren der Benutzerauthentifizierung. Dazu gehören die formularbasierte Authentifizierung, die HTTPS-Clientauthentifizierung und die HTTP-Basisauthentifizierung. JAAS ist als erforderliche Authentifizierungsmethode enthalten, die Container unterstützen müssen. Die Spezifikation ist jedoch nicht streng, wie der Container diese Funktionalität bereitstellen soll. Daher bietet jeder Container eine andere Unterstützung für JAAS. Darüber hinaus ist JAAS selbst ein eigenständiges Authentifizierungsframework und kann zur Implementierung der Containerauthentifizierung verwendet werden, unabhängig davon, ob die Spezifikation dies unterstützt. Ich erkläre dieses Konzept später ausführlicher.

Jeder der Authentifizierungsmechanismen bietet eine Standardmethode, um dem Container Informationen über den Benutzer zu geben. Ich bezeichne dies als Berechtigungsnachweisrealisierung . Der Container muss diese Informationen weiterhin verwenden, um zu überprüfen, ob der Benutzer vorhanden ist und über ausreichende Berechtigungen verfügt, um die Anforderung zu stellen. Ich bezeichne das als Authentifizierung von Anmeldeinformationen . Einige Container bieten eine Konfiguration zum Einrichten der Authentifizierung von Anmeldeinformationen, andere bieten Schnittstellen, die implementiert werden müssen.

J2EE-Authentifizierungsmethoden

Lassen Sie uns kurz einige der gängigsten Methoden zum Implementieren und Konfigurieren der Containerauthentifizierung betrachten.

Formularbasierte Authentifizierung

Mit der formularbasierten Authentifizierung können Benutzer mithilfe eines beliebigen HTML-Formulars beim J2EE-Anwendungsserver identifiziert und authentifiziert werden. Die Formularaktion muss sein j_security_checkund zwei HTTP-Anforderungsparameter (Formulareingabefelder) müssen immer in der Anforderung enthalten sein, einer aufgerufen j_usernameund der andere j_password. Bei Verwendung der formularbasierten Authentifizierung erfolgt die Realisierung der Anmeldeinformationen, wenn das Formular gesendet und der Benutzername und das Kennwort an den Server gesendet werden.

Hier ist ein Beispiel für eine JSP-Seite (JavaServer Pages), die eine formularbasierte Authentifizierung verwendet:

 Login Geben Sie Ihren Benutzernamen ein:

Geben Sie Ihr Passwort ein: