V tomto, už devätnástom, článku o servletoch začneme s problematikou bezpečnosti. Na úvod to bude HTTP autentifikácia, neskôr si povieme niečo o digitálnych certifikátoch a nakoniec o možnostiach SSL (Secure Sockets Layer). V doterajších článkoch sme ticho predpokladali, že naše servlety existujú v perfektnom svete, kde každý je dôveryhodný a kde nikto nezatvára na noc dvere. Lenže pravda je taká, že čoraz viac spoločností využíva e-commerce typu B2C a B2B, pričom problematika bezpečnosti a dôveryhodnosti sa postupne stala najdôležitejšou oblasťou pri tvorbe webových aplikácií.

Informačná bezpečnosť je istý druh vedy o tom, ako udržať citlivé informácie v rukách dôveryhodných ľudí bez toho, aby prišlo k neželanému úniku týchto skutočností. Z pohľadu webu ide o tri kľúčové oblasti: Autentifikácia, Dôveryhodnosť a Integrita.

Tri kľúčové oblasti bezpečnosti - A.D.I.

Zámerom webového klienta je mať istotu, že komunikuje s overeným serverom, a tiež, že počas prenosu nepríde k odchytávaniu prenášaných informácií (číslo kreditnej karty, heslo, ID a ďalšie). Podobne aj server má záujem o spoľahlivú autentifikáciu a dôveryhodnosť. Ak napríklad nejaká spoločnosť poskytuje služby zákazníkom alebo citlivé informácie zamestnancom prostredníctvom intranetu, respektíve extranetu, je v jej záujme, aby k nim mal prístup len autorizovaný subjekt. V neposlednom rade obidve strany potrebujú mať istotu, že informácie, ktoré si vymieňajú, dostane druhá strana v nezmenenej podobe.

Autentifikácia, dôveryhodnosť a integrita sú úzko prepojené s technológiou digitálnych certifikátov. Tieto certifikáty umožňujú serveru a klientovi používať dômyselné kryptografické techniky na zabezpečenie dát. Java má zabudovanú podporu používania digitálnych certifikátov a servlety tak predstavujú vhodnú platformu na nasadzovanie bezpečných aplikácií pre web.

Bezpečnosť je tiež o tom, aby sa hacker nedostal k citlivým dátam uloženým na web serveri. Keďže Java je od základu postavená ako bezpečný a sieťovo orientovaný jazyk, je možné využiť jeho bezpečnostné prvky a zároveň si byť istý, že serverové doplnky od tretích strán sú minimálne tak bezpečné ako vaše vlastné.

HTTP autentifikácia

Protokol HTTP poskytuje základný typ autentifikácie (BASIC AUTHENTICATION) založený na modeli výzva-odpoveď/meno-heslo. Pomocou tejto techniky môže web server spravovať databázu mien a hesiel a identifikovať niektoré zdroje (súbory, adresáre, servlety a ďalšie) ako chránené. Keď klient požiada o prístup k chránenému zdroju, server odošle žiadosť o zadanie mena a hesla. V tomto bode zobrazí browser špeciálne prihlasovacie okno, do ktorého môže užívateľ zadať potrebné údaje. Tieto údaje sa odošlú na server a ten ich overí s údajmi v databáze. Ak sa zhodujú, prístup je povolený. Celý proces autentifikácie je manažovaný samotným serverom.

Základný typ autentifikácie je veľmi slabý, čo sa týka bezpečnosti. Nezabezpečuje dostatočnú dôveryhodnosť a už vôbec nie integritu. Problémom je, že heslá prenášané cez sieť sú iba chabo zabezpečené veľmi dobre známym a ľahko prelomiteľným Base64 kódovaním. Ktokoľvek, kto monitoruje TCP/IP komunikáciu, môže ľahko a rýchlo získať prístup k neželaným informáciám vrátane mena a hesla. Ďalší aspekt, prečo HTTP autentifikácia nie je celkom ideálna, je to, že heslá sú často uložené na servery ako čistý text. Ak príde k narušeniu servera zvonka, ktokoľvek si môže heslá prečítať. Ak to mám zhrnúť, tak HTTP autentifikácia je síce lepšia ako nič, ale aplikácie, ktorých ochrana je založená výhradne na tomto systéme, nemôžeme považovať za zabezpečené.

Variantom základnej schémy autentifikácie poskytujúcim lepšie zabezpečenie je autentifikácia založená na súhrnnom výbere (DIGEST AUTHENTICATION). Spočíva v tom, že tento výber je vytvorený ako hash (použitím bezpečného MD5 kryptovacieho algoritmu) z mena, hesla, URI, HTTP typu požiadavky (get, post, put, delete) a náhodne generovanej unikátnej hodnoty poskytnutej serverom. Obidve strany (server a klient) poznajú heslo a použijú ho na vytvorenie spomenutého hashu, respektíve súhrnného výberu. Ak si tieto hodnoty odpovedajú, prístup je klientovi povolený. Takýto spôsob komunikácie je oveľa bezpečnejší, pretože súhrnný výber (hash) je platný len pre jediné URI a náhodne generovanú hodnotu. Napriek tomu server stále musí spravovať databázu originálnych hesiel. Tento spôsob autentifikácie musí však podporovať ako server tak aj browser.

Autentifikácia klientov je často riadená na úrovni servera. Administrátor nastaví zdroje, ktoré majú byť chránené, a tiež užívateľov, ktorí k nim majú prístup. Informácie o užívateľoch (skupiny, mená, heslá) sú uložené vo forme dostupnej pre server, teda server ich vie čítať, prípadne s nimi manipulovať. Niekedy však požadovaná schéma bezpečnosti nemôže byť implementovaná priamo serverom. Napríklad informácie o užívateľoch musia byť uložené vo forme nečitateľnej pre server. Vtedy je možné využiť možnosti a schopnosti servletov. Servlet môže byť vytvorený tak, že je schopný získavať informácie o užívateľoch zo špeciálne formátovaných súborov alebo relačných databáz. Môže implementovať akúkoľvek bezpečnostnú politiku podľa vašich potrieb.

Nanešťastie jedinými dvoma metódami z Java Servlet API, ktoré majú niečo spoločné s bezpečnosťou, sú getAuthType() a getRemoteUser(). Je to zrejme dané tým, že každý web server podporuje vlastný systém bezpečnosti a týka sa to aj HTTP autentifikácie. (Keďže v týchto článkoch sa zameriavam na server Tomcat, neskôr si ukážeme, ako vytvoriť systém zabezpečenia práve na ňom.) Pri HTTP autentifikácii využíva servlet zodpovedný za prihlásenie užívateľa údaje z HTTP hlavičky, konkrétne z hlavičky Authorization. Ak má byť prístup zamietnutý, klientovi sa odošle status kód SC_UNAUTHORIZED s hlavičkou WWW-Authenticate.

Hlavička Authorization poslaná klientom obsahuje prihlasovacie meno a heslo užívateľa. Pri základnom type HTTP autentifikácie (BASIC AUTHENTICATION) obsahuje hlavička reťazec meno:heslo zakódované v Base64. Následne môže servlet reagovať poslaním hlavičky WWW-Authenticate ako som už spomenul, v ktorej je uvedené, voči ktorej autorizačnej schéme a doméne (realm) bude klient verifikovaný. Realm je vlastne množina užívateľských účtov a chránených zdrojov prislúchajúcich k jednotlivým účtom.

Nasledujúci príklad ukazuje servlet, ktorý realizuje HTTP autentifikačný mechanizmus. Zoznam užívateľov a hesiel je priamo obsiahnutý v kóde. Ale to len pre jednoduchosť. V produkčnom servlete by sme využili externý a chránený zdroj užívateľských dát (XML, databázu, properties súbor a podobne). Aby sme mohli získať zakódované prihlasovacie meno a heslo, budeme potrebovať nejaký Base64 dekodér. Ja som použil sun.misc.BASE64Decoder, ktorý si môžete voľne stiahnuť z internetu. Ak by vás zaujímali nejaké detaily ohľadom Base64 kódovania, nájdete ich na http://www.ietf.org/rfc/rfc1521.txt.

package interval;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import sun.misc.BASE64Decoder;
public class AuthServlet extends HttpServlet {
  Hashtable users = new Hashtable();
  public void init(ServletConfig config) throws ServletException {
    super.init(config);
    users.put(„Jano:superman“,“OK“);
    users.put(„Fero:batman“,“OK“);
    users.put(„Juro:daredevil“,“OK“);
   }
  public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
     PrintWriter out = res.getWriter();
  //získame obsah hlavičky Authorization
  String auth = req.getHeader(„Authorization“);
  //zistíme či povolíme vstup tomuto užívateľovi
  if (!allowUser(auth)) {
    //nepovolíme, preto mu to dáme vedieť
    res.setHeader(„WWW-Authenticate“, „BASIC realm=’comics'“);
    res.sendError(res.SC_UNAUTHORIZED);
  }
  else {
    //povolíme a ukážeme mu supertajnú stránku
    out.println(„Top-secret page #1“);
   }
   }
  //táto metóda porovná informácie o užívateľovi
  //s informáciami uloženými v hash tabuľke
  protected boolean allowUser(String auth) throws IOException {
    if (auth == null) return false;//žiadna autentifikácia
    if (!auth.toUpperCase().startsWith(„BASIC „))
    //tento servlet zvláda len BASIC autentifikáciu
       return false;
    //získame zakódované meno:heslo nasledujúce po BASIC
    String userpassenc = auth.substring(6);
    //dekódujeme ho použijúc Base64 dekodér
    BASE64Decoder dec = new BASE64Decoder();
    String userpassdec = new String(dec.decodeBuffer(userpassenc));

    //skontrolujeme či máme takého usera a heslo v zozname
    //ak áno povolíme mu vstup
    if („OK“.equals(users.get(userpassdec)))
      return true;
     else
      return false;
   }
}

Napriek tomu, že web server umožní prístup k nášmu servletu, servlet samotný zobrazí chránené informácie len tým užívateľom, ktorí sa správne autentifikujú. Servlet by mohol byť ešte modifikovaný, napríklad tak, že užívateľ, ktorý sa prihlási ako „anonymous“ a zadá svoj email, bude mať umožnený prístup s určitými obmedzeniami.

Uvedený spôsob autentifikácie môže byť použitý nie len pre obmedzenie prístupu k jedinému servletu. Môžete vytvoriť napríklad servlet, umožňujúci prehliadať súbory na disku alebo rôzne databázové tabuľky. A prostredníctvom autentifikácie môžete riadiť prístup k týmto zdrojom. Výhodou tohto spôsobu ochrany je, že umožňuje prekonať bezpečnostné limity servera a zvýšiť tak bezpečnosť vašich aplikácií.

V budúcom článku sa pozrieme na spôsob autentifikácie vyžívajúci HTML formulár. A samozrejme si spravíme pár ukážkových príkladov.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět