Document

Werbung
Ü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
Herunterladen