Java Enterprise Edition spotkanie nr 4 Java Server Pages c.d. 1
Opracował Jacek Sroka Implict variables & objects application javax.servlet.servletcontext np. application.log() lub getrealpath("/web-inf/licznik.txt") session javax.servlet.http.httpsession tylko jak <%@ page session="true" %> request javax.servlet.http.httpservletrequest response javax.servlet.http.httpservletresponse out javax.servlet.jsp.jspwriter page java.lang.object nieprzydatne, bo trzeba rzutować; lepiej używać this pagecontext javax.servet.jsp.pagecontext pozwala uzyskać session, application, config i out metody pozwalające pobierać i ustawiać atrybuty w różnych zasięgach przechowuje atrybuty dla zasięgu "page" (to samo żądanie i translation unit) forward() i include() exception java.lang.throwable tylko jak <%@ page iserrorpage="true" %> 2
Opracował Jacek Sroka Implict variables & objects config javax.servlet.servletconfig strony JSP też mogą mieć parametry Nazwa serwletu = <%= config.getservletname() %> <br/> Wartość parametru x = <%= config.getinitparameter("x") %> <servlet> <servlet-name>parametry</servlet-name> <jsp-file>/config.jsp</jsp-file> <init-param> <param-name>x</param-name> <param-value>ala</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>parametry</servlet-name> <url-pattern>/config.jsp</url-pattern> <!-- jak by nie było tego mapowania, byłyby dwa egzemplarze serwletu --> </servlet-mapping> 3
Opracował Jacek Sroka Deklaracja z Tomcata public void _jspservice(httpservletrequest request HttpServletResponse response) throws java.io.ioexception, ServletException { PageContext pagecontext = null; HttpSession session = null; Throwable exception = org.apache.jasper.runtime. JspRuntimeLibrary.getThrowable(request); if (exception!= null) { response.setstatus(httpservletresponse.sc_internal_server_error); } ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; try { response.setcontenttype("text/html; charset=utf-8"); pagecontext = JspFactory.getDefaultFactory().getPageContext (this, request, response, null, true, 8192, true); application = pagecontext.getservletcontext(); config = pagecontext.getservletconfig(); session = pagecontext.getsession(); out = pagecontext.getout();... 4
Opracował Jacek Sroka Statyczna inkluzja wartość atrybutu nie może być wyliczana <%@ include file="<%= wyr %>" %> nie odbywa się żadne żądanie, więc nie ma sensu przekazywać parametrów <%@ include file="inna.jsp?fiubździu=trelemorele" %> strony nie muszą się kompilować niezależnie - mogą dzielić zmienne (chociaż lepiej używać w tym celu pagecontext) 5
Opracował Jacek Sroka odpowiada RequestDispatcher.include() wartość atrybutu może być wyliczana można dodać parametr flush="true" (czy przed przekazaniem sterowania opróżnić bufor) 6
Opracował Jacek Sroka odpowiada RequestDispatcher.forward() wartość atrybutu może być wyliczana nie można użyć parametru flush 7
Opracował Jacek Sroka Przekazywanie parametrów <jsp:include page="..."> <jsp:param name="nazwa1" value="wartość1"/> <jsp:param name="nazwa2" value="<%= wyr %>"/> </jsp:include> 8
JavaBeans konwencja nazewnicza getxxx(), setxxx() i isxxx() publiczny, bezargumentowy konstruktor można serializować przy pomocy ObjectOutputStream package beany; public class Osoba { private String imię; private int wiek; private boolean królowabalu; public String getimię() { return imię; } public void setimię(string imię) { this.imię = imię; } public boolean iskrólowabalu() { return królowabalu; } public void setkrólowabalu(boolean królowabalu) { this.królowabalu = królowabalu; } public int getwiek() { return wiek; } } public void setwiek(int wiek) { this.wiek = wiek; } 9
Jak nie korzystać z JavaBeans w JSP formularz HTML <form action="osoba1.jsp"> Imię: <input type="text" name="imie" value="ala"/><br/> Wiek: <input type="text" name="wiek" value="24"/><br/> Królowa balu: <input type="checkbox" name="krolowabalu"/><br/> <input type="submit"/> </form> JSP (Osoba1.jsp) <%@ page import="beany.osoba" %> <% Osoba osoba = null; synchronized(session) { osoba = (Osoba) session.getattribute("osoba"); if (osoba == null) { osoba = new Osoba(); session.setattribute("osoba", osoba); } osoba.setimię(request.getparameter("imie")); osoba.setwiek(new Integer(request.getParameter("wiek"))); osoba.setkrólowabalu("on".equals(request.getparameter("krolowabalu"))); } %> Zapamiętano dane osoby! (<a href="pokazdaneosoby1.jsp">pokaż dane</a>) 10
Jak nie korzystać z JavaBeans w JSP c.d. JSP (PokażDaneOsoby1.jsp) <%@ page import="beany.osoba" %> <% Osoba osoba = null; synchronized(session) { osoba = (Osoba) session.getattribute("osoba"); if (osoba == null) { %> Nie było zapamiętanych osób! <% } else { %> Zapamiętano osobę <%= osoba.getimię()%>, o wieku <%= osoba.getwiek()%>, która <%= (osoba.iskrólowabalu()? "jest" : "nie jest") %> królową balu. <% } } %> 11
Korzystanie z JavaBeans przy pomocy akcji <jsp:usebean> atrybuty id obowiązkowa nazwa zmiennej scope domyślnie page class klasa beana (pełna nazwa) type typ zmiennej (pełna nazwa) beanname nazwa zserializowanego beana (np. beany.ala -> beany/ala.ser) lub nazwa klasy (w odróżnieniu od class może być wyliczana w trakcje żądania) możliwe kombinacje: class type jak nie istniał egzemplarz to zgłaszany jest InstantiationException class i type jeżeli egzemplarz nie istniał to jest tworzony beanname i type używa java.beans.beans.instantiate() 12
Przykład JSP <jsp:usebean id="osoba" type="osoba" scope="session" beanname="beany.ala"/> wygenerowany Serwlet Osoba osoba = null; synchronized (session) { osoba = (Osoba) session.getattribute("osoba"); if (osoba == null){ try { osoba = (Osoba) java.beans.beans.instantiate( getclass().getclassloader(), "beany.ala"); } catch (ClassNotFoundException exc) { throw new InstantiationException(exc.getMessage()); } catch (Exception exc) { throw new ServletException("Cannot create bean of class " + "beany.ala", exc); } session.setattribute("osoba", osoba); } } 13
Zawartość jsp:usebean zawartość elementu jsp:usebean jest wykonywana tylko, jeżeli nie odnaleziono istniejącego egzemplarza zawartość może, ale nie musi być skryptletem <jsp:usebean id="osoba" class="beany.osoba" scope="session"> <% osoba.setimię("ala"); osoba.setwiek(24); osoba.setkrólowabalu(false); %> </jsp:usebean> wygenerowany serwlet: synchronized (session) { osoba = (beany.osoba) session.getattribute("osoba"); if (osoba == null){ osoba = new beany.osoba(); session.setattribute("osoba", osoba); } } osoba.setimię("ala"); osoba.setwiek(24); osoba.setkrólowabalu(false); 14
Korzystanie z JavaBeans przy pomocy akcji c.d. <jsp:setproperty> atrybuty name obowiązkowa nazwa zmiennej property obowiązkowa nazwa zmienianej właściwość value nowa wartość param parametr żądania możliwe kombinacje: value param jak nie ma takiego parametru żądania, to wartość nie ulega zmianie; jak ma kilka wartości, to brana jest pod uwagę tylko pierwsza ani value ani param param ma wartość property jako property można podać "*" <jsp:getproperty name="..." property="..."> 15
Jak korzystać z JavaBeans w JSP formularz HTML <form action="osoba2.jsp"> Imię: <input type="text" name="imie" value="ola"/><br/> Wiek: <input type="text" name="wiek" value="25"/><br/> <table> <td>królowa balu:</td> <td> <input type="radio" name="krolowabalu" value="true" checked="1"/>tak <br/> <input type="radio" name="krolowabalu" value="false" />Nie </td> </table> <input type="submit"/> </form> JSP (Osoba2.jsp) <%@ page import="beany.osoba" %> <jsp:usebean id="osoba" class="beany.osoba" scope="session"/> <jsp:setproperty name="osoba" property="*"/> <%-- uwaga na polskie litery --%> <jsp:setproperty name="osoba" property="imię" param="imie"/> Zapamiętano dane osoby! (<a href="pokazdaneosoby2.jsp">pokaż dane</a>) 16
Jak korzystać z JavaBeans w JSP c.d. JSP (PokażDaneOsoby2.jsp) <%@ page import="beany.osoba" %> <% boolean czybyłaosoba = true; %> <jsp:usebean id="osoba" class="beany.osoba" scope="session"> <% czybyłaosoba = false; %> </jsp:usebean> <% if (!czybyłaosoba) { %> Nie było zapamiętanych osób! <% } else { %> Zapamiętano osobę <jsp:getproperty name="osoba" property="imię"/>, o wieku <jsp:getproperty name="osoba" property="wiek"/>, która <%= (osoba.iskrólowabalu()? "jest" : "nie jest") %> królową balu. <% } %> 17
Konwersja typów Zazwyczaj silnik JSP jest za nas w stanie wykonać konwersję typów (z wyjątkiem wyrażenia wyliczanego w chwili wykonania dla parametru value) bean: public class Abecadło { private char[] litery; public char[] getlitery() { return litery; } public void setlitery(char[] litery) { this.litery = litery; } } link: IndeksowaneWlasciwosci.jsp?litery=Ala&litery=Ela&litery=Ola&litery=Ula strona: <%@ page import="beany.abecadło" %> <jsp:usebean id="abecadło" class="beany.abecadło"/> <jsp:setproperty name="abecadło" property="litery"/> <jsp:getproperty name="abecadło" property="litery"/> <%-- zazwyczaj będziemy jednak chcieli wypisać elementy tablicy --%> <br/> <% for (char c : abecadło.getlitery()) out.println(c); 18 %>
Bezpieczeństwo 19
Podstawowe pojęcia uwierzytelniania (authentication) autoryzacja (authorization) atrybuty bezpieczeństwa informacji integralność danych (data integrity) poufność (confidentiality) tylko ktoś autoryzowany ma dostęp do danych, ale na wszelki wypadek podsłuchujący nic nie zrozumieją dostępność (availability) audyt (auditing) rewizje kodu (peer-to-peer code reviews) zaokrąglanie transakcji bankowych co robić z ryzykiem: unikać, ograniczać, zaakceptować, przenieść 20
Mechanizmy uwierzytelniania użytkowników w aplikacjach WWW Mechanizmy uwierzytelniania uż. według specyfikacji Serwletów HTTP Basic authentication HTTP Digest authentication HTTPS Client authentication FORM-based authentication 21
HTTP Basic authentication Mechanizm zdefiniowany w specyfikacji HTTP 1.1 Przeglądarka nie wie, że wymagane jest uwierzytelnianie GET /servlet/testservlet HTTP/1.1 Zamiast zasobu odsyłana jest prośba o uwierzytelnienie HTTP/1.1 401 Unauthorized Server: Tomcat/5.0.25 WWW-Authenticate: Basic realm="sales" Content-Length=500 Content-Type=text/html <html> jakiś komunikat </html> Przeglądarka wyświetla okienko z prośbą o zalogowanie Przeglądarka ponawia żądanie do zasobu, dodając zakodowaną przy pomocy Base64 parę login:hasło GET /servlet/testservlet HTTP/1.1 Authorization: Basic am9objpqamo= Serwer sprawdza nadesłane wartości i albo odsyła zasób, albo ponawia komunikat 401 22
Opracował Jacek Sroka HTTP Digest authentication HTTP Basic authentication gdzie zamiast loginu i hasła jest przesyłany skrót MD5
Opracował Jacek Sroka HTTPS Client authentication Komunikacja HTTP jest przepuszczana przez SSL SSL przewiduje opcjonalny mechanizm uwierzytelniania klienta Klient posiada własny certyfikat (zgodny z X.509) i jest uwierzytelniany na jego podstawie
Opracował Jacek Sroka FORM-based authentication Mechanizm podobny do HTTP Basic authentication, ale zamiast okienka przeglądarki login i hasło pobierane jest z formularze Wymagania względem formularza action="j_security_check" pole j_username pole j_password należy używać metody post
Wady/zalety HTTP Basic authentication łatwy w realizacji niebezpieczne, bo Base64 to nie wspierany przez wszystkie szyfrowanie przeglądarki nie można wpłynąć na wygląd okienka dialogowego HTTP Digest authentication bezpieczniejszy od Basic auth. w MS IE od wersji 5 niewymagane przez specyfikację i rzadko wspierane HTTPS Client authentication najbezpieczniejszy wymaga certyfikatów klienta wspierany przez wszystkie przeglądarki FORM-based authentication łatwy w realizacji niebezpieczne wspierany przez wszystkie przeglądarki łatwo dopasować wygląd formularza 26
Deklaratywne zabezpieczanie aplikacji WWW... <login-config> <!--BASIC DIGEST CLIENT-CERT FORM--> <auth-method>basic</auth-method> <realm-name>mim</realm-name> </login-config>... <login-config> <!--BASIC DIGEST CLIENT-CERT FORM--> <auth-method>form</auth-method> <form-login-config> <form-login-page>/login.jsp</...> <form-error-page>/error.jsp</... </form-login-config> </login-config>... <security-role> <description> bla bla bla </description> <role-name>role1</role-name> </security-role> <security-role> <role-name>tomcat</role-name> </security-role>... 27
Deklaratywne zabezpieczanie aplikacji WWW c.d.... <security-constraint> <web-resource-collection> <web-resource-name>kolekcja1</web-resource-name> <url-pattern>/index.html</url-pattern> <url-pattern>/index.jsp</url-pattern> <http-method>get</http-method> <http-method>post</http-method> <!-- wszystkie pozostałe metody są niezabezpieczone --> <!-- zamiast wymieniać wszystkie metody można nie podać żadnej --> </web-resource-collection> <auth-constraint> <role-name>role1</role-name> <!-- * oznacza wszystkie role wymienione w deskryptorze --> </auth-constraint> <user-data-constraint> <!-- NONE INTEGRAL CONFIDENTIAL --> <transport-guarantee>confidential</transport-guarantee> </user-data-constraint> </security-constraint>... 28
Programistyczne zabezpieczanie aplikacji WWW Przydatne metody HttpServletRequest: String getauthtype() null HttpServletRequest.BASIC_AUTH, HttpServletRequest.FORM_AUTH, HttpServletRequest.CLIENT_CERT_AUTH, HttpServletRequest.DIGEST_AUTH java.security.principal getuserprincipal() //w znaczeniu zlecaniodawca String getremoteuser() boolean isuserinrole(string) Wylogowanie użytkownika (tylko dla metody FORM) session.invalidate() 29
Mapowanie ról Ponieważ w podejściu programistycznym nazwy ról są na stałe wpisane w kodzie, żeby skonfigurować aplikację po napisaniu należy zmapować je na rzeczywiste role używane przez kontener <servlet>... <security-role-ref> <role-name>alamakota</role-name> <role-link>tomcat</role-link> </security-role-ref>... </servlet> 30
Czy nie lepiej wszystko zrobić samemu Opracowywanie nowych algorytmów kryptograficznych, protokołów uwierzytelniania, systemów kontroli dostępu wymaga lat doświadczenia Łatwo coś przeoczyć Dużo kosztownej pracy, z której mało pożytku 31
Nie tylko dobra aplikacja Konfiguracja aplikacji zmiana domyślnych haseł Konfiguracja serwera aplikacji zmiana domyślnych haseł poprawna konfiguracja usług serwera (np. JNDI) Konfiguracja sieci ataki typu man-in-the-middle ataki typu denial-of-service 32