Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Übungsaufgabe 9: Warenkorb
Erweitern Sie Ihre E−Shop−Anwendung um einen Warenkorb! In diesen
Warenkorb kann der Benutzer Produkte hineinlegen.
Der Warenkorb soll auf jeder Seite sichtbar sein. Er zeigt für jedes Produkt
im Korb Produktname, Stückzahl, Einzelpreis und Gesamtpreis an. Initial
ist der Warenkorb natürlich leer.
In der Detailansicht eines Produkts kann der Benutzer das Produkt mit
Angabe der Stückzahl zum Warenkorb hinzufügen.
In der Warenkorbanzeige ist die Stückzahl eines Produkts modifizierbar.
Setzt der Anwender die Stückzahl auf 0, wird das Produkt aus dem
Warenkorb entfernt.
Die Seite »Kasse« wird später der Abrechnung dienen. In dieser
Übungsaufgabe wird der Einkaufszettel mit der Gesamtsumme angezeigt,
der Benutzer um Bestätigung gebeten und die Sitzung beendet.
Web−Anwendungen mit Java
251
Request−Methoden
Zahlreiche Methode zum Erfragen von
request−spezifischen Details
Beispiel Snoop−Servlet
Web−Anwendungen mit Java
252
Snoop−Servlet
package de.rainer_klute.servlet;
import
import
import
import
java.io.*;
java.util.*;
javax.servlet.*;
javax.servlet.http.*;
/**
* <p>Dieses Servlet analysiert einen HTTP−Request und
* zugehörige servletspezifische Klassen.</p>
*
* @author Rainer Klute
*/
public class Snoop extends HttpServlet
{
Web−Anwendungen mit Java
253
Snoop−Servlet
/**
* <p>Gibt zwei Objekte als eine Zeile einer
* HTML−Tabelle aus.</p>
*/
private void printTableLine(PrintWriter out,
Object cell1, Object cell2)
{
out.println("<tr valign=\"top\">");
printTableCell(out, cell1);
printTableCell(out, cell2);
out.println("</tr>");
}
Web−Anwendungen mit Java
254
Snoop−Servlet
/**
* <p>Gibt ein Objekt als Tabellenzelle aus.</p>
*/
private void printTableCell(PrintWriter out,
Object cell)
{
StringBuffer b = new StringBuffer(80);
String s = (cell == null ? "<p>null</p>"
: cell.toString().trim());
b.append("<td>");
Web−Anwendungen mit Java
255
Snoop−Servlet
}
if (s.equals(""))
b.append("<p> </p>");
else
{
if (s.charAt(0) == ’<’)
b.append(s);
else
{
b.append("<p>");
b.append(s);
b.append("</p>");
}
}
b.append("</td>");
out.println(b.toString());
Web−Anwendungen mit Java
256
Snoop−Servlet
/**
* <p>Bearbeitet GET−Request.</p>
*/
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
Enumeration e;
PrintWriter out = response.getWriter();
StringBuffer b = new StringBuffer(50);
response.setContentType("text/html");
out.println("<!DOCTYPE html PUBLIC " +
"\"−//W3C//DTD HTML 4.0//EN//\">");
out.println("<html>");
out.println("<head>");
out.println("<title>Snoop</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Snoop</h1>");
Web−Anwendungen mit Java
257
Snoop−Servlet
/* Informationen zum Servlet */
out.println("<div>");
out.println("<h2>Generic Servlet</h2>");
out.println("<table border=\"1\">");
/* Servlet−Konfiguration */
printTableLine(out, "Servlet Config:",
getServletConfig());
/* Servlet−Info */
printTableLine(out, "Servlet Info:",
getServletInfo());
Web−Anwendungen mit Java
258
Snoop−Servlet
/* Initialisierungsparameter */
b.setLength(0);
e = getInitParameterNames();
if (e.hasMoreElements())
{
b.append("<table border=\"1\">");
while (e.hasMoreElements())
{
String name = (String) e.nextElement();
String value = getInitParameter(name);
b.append("<tr valign=\"top\">");
b.append("<td><p>" + name + "</p></td>");
b.append("<td><p>" + value + "</p></td>");
b.append("</tr>");
}
b.append("</table>");
}
printTableLine(out, "Init Parameters:", b);
Web−Anwendungen mit Java
259
Snoop−Servlet
/* Servlet−Kontext */
printTableLine(out, "Servlet Context:",
getServletContext());
/* Servlet−Name */
printTableLine(out, "Servlet Name:",
getServletName());
out.println("</table>");
out.println("</div>");
/* Informationen zum Request
* (nicht HTTP−spezifisch) */
out.println("<div>");
out.println("<h2>Servlet Request</h2>");
out.println("<table border=\"1\">");
Web−Anwendungen mit Java
260
Snoop−Servlet
/* Request−Attribute */
b.setLength(0);
e = request.getAttributeNames();
if (e.hasMoreElements())
{
b.append("<table border=\"1\">");
while (e.hasMoreElements())
{
String name = (String) e.nextElement();
Object value = request.getAttribute(name);
b.append("<tr valign=\"top\">");
b.append("<td><p>" + name + "</p></td>");
b.append("<td><p>" + value.toString() +
"</p></td>");
b.append("</tr>");
}
b.append("</table>");
}
printTableLine(out, "Attributes:", b);
Web−Anwendungen mit Java
261
Snoop−Servlet
/* Zeichenkodierung */
printTableLine(out, "Character Encoding:",
request.getCharacterEncoding());
/* Anzahl Bytes */
printTableLine(out, "Content Length:",
request.getContentLength() + "");
/* Inhaltstyp */
printTableLine(out, "Content Type:",
request.getContentType());
/* Bevorzugte Lokalisierung */
printTableLine(out, "Locale:",
request.getLocale());
Web−Anwendungen mit Java
262
Snoop−Servlet
/* Alle Lokalisierungen */
b.setLength(0);
e = request.getLocales();
while (e.hasMoreElements())
{
b.append(e.nextElement());
if (e.hasMoreElements())
b.append(", ");
}
printTableLine(out, "Locales:", b);
/* Servlet−Paraeter */
b.setLength(0);
e = request.getParameterNames();
if (e.hasMoreElements())
{
Web−Anwendungen mit Java
263
Snoop−Servlet
b.append("<table border=\"1\">");
while (e.hasMoreElements())
{
String name = (String) e.nextElement();
String[] values =
request.getParameterValues(name);
for (int i = 0; i < values.length; i++)
{
b.append("<tr valign=\"top\">");
b.append("<td><p>" +
(i == 0 ? name : " ") +
"</p></td>");
b.append("<td><p>" +
values[i].toString() +
"</p></td>");
b.append("</tr>");
}
}
b.append("</table>");
}
printTableLine(out, "Parameters:", b);
Web−Anwendungen mit Java
264
Snoop−Servlet
/* Protokoll, z.B. "HTTP/1.0" */
printTableLine(out, "Protocol:",
request.getProtocol());
/* IP−Adresse des Clients */
printTableLine(out, "Remote Address:",
request.getRemoteAddr());
/* Domain−Name des Clients */
printTableLine(out, "Remote Host",
request.getRemoteHost());
/* Schema (i.d.R. "http") */
printTableLine(out, "Scheme:",
request.getScheme());
/* Domain−Name des Servers */
printTableLine(out, "Server Name:",
request.getServerName());
Web−Anwendungen mit Java
265
Snoop−Servlet
/* Nummer des Server−Ports */
printTableLine(out, "Server Port:",
request.getServerPort() + "");
/* Sicherer (verschlüsselter) Zugriff? */
printTableLine(out, "Secure:",
request.isSecure() + "");
out.println("</table>");
/* Informationen zum Request (HTTP−spezifisch) */
out.println("<h2>HTTP Servlet Request</h2>");
out.println("<table border=\"1\">");
/* Authentifizierungstyp */
printTableLine(out, "Auth Type:",
request.getAuthType());
/* Kontextpfad */
printTableLine(out, "Context Path:",
request.getContextPath());
Web−Anwendungen mit Java
266
Snoop−Servlet
/* Cookies */
b.setLength(0);
Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length; i++)
b.append(toHTML(cookies[i]));
printTableLine(out, "Cookies:", b);
/* HTTP−Header */
b.setLength(0);
e = request.getHeaderNames();
if (e.hasMoreElements())
{
b.append("<table border=\"1\">");
while (e.hasMoreElements())
{
String name = (String) e.nextElement();
Enumeration values =
request.getHeaders(name);
Web−Anwendungen mit Java
267
Snoop−Servlet
while (values.hasMoreElements())
{
b.append("<tr valign=\"top\">");
b.append("<td><p>" + name +
"</p></td>");
b.append("<td><p>" +
values.nextElement() +
"</p></td>");
b.append("</tr>");
}
}
b.append("</table>");
}
printTableLine(out, "Header:", b);
/* HTTP−Methode */
printTableLine(out, "Method:",
request.getMethod());
Web−Anwendungen mit Java
268
Snoop−Servlet
/* Pfad−Info */
printTableLine(out, "Path Info:",
request.getPathInfo());
/* Pfad im Server−Dateisystem */
printTableLine(out, "Path Translated:",
request.getPathTranslated());
/* Query−String */
printTableLine(out, "Query String:",
request.getQueryString());
/* Name des authentifizierten Benutzers */
printTableLine(out, "Remote User",
request.getRemoteUser());
/* ID der vom Client gewünschten Session */
printTableLine(out, "Requested Session ID:",
request.getRequestedSessionId());
Web−Anwendungen mit Java
269
Snoop−Servlet
/* URI des HTTP−Requests */
printTableLine(out, "Request URI:",
request.getRequestURI());
/* Servlet−Pfad */
printTableLine(out, "Servlet Path:",
request.getServletPath());
/* Session */
printTableLine(out, "Session:",
request.getSession());
/* Authentifizierter Benutzer */
printTableLine(out, "User Principal:",
request.getUserPrincipal());
/* Angeforderte Session−ID aus Cookie? */
printTableLine
(out, "Is requested session ID from Cookie:",
request.isRequestedSessionIdFromCookie() +
"");
Web−Anwendungen mit Java
270
Snoop−Servlet
/* Angeforderte Session−ID aus URL? */
printTableLine
(out, "Is Requested Session ID From URL:",
request.isRequestedSessionIdFromURL() + "");
/* Angeforderte Session−ID gültig? */
printTableLine
(out, "Is Requested Session ID Valid:",
request.isRequestedSessionIdValid() + "");
/* Besitzt authentifizierte Benutzer die
* spezifizierte Rolle? */
printTableLine(out, "Is user in role \"Foobar\":",
request.isUserInRole("Foobar") +
"");
/* Body des HTTP−Requests, soweit noch nicht
* ausgewertet */
if (request.getMethod().equals("POST"))
{
Web−Anwendungen mit Java
271
Snoop−Servlet
StringBuffer sb = new StringBuffer(500);
int c;
/* Versuche, den Reader aus dem Request
* zu bekommen. Falls das mißlingt, weiche
* auf den InputStream aus. */
try
{
/* Zeichen aus Reader lesen */
Reader r = request.getReader();
do
{
c = r.read();
if (c != −1)
sb.append((char) c);
}
while (c != −1);
}
Web−Anwendungen mit Java
272
Snoop−Servlet
}
catch (IllegalStateException ex)
{
/* Zeichen aus InputStream lesen */
InputStream r = request.getInputStream();
do
{
c = r.read();
if (c != −1)
sb.append((char) c);
}
while (c != −1);
}
String s = sb.toString();
printTableLine(out, "Data submitted:",
s.equals("")
? " "
: "<pre>" + sb.toString() +
"</pre>");
Web−Anwendungen mit Java
273
Snoop−Servlet
out.println("</table>");
}
out.println("</div>");
out.println("</body>");
out.println("</html>");
out.println();
/**
* <p>Liefert HTML−Darstellung eines Cookies.</p>
*/
String toHTML(Cookie c)
{
StringBuffer b = new StringBuffer();
b.append("<table border=\"1\"");
Web−Anwendungen mit Java
274
Snoop−Servlet
b.append("<tr>");
b.append("<td><p>Name:</p></td>");
b.append("<td><p>");
b.append(c.getName());
b.append("</p></td>");
b.append("</tr>");
b.append("<tr>");
b.append("<td><p>Comment:</p></td>");
b.append("<td><p>");
b.append(c.getComment());
b.append("</p></td>");
b.append("</tr>");
b.append("<tr>");
b.append("<td><p>Domain:</p></td>");
b.append("<td><p>");
b.append(c.getDomain());
b.append("</p></td>");
b.append("</tr>");
Web−Anwendungen mit Java
275
Snoop−Servlet
b.append("<tr>");
b.append("<td><p>MaxAge:</p></td>");
b.append("<td><p>");
b.append(c.getMaxAge());
b.append("</p></td>");
b.append("</tr>");
b.append("<tr>");
b.append("<td><p>Path:</p></td>");
b.append("<td><p>");
b.append(c.getPath());
b.append("</p></td>");
b.append("</tr>");
b.append("<tr>");
b.append("<td><p>Secure:</p></td>");
b.append("<td><p>");
b.append(c.getSecure());
b.append("</p></td>");
b.append("</tr>");
Web−Anwendungen mit Java
276
Snoop−Servlet
b.append("<tr>");
b.append("<td><p>Value:</p></td>");
b.append("<td><p>");
b.append(c.getValue());
b.append("</p></td>");
b.append("</tr>");
b.append("<tr>");
b.append("<td><p>Version:</p></td>");
b.append("<td><p>");
b.append(c.getVersion());
b.append("</p></td>");
b.append("</tr>");
}
b.append("</table>");
return b.toString();
Web−Anwendungen mit Java
277
Snoop−Servlet
/**
* <p>Bearbeitet POST−Request.</p>
*/
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
doGet(request, response);
}
}
Web−Anwendungen mit Java
278
Sicherheit
Web−Anwendungen können Ressourcen und
Funktionen enthalten, die nicht für jeden zugänglich
sein sollen.
Beispiel Online−Banking:
Kontoinhaber kann Überweisung durchführen.
Interessent ohne Konto kann Demokonto nutzen.
Sensible Daten müssen während des Transfers vor
Ausspähen und Verändern geschützt sein.
Beispiel Online−Banking:
Kontoauszug ist nur für den Nutzer selbst bestimmt.
Dritter darf Überweisung nicht verändern.
Web−Anwendungen mit Java
279
Sicherheitsanforderungen
Authentifizierung: Mechanismus, durch den ein
Kommunikationspartner dem anderen seine Identität
nachweist
Autorisierung: Mechanismus, der Interaktionen mit
Ressourcen auf bestimmte Benutzer beschränkt
Vertraulichkeit: Mechanismus, der sicherstellt, daß die
übertragene Information nur für die dazu Berechtigten
verfügbar ist und während der Übertragung nicht
kompromittiert wird
Integrität: Mechanismus, der sicherstellt, daß Dritte
keine Daten während des Transits verändern
Web−Anwendungen mit Java
280
Authentifizierungsmechanismen
Wer ist der Zugreifer?
HTTP Basic Authentication
Ältestes und am weitesten verbreitete Verfahren
User−ID und Kennwort werden de facto im Klartext
übertragen.
Base−64−Kodierung
Keine Authentifizierung des Servers
Unverschlüsselte Datenübertragung
Unsicher
Kryptographisch sicher mit HTTPS
Web−Anwendungen mit Java
281
Authentifizierungsmechanismen
HTTP Digest Authentication
Keine Übertragung des Kennworts
Client weist nach, daß er im Besitz des korrekten
Kennworts ist.
Challenge−/Response−Verfahren
Unverschlüsselte Übertragung der Nutzdaten
Keine weite Verbreitung
Web−Anwendungen mit Java
282
Authentifizierungsmechanismen
HTTPS Client Authentication
HTTPS: HTTP über SSL (Secure Socket Layer)
Kryptographisch starkes Authentifizierungsverfahren
Client benötigt Zertifikat (Public Key Certificate, PKC)
Verschlüsselte Übertragung des gesamten Verkehrs
(Benutzername, Kennwort, Nutzdaten)
Web−Anwendungen mit Java
283
Authentifizierungsmechanismen
Formularbasierte Authentifizierung
Eingabe von User−ID und Kennwort im HTML−Formular
Paßt zum visuellen Design der Anwendung
Felder j_username und j_password
FORM−Attribut ACTION lautet j_security_check.
<form action="j_security_check" method="post">
<p>Name:
<input name="j_username"></p>
<p>Kennwort: <input type="password"
name="j_password"></p>
<p><input type="submit" value="Login"></p>
</form>
Klartextübertragung von User−ID und Kennwort
Kryptographisch sicher mit HTTPS
Web−Anwendungen mit Java
284
Deklarative Sicherheit
Sicherheitseinstellungen außerhalb der
Anwendung
Einstellungen im Deployment descriptor
WEB−INF/web.xml
Gelten jeweils pro Anwendung
Für welche Ressourcen und für welche HTTP−
Methoden Beschränkungen einrichten?
Wer darf auf was wie zugreifen?
Welche Verfahren zur Authentifizierung und zur
Übertragung verwenden?
Web−Anwendungen mit Java
285
Programmierte Sicherheit
Sicherheitseinstellungen innerhalb der Anwendung
Unterschiedliches Verhalten der Anwendung je nach
Rolle des Benutzers
Beispiel (Rollen im E−Shop):
Anonymer Kunde darf Produktinformationen und Preise
lesen und natürlich Produkte bestellen.
Authentifizierter Kunde sieht Preise gemäß seiner
individuellen Rabattklasse.
Produktmanager aktualisiert Preise und
Produktinformationen.
Autorisierung sollte nur über Rollen erfolgen,
nicht über Benutzernamen.
Web−Anwendungen mit Java
286
Programmierte Sicherheit
Methoden in HttpServletRequest:
String getRemoteUser()
Name des authentifizierten Benutzers oder null
java.security.Principal getUserPrincipal()
Principal−Objekt des authentifizierten Benutzer oder null
Entspricht einer eindeutigen Identität, z.B. Person, Organisation,
Login−Name, Benutzergruppe
Wird von diversen Klassen in java.security.acl und
java.security.cert verwendet.
boolean isUserInRole(String role)
Stellt fest, ob authentifizierter Benutzer die angegebene
Rolle besitzt.
Web−Anwendungen mit Java
287
Benutzer und Rollen
Web−Anwendung benötigt Zuordnung
Benutzer
Kennwort
Rollen
Einrichten der Zuordnungen
nicht standardisiert
spezifisch für den jeweiligen Servlet−Container
Web−Anwendungen mit Java
288
Benutzer und Rollen bei Tomcat 4
Benutzer, Kennwort und Rollen stammen aus...
Datenbank: JDBCRealm
JNDI−Verzeichnisdienst, z.B. LDAP: JNDIRealm
Textdatei: MemoryRealm, liest aus conf/tomcat−
users.xml
Geeignet für geringe Benutzeranzahl
Keine Änderungen im laufenden Betrieb möglich, z.B.
Registrieren neuer Benutzer
Einstellungen gelten wahlweise
für alle Anwendungen,
für alle Anwendungen auf einem virtuellen Host,
für eine Anwendung.
Web−Anwendungen mit Java
289
Sicherheit konfigurieren
<security−constraint>
<web−resource−collection>
<web−resource−name>Test</web−resource−name>
<url−pattern>/Snoop/*</url−pattern>
<http−method>GET</http−method>
<http−method>POST</http−method>
</web−resource−collection>
<auth−constraint>
<role−name>Snooper</role−name>
<role−name>Webmaster</role−name>
</auth−constraint>
<user−data−constraint>
<transport−guarantee>CONFIDENTIAL</transport−guarantee>
</user−data−constraint>
</security−constraint>
Web−Anwendungen mit Java
290
Sicherheit konfigurieren
Einzelheiten siehe DTD web−app_2_3.dtd!
Element security−constraint
Trifft Sicherheitseinstellungen für eine oder mehr
Ressource−Collections.
Enthält web−resource−collection, auth−constraint, user−
data−constraint.
Element web−resource−collection
Spezifiziert eine Zusammenstellung von Ressourcen und
zugehörigen HTTP−Methoden.
Enthält url−pattern und http−method.
Web−Anwendungen mit Java
291
Sicherheit konfigurieren
Element url−pattern spezifiziert eine oder mehrere
Ressourcen.
Darf mehrfach vorkommen.
/foo/bar/*: alle mit »/foo/bar« beginnenden URIs
*.foobar: alle mit ».foobar« endenden URIs
Alle anderen Strings sind vollständige URIs.
Element http−method spezifiziert eine HTTP−Methode.
Darf mehrfach vorkommen.
Falls http−method fehlt: alle HTTP−Methoden
Web−Anwendungen mit Java
292
Sicherheit konfigurieren
Element auth−constraint
Enthält role−name.
Element role−name
Spezifiziert den Namen einer Rolle, die den Zugriff
gewährt.
Darf mehrfach vorkommen.
Web−Anwendungen mit Java
293
Sicherheit konfigurieren
Element user−data−constraint
Spezifiziert Einschränkungen für die Nutzdaten.
Enthält transport−guarantee.
Element transport−guarantee
Anforderungen für den Datentransport
NONE: keine Anforderungen. Daten dürfen im Klartext
übertragen werden.
INTEGRAL: Daten dürfen während des Transports
gelesen, aber nicht geändert werden. (Erfordert SSL.)
CONFIDENTIAL: Daten können während des
Transports nicht gelesen werden. (Erfordert SSL.)
Web−Anwendungen mit Java
294
Login
Zugriff auf die erste geschützte Ressource erfordert
Authentifizierung des Benutzers.
Deployment descriptor definiert
Authentifizierungsverfahren.
Beispiel (HTTP Basic Authentication):
<login−config>
<auth−method>BASIC</auth−method>
<realm−name>RootApplication</realm−name>
</login−config>
Beispiel (Digest Authentication):
<login−config>
<auth−method>DIGEST</auth−method>
<realm−name>RootApplication</realm−name>
</login−config>
Web−Anwendungen mit Java
295
Login
Web−Anwendungen mit Java
296
Login
Beispiel (Formularbasierte Authentifizierung):
<login−config>
<auth−method>FORM</auth−method>
<form−login−config>
<form−login−page>/Login.html</form−login−page>
<form−error−page>/LoginError.html</form−error−page>
</form−login−config>
</login−config>
Web−Anwendungen mit Java
297
Login
Web−Anwendungen mit Java
298
HTTPS
HTTPS: HTTP over SSL
SSL: Secure Socket Layer
Client authentifiziert den Server.
Server benötigt Schlüsselpaar
Privater Schlüssel
Öffentlicher, zertifizierter Schlüssel (Zertifikat)
Verschlüsselte Datenübertragung
Ausgefüllte Formularfelder
Persönliche Daten, Kennwörter, Kreditkartennummern
Daten vom Server
Web−Anwendungen mit Java
299
HTTPS mit Tomcat
Tomcat benötigt JSSE
JSSE: Java Secure Socket Extension
SSL benötigt RSA−Verschlüsselung
Seit 2000 patentfrei
Starke Kryptographie fällt nicht mehr unter das
amerikanische Kriegswaffenkontrollgesetz.
Sun Microsystems kann JSSE von exportiert werden.
Alternativen verfügbar
In J2SE SDK 1.4 bereits enthalten, sonst von
http://java.sun.com/products/jsse herunterladen
Web−Anwendungen mit Java
300