Tipy pro zabezpečení webu

Zdroj: SOOM.cz [ISSN 1804-7270]
Autor: Emkei
Datum: 15.4.2010
Hodnocení/Hlasovalo: 1.15/300

Neustále se Vaše webová prezentace stává obětí různých útočníků, ať už těch fyzických nebo softwarových? Zabezpečili jste si svůj web, a přesto je opět kompromitován? Poradíme Vám, jak se efektivně bránit pomocí méně známých, ovšem o to účinnějších postupů a jak aplikovat bezpečnostní model Defense in Depth.

Úvod

CyberspaceRozhodně není pochyb o tom, že článků na téma bezpečnost webových aplikací je dostatek, byť se ne vždy jedná o rady hodné následování či aplikovatelné v reálném prostředí. Proto jsem se rozhodl nezmiňovat zde žádné metody zabraňující různým typům injekcí, XSS atp., ale zaměřit se na méně známé či dokonce pro mnohé neznámé tipy a triky zvyšující odolnost vašich Internetových aplikací. Většina níže uvedených snippetů je součástí redakčního systému SOOMu, můžete si tak při čtení zároveň ověřit jejich účinnost v praxi.


Clickjacking

Oblíbené to téma poslední doby, přestože je tu s námi tato metoda již mnoho let. Spočívá v překrytí napadené aplikace stránkou útočníka, která vyzve uživatele ke klikání na určitá místa v neškodně vyhlížejícím okně. Proklik se ovšem projeví na aplikaci "za" touto stránkou a oběť tak nevědomky manipuluje s naprosto jinou službou (webkamerou, internetbankingem, e-mailem, profilem atp.), což s sebou samozřejmě přináší nemalá rizika.

Obrana je naštěstí v celku jednoduchá, stačí vložit do sekce <head> následující kus javascriptového kódu, který znemožní načtení vašich webových stránek v jakémkoli rámu (iframe):

Občas ovšem takový bezpečnostní prvek může překážet, např. rozhodnete-li se využít služby, která Vaše stránky v rámu načítá (např. různé analytické služby pro tvůrce webových stránek). Za ochranu vašich uživatelů to ale rozhodně stojí.


Cookies

U vámi nastavovaných cookies vždy aktivujte příznak HTTPOnly, který zajistí, že s nimi nebude možné manipulovat prostřednictvím JavaScriptu. Tento flag podporuje většina soudobých prohlížečů, čímž se stal kladivem na dříve jeden z nejrozšířenějších útoků, tzv. Cookie Stealing. Aktivace lze provést na více úrovních, globálně v php.ini nebo prostřednictvím konfiguračního souboru .htaccess

případně přímo v PHP scriptech, konkrétně pátým parametrem funkce session_set_cookie_params(), respektive pro jednotlivá cookies následovně:

Výraz NULL zastupuje výchozí hodnotu, nahraďte jej v případě potřeby optimálními daty pro svoji aplikaci, viz manuálové stránky. Sedmý parametr (TRUE) aktivuje příznak HTTPOnly.

Pokud se útočníkovi přesto podaří cookie přihlášeného uživatele získat, pak ještě nemusí být vše ztraceno. Při autentizaci uživatele archivujte mj. i jeho IP adresu a User-Agenta. Pokud se tyto informace během sezení změní, pak je okamžitě ukončete a uživatele odhlaste, neboť je velká pravděpodobnost, že mu bylo cookie odcizeno. U IP adresy ideálně kontrolujte pouze první 3 oktety, stále totiž existuje mnoho uživatelů s dynamickým rozsahem.


Cookie Fixation

Tato metoda vychází z předpokladu, že se útočníkovi podaří podstrčit oběti jemu známé cookie, se kterým se uživatel následně přihlásí. Jelikož útočník hodnotu takového cookie zná, není pro něj problém přihlásit se současně s obětí, a to bez znalosti přístupového hesla.

Obrana proti takovému útoku je více než jednoduchá, po úspěšném přihlášení uživatele zavolejte (v případě PHP) funkci

která zajistí vygenerování nového identifikátoru sezení (PHPSESSID) a smaže ten předchozí, útočník tak nebude mít šanci.

Přegenerování tohoto ID (nemusí se nutně jmenovat PHPSESSID) navíc komplikuje práci lidem tvořícím automatizované boty, jež se k takto zabezpečeným službám přihlašují. Musejí totiž po odeslání přihlašovacích údajů aktualizovat cookie, se kterým doposud pracovali. To si ne každý uvědomí a ochrana tak odfiltruje přinejmenším méně zdatné útočníky.


Kompilace zdrojových souborů

Máte-li na svém serveru možnost použít některý z kompilátorů jazyka PHP, pak rozhodně neváhejte, v opačném případě požádejte správce o doinstalování takového balíčku. Osobně používám BCompiler a jsem zcela spokojen. Nedoporučuji ovšem kompilovat veškeré vaše scripty, neboť taková aplikace se obtížně spravuje (je nutné mít zálohu nekompilovaných souborů a ty v případě potřeby aktualizovat, zkompilovat a následně nahrát na produkční server místo těch původních, dekompilace totiž není možná). Zkompilujte proto především soubory s citlivými údaji, tedy například script zajišťující přístup k databázi. Kompilace se provádí následovně:

Kompilovaný kód má ovšem jednu podstatnou nevýhodu, kterou jsem vám dosud zatajil, a sice, že při jeho otevření jsou ve změti tisknutelných i netisknutelných znaků čitelné stringy z nekompilované verze, tedy včetně přístupového hesla. Tato nechtěná vlastnost se dá ovšem snadno vyřešit např. tím způsobem, že namísto klasického zadávání přístupových údajů v řetězci

předáme přihlašovací údaje v polích obohacených o změť náhodných znaků ($mysqlDust):

V kompilovaném souboru database.php tak bude pouze změť písmen a znaků, ze které útočník heslo pouhým okem nezíská. Script zajišťující připojení k databázi by pak mohl vypadat nějak následovně:

Takto zkompilované přihlašovací údaje jsou v relativním bezpečí, ačkoliv se k nim šikovný útočník může teoreticky stále dostat. Přesto však zmíněný bezpečnostní prvek odfiltruje drtivou většinu záškodníků, a jeho nasazení vřele doporučuji, chcete-li v případě kompromitace zdrojových kódu ochránit alespoň svoji databázi. Zároveň opatřete zkompilovaný soubor nenápadným jménem, přeci jen v případě database.php nebo config.php je to zcela jistě první soubor, na který se útočník zaměří. Volba zavádějícího jména (seo.php, style.php, tadyNicNeni.php, …) tak může rovněž kdejakému útočníkovi zamotat hlavu.


Iframe na konci stránky

Už jste někdy zažili, že se Vám na konci webové stránky objevil zákeřný iframe, který jste tam ovšem nevložili Vy? Pak nebuďte líní a vymažte si heslo z TotalCommanderu. Že si je ale nepamatujete? Napište si je tedy samostatně někam do nenápadného textového souboru. Takto uložené heslo, byť v plain-textu, je totiž mnohem bezpečnější než to zakódované v TotalCommanderu, pamatujte na to.

Občas se však stává, že vymažete heslo ze svého klienta, změníte přístupové kódy k FTP, nahrajete čistou webovou prezentaci ze zálohy, a přesto se zákeřný iframe objeví po nějakém čase znovu. V tom případě je možné, že je chyba přímo v zabezpečení zvoleného webhostingového serveru a vy s tím zdánlivě nic nenaděláte. Opak je ovšem pravdou. Vložte na úplný konec všech svých souborů nesoucích jméno "index" následující řádky:

Funkce exit() zajistí, že v případě vložení zákeřného kódu (obvykle na úplný konec souboru) nebudou vaše stránky žádným způsobem ovlivněny. Zpracování stránky totiž včas skončí a vše, co je za ní (malware), se již uživateli neodešle.


Ochrana proti botům a DoS

Tento bezpečnostní prvek sestává z jednoduchého snippetu, který s každým requestem na stránku zaznamená IP adresu, ze které tento požadavek přišel a číselný údaj, o kolikátý požadavek v pořadí se z této IP jedná. Přijde-li během počítání požadavek z jiné IP adresy, než se kterou aktuálně snippet pracuje, začne se počítat od nuly s novou IP. Pokud počet požadavků dosáhne u zpracovávané IP určité meze (řekněme 500 požadavků v řadě), pak se zcela jistě nejedná o požadavky generované člověkem, nýbrž strojem a příslušná IP je zablokována, např. pomocí konfiguračního souboru .htaccess. Takto lze efektivně odolávat masivním floodům v diskuzích, cíleným DoS útokům a jiným praktikám, za jejichž realizací stojí automatizovaní boti, nikoliv lidé. Nemusíte se bát, že byste neoprávněně zamezili přístup člověku, který si prohlíží Váš web např. v noci. I v noci by totiž jen těžko nevědomě vygeneroval 500 requestů na stránku, natož v dostatečně krátké době, aby ji mezi tím nestačil navštívit jiný uživatel či vyhledávací bot. Znáte-li modul mod_evasive pro Apache, pak výše uvedená funkce částečně supluje jeho nepřítomnost.


Deface stránky

Tato ochrana nepatří k těm preventivním, naopak, snaží se co možná nejvíce snížit dopad již úspěšně provedeného útoku, konkrétně deface úvodní stránky webové prezentace. Uložte si kopii Vašeho indexu mimo root webu a do CRONu přidejte pravidlo, které bude každou hodinu porovnávat zálohu indexu s jeho publikovanou verzi, např. pomocí kontrolních součtů či velikosti souborů. Neshoduji-li se tyto hodnoty, pak došlo ke změně indexu a je třeba jej nahradit tím ze zálohy a podat zprávu e-mailem správci systému, který tak má možnost okamžitě reagovat na deface úvodní stránky. Před nahrazením indexu ze zálohy nejprve zkopírujte upravenou verzi pro pozdější analýzu, nepřepisujte ji. Tento bezpečnostní prvek je zároveň nutné doplnit o detekci více indexů v rootu webu. Jmenuje-li se totiž Vaše úvodní stránka index.php, může útočník do stejné složky vložit upravený index s příponou html, kterou server (dle nastavení direktivy DirectoryIndex) upřednostní v zobrazení před Vaším skutečným indexem. Útočník nebyl nucen v původním indexu nic měnit, výše uvedená implementace by tedy správce serveru na útok neupozornila! Kontrolujte proto kromě CRC/velikosti publikovaného a zálohovaného indexu i výskyt dalších indexů v rootu webu a ty případně mažte. Pro kontrolu integrity indexu použijte raději kontrolní součty, ověření založené na velikosti obou souborů není těžké obelstít, přesto se jedná stále o lepší variantu než v případě žádné ochrany.

Zmíněný prvek má i několik praktických nevýhod. Provedete-li změnu v indexu, nesmíte zapomenout aktualizovat i zálohu mimo root webu, což s sebou přináší dodatečné povinnosti. Pokud navíc odlaďujete scripty přímo na produkčním serveru a přejmenujete dočasně původní index.php na index2.php, pak vám jej snippet (pravděpodobně, záleží na konkrétní implementaci) po chvíli smaže. Na druhou stranu uvedený bezpečnostní prvek skvěle doplňuje ochranu před škodlivým kódem na konci stránky.


SQLi Scannery

Pokud si někdo vyhlídne konkrétně váš web, pak vám následující ochrana příliš nepomůže, vhodná je ovšem k odfiltrování SQL Injection scannerů "běhajících" po Internetu bez interakce jejich majitelů. Takovým scannerům je totiž obvykle předložen seznam náhodně sesbíraných domén, které mají otestovat a v případě jakéhokoli problému skočí na další doménu v pořadí, aniž by se řešením vzniklých potíží zdržovali (nebylo by to totiž příliš efektivní). Hromadný scanner pracuje s různými hodnotami v URL parametrech a přitom porovnává kontrolní součty stránek, které načetl. Vyjdou-li mu ovšem s každým požadavkem na server jiné součty, pak vyhodnotí stránku jako nestabilní, neboť je její obsah neustále měněn a pro její exploitaci je nutná interakce člověka. To je samozřejmě v případě masového scanování neefektivní a naše doména se jednoduše přeskočí. Jak tedy můžeme docílit toho, aby byla webová prezentace vyhodnocena jako nestabilní? Přidejte do stránky, např. patičky, nějaký dynamický element, který se bude neustále měnit a ten pomocí kaskádových stylů skryjte. Nedoporučuji ovšem k tomuto účelu používat funkci time(), která pravděpodobně napadne každého nejdříve. Sofistikovanější scannery totiž při porovnávání stránek (respektive jejich kontrolních součtů) mohou vynechávat jakékoliv číselné hodnoty na stránce, čímž odfiltrují hodiny, veškerá počítadla a samozřejmě i výstup funkce time(), tudíž Vaše snaha přijde prakticky vniveč. Namísto zmíněné funkce zkuste použít něco obdobného, jako uvádím níže:



Generátor jedinečných identifikátorů

Už jste se dozajista někdy setkali s podivně vyhlížející URL, která v některém ze svých parametrů obsahovala dlouhou změť znaků, tzv. jedinečný identifikátor. Tyto identifikátory se užívají při aktivaci účtů, mazání souborů z veřejných úložišť, u formulářových tokenů zajišťujících obranu před CSRF, no prostě skoro na každém kroku. Jejich účel je jasný, identifikovat oprávněnou osobu a autorizovat ji. Problém je však v tom, jak moc velkou práci si dal programátor dané aplikace s vytvářením generátoru takových identifikátorů, které by měly být dozajista nepredikovatelné. Bohužel, jak už to v cyberspace bývá, mnohdy predikovatelné jsou. K tomu dochází v případech, kdy programátor namísto funkce pro práci s pseudonáhodnými čísly sáhne po funkci time(), kterou dále prožene nějakou hashovací či kódovací funkcí, aby to "nějak vypadalo". Pro útočníka pak není problém hodnotu takových identifikátorů odhadnout, respektive určitý rozsah vyzkoušet metodou pokus-omyl, čímž je neoprávněně autorizován. Generujte proto jedinečné identifikátory výhradně pomocí funkcí pracujících s pseudonáhodnými čísly a na funkci time() v takové chvíli zapomeňte. Jak by funkce pro generování nepredikovatelných identifikátorů mohla vypadat, ilustruje následující ukázka:



PHP Upload

Jak už jsem uvedl v úvodu samotného článku, nehodlám zde uvádět dokola omílané zásady tvorby bezpečných webových aplikací a zaměřím se pouze na méně známé tipy a triky. V případě uploadu tedy pouze připomenu, že se upřednostňuje whitelisting před blacklistingem a nespoléhá se výhradně na kontrolu souborů podle MIME typu (lze zfalšovat). Apache má navíc ohledně detekce typu souboru jeden podstatný neduh, pokud je mu totiž koncovka souboru neznámá, podívá se na tu předchozí. Soubor se jménem hack.php.x8nDj tedy přes blacklist projde, Apache jej ale přesto interpretuje jako PHP script, neboť koncovku x8nDj nezná. Máte-li opodstatněný důvod k nasazení blacklistingu, pak nezapomeňte, že suffix php je pouze jeden z mnoha, který mohou PHP scripty nést. Stejně tak dobře budou obvykle interpretovány i soubory s příponou php3 či phtml. Nezapomínejte zároveň zohlednit velikost písma, přes .php na blacklistu s přehledem projde script s příponou .PHP a bude interpretován. Při samotné kontrole suffixu souboru zahrňte do kontroly i tečku, obrázek by tedy měl končit řetězcem .png, nikoliv pouze png. V druhém případě totiž postačí podstrčit soubor se jménem hack.php.xxxpng, který vaší kontrolou projde, Apache jej však interpretuje jako PHP script, viz výše popisované chování.

Ne vždy si ale můžete dovolit uživatele omezit filtrováním přípustných suffixů, v takovém případě se jednoduše pro určitou složku a podsložky, kam jsou soubory nahrávány, vypne podpora scriptovacích jazyků. Se scriptem cokoliv.php je pak zacházeno jako s běžným textovým souborem a k jeho interpretaci nikdy nedojde. Připadá vám uvedený způsob bezpečný? Správná odpověď zní, že ne zcela. Správci takových aplikací totiž často zapomínají na jednu podstatnou věc, a sice, že si útočník může na server nahrát vlastní konfigurační soubor .htaccess, ve kterém si podporu scriptování opětovně povolí. Zamezte tedy uživatelům vkládat na server soubory se jménem ".htaccess", vyhnete se tak nemilým překvapením.

Ať už zvolíte jakoukoli formu uploadu, pokaždé byste měli do složky, kam umožníte uživatelům nahrávat soubory, umístit jako pojistku konfigurační soubor .htaccess obsahující řádek

který deaktivuje podporu scriptování v daném adresáři a všech podadresářích (aplikace přístupu Defense in Depth).


Ankety

Pokud se vám podaří na Internetu nalézt takovou anketu, kterou není možné zmanipulovat, pak je to všechno pouhý sen :) Jestliže si chce v dnešní době anketa udržet alespoň špetku objektivity, pak se kontrole na základě unikátnosti IP adresy nevyhne. Zpravidla se kontrola doplní ještě o trvalé cookie a tím veškeré další snahy programátora v zamezení manipulace s výsledky končí. Přitom existuje mnoho snazších a efektivnějších způsobů, jak nekalé hlasy odfiltrovat. Chce-li útočník zmanipulovat nějakou anketu opatřenou kontrolou unikátních IP adres, pak obvykle sáhne po obsáhlém proxy listu nebo síti TOR. V případě sítě TOR je situace snazší, přístup skrz ní lze totiž snadno detekovat díky seznamu všech jejich serverů (viz Anonymity Checker zde na SOOMu) a hlasování tedy v takovém případě zabránit. Pokud hlasy přicházejí z proxy serverů, pak i to lze poměrně snadno odhalit, neboť je vcelku nápadné, když v tuzemské anketě přichází většina hlasů ze zahraničí (blokace cizích tld v hostname) a navíc se některé servery sami jako proxy identifikují (viz superglobální proměnná SERVER).

Nikdy není na škodu v indexu zapnout podporu sezení (pomocí funkce session_start()) a u přicházejících hlasů kontrolovat přítomnost cookie PHPSESSID. Boti totiž zpravidla žádné cookie, tedy ani toto, neodesílají, zatímco skuteční uživatelé pokaždé. Z výše uvedených důvodu se proto mnoho útočníků uchyluje k třetí variantě, paradoxně té nejsnazší a zároveň pouhým okem nejhůře detekovatelné. Umístí na svoji či hacknutou webovou stránku do atributu src libovolného skrytého tagu odkaz na požadovaný hlas v anketě, čímž zajistí zahlasování od každého návštěvníka takových schránek, a to aniž by cokoliv zpozoroval (v případě POST formulářů přichází na řadu JavaScript). Hlasy tudíž přicházejí z českých IP adres a se smysluplnými User-Agenty, od skutečných hlasů jsou proto k nerozeznání. I tak lze ovšem přes 90 % takto nekalých hlasů odfiltrovat, a to zcela primitivním způsobem. Přesto touto ochranou nedisponuje takřka žádná anketa, se kterou se na Internetu setkáte. Princip je jednoduchý, každý webový prohlížeč ve svém výchozím nastavení odesílá vedle ostatních záznamů i hlavičku Referer, která se v případě podvržených hlasů neshoduje s názvem serveru, na kterém je anketa umístěna. Pokud tedy není hodnota hlavičky Referer prázdná a zároveň se neshoduje s názvem vašeho serveru, hlas byste rozhodně neměli započítat. V kombinaci s kontrolou přítomnosti cookie PHPSESSID lze úspěšnost detekce těchto falešných hlasů zvýšit až na obdivuhodných 100 %. Jednoduché, leč málo kde implementované.


Formuláře

V dnešní době je potřeba zabezpečit webové formuláře nejen proti všudypřítomným spambotům, ale i fyzickým útočníkům. Jako ochrana před CSRF poslouží tzv. ticketový systém, nedovolte uživateli odeslat formulář dříve než po 15 vteřinách od načtení stránky, kontrolujte obsah hlavičky Referer, ignorujte příspěvky obsahující pouze odkaz(y) a zahazujte kopie poslední zprávy (obrana proti floodu). Přítomnost captchy rovněž není v případě necílených útoků potřeba, např. zde na SOOMu aplikovaná antispam ochrana je velice efektivní, aniž by ale návštěvníky příliš obtěžovala. Webové formuláře u nepřihlášených uživatelů obsahují dva checkboxy, z nichž jeden je nutné pro odeslání příspěvku zaškrtnout a druhý je skrytý (nesmí být zaškrtnut). Spamboti ovšem přílišnou inteligencí neoplývají, proto vždy zaškrtnou buď všechny checkboxy nebo ani jeden z nich. V obou případech se jim formulář odeslat nepodaří.


Správa DNS záznamů

Pokud Vaše prezentace neběží na vlastním serveru, pak si pravděpodobně ani sami nespravujete DNS záznamy a tuto práci přenecháváte zkušenějším. Správce doménových záznamů obvykle nabízí pro jejich editaci user-friendly rozhraní, ke kterému je možné přihlásit se klasicky kombinací jména a hesla. Pro zapomnětlivé je ve většině případů navíc k dispozici služba resetování hesla a zaslání nového na e-mailovou adresu majitele účtu. Právě v této aplikaci se ovšem skrývá potenciálně největší nebezpečí, neboť je pro útočníka mnohem snazší kompromitovat e-mailovou schránku majitele a přesměrovat uživatele na svůj falešný stroj, než kompromitovat skutečný server. Volte proto pro účely zasílání zapomenutého hesla ověřeného hráče na trhu, jakým je např. Gmail a vyhněte se tuzemských freemailům nebo schránkám přímo tam, kde máte zároveň i svoji prezentaci. Právě přesměrováním DNS záznamů byly v nedávné minulosti defacnuty giganti jakými jsou např. Twitter nebo čínské Baidu.


<?php nebo <?, toť otázka

Zas tak příliš složitá otázka to není, rozhodně nebuďte líní a k uvození PHP kódu použijte výraz <?php namísto <?, což vám ostatně poradí i každá seriozní kniha či tutoriál o PHP. Možná se ale ptáte, co to má společného s bezpečností. Celkem dost, jste-li totiž líní ve svých scriptech používat delší z uvozovacích tagů a útočník na kompromitovaném serveru deaktivuje direktivu short_open_tag v php.ini, pak se všemi vašimi scripty bude nakládáno jako s obyčejnými textovými hodnotami a zobrazí se uživatelům v jejich prohlížečích. Heslo k databázi jim zcela jistě zvedne náladu :)


Include & Require

Bezpečné vkládání souborů pomocí pole očekávaných hodnot nebo cyklu switch by mělo být samozřejmostí. Co když ovšem předem seznam vkládaných hodnot neznáte, nebo se jednoduše chcete zbavit břemene neustálé nutnosti tento seznam aktualizovat? Pak rozhodně načítejte pouze lokální soubory (před proměnou nesoucí jméno vkládaného souboru vložte zástupný symbol pro aktuální adresář './'), deaktivujte direktivu allow_url_include, testujte existenci includovaného souboru (funkce file_exists()) a negativně reagujte na přítomnost určitých znaků, jakými jsou 'index' (vyhnete se tak zacyklení scriptu a následnému DoSu), null byte, bílé a řídící znaky (trim($promenna, " \t\n\r\0\x0B\xA0")), './', '../', ':', '://', 'sess_' (fyzické soubory sezení), 'environ' (viz útok pomocí /proc/self/environ) a veškeré názvy adresářů, kam směřuje upload ('files/', 'tmp/', 'temp/', 'images/', 'data/' atp.).


Přístupová práva souborů

Žádný adresář nebo soubor na serveru nemá potřebu mít oprávnění 777 (rwx pro všechny), a to i v případě, že do něj směřuje upload nebo jsou zapisována data. Vždy se snažte veškerá práva co možná nejvíce omezit. Problém ovšem nastává u dynamicky vytvářených a uploadovaných souborů, jejichž vlastníkem nejste vy, nýbrž server, pod jehož identitou ale může vystupovat kdokoliv, tedy i útočník. Nastavení přístupových práv a vlastníků souborů proto věnujte nemalou část svého času, vyhnete se tak banálním útokům na nebezpečně nakonfigurovaném webhostingu (což je většina současných). V praxi můžete narazit i na servery, kde je zapisovatelný root webu i pro skupinu nebo dokonce ostatní uživatele serveru. Majitelé se často zaměřují pouze na přístupová práva adresářů, které sami vytvořili a na root se tak notoricky zapomíná. Myslete na to u své aplikace.


Autentizace

Neběží-li vaše prezentace výhradně na protokolu https, pak se přihlašovací údaje uživatelů odesílají na server v nezašifrované podobě a kdokoliv je tak může na síti odchytit. Přinejmenším pro privilegované uživatele (správci, redaktoři, moderátoři atp.) se snažte vždy zajistit šifrovanou komunikaci. Jelikož se hesla v databázi ukládají v podobě hashe (respektive měly by), nic aplikaci nebrání v tom, aby heslo zahashovala již na straně klienta a serveru byl odeslán pouze tento nečitelný výsledek. V přihlášení útočníka do vaší aplikace sice tento trik nezabrání, nedostane se ovšem k heslu v plain-textu, a jelikož uživatelé s oblibou používají stejné heslo u více služeb, ani k účtům na jiných serverech. Heslo se u klienta hashuje pomocí JavaScriptu, hash se uloží do skrytého pole a pole s heslem se vymaže. Teprve následně je formulář odeslán. Pokud má uživatel podporu JavaScriptu vypnutou, pak odeslání formuláře probíhá klasicky a skryté pole zůstane prázdné, heslo pak ovšem, jak již bylo řečeno, poputuje sítí ve své čitelné podobě, což není žádoucí. Zmínili jsme způsob ukládání hesel v databázi, konkrétně hexadecimální řetězec pevné délky, tzv. hash. Ani samotné hashování ovšem nemusí být výhra, a to díky rainbow tabulkám a brute-force/slovníkovým útokům. Jak tedy heslo bezpečně uložit? Vyžadujte od uživatele minimálně šestiznakové heslo, osolte ho jedinečným řetězcem pro uživatele (zpravidla login) a jedinečným řetězcem pro server (tím docílíte stavu, kdy bude mít stejné heslo u různých uživatelů jiný hash a stejní uživatelé se stejným heslem, ovšem na různých serverech taktéž rozdílný hash). Heslo následně předejte hashovací funkcí md5() a sha1(), a to opakovaně. Dbejte na to, aby poslední funkce, kterou heslo projde, byla sha1(), její výstup totiž zkrátíme v posledním kroku z původních 40 znaků na 32, čímž se případný útočník bude při kompromitaci databáze domnívat, že se jedná o md5 hash. Navíc, díky tomuto zkrácení, nebude možné použít klasické crackery a rainbow tabulky pro lámání hesla, na druhou stranu jsme si ale teoreticky vytvořili mnoho případných kolizí. Přesto je to pro nás mnohem výhodnější, než řetězce nekrátit. Proč? Uveďme si příklad z praxe. Igigi při svém nedávném útoku na portál Azet.sk získal hashe hesel 7 milionů uživatelů, přičemž se mu z nich pomocí rainbow tabulek podařilo rozluštit (podle jeho slov) přes 6 milionů. Kdyby ovšem programátoři hashe uložili výše uvedeným způsobem, myslíte si, že by našel v dostatečné krátkém čase 6 milionů kolizí?
Snippet pro generování hashů hesel vhodných k uložení do databáze by mohl vypadat nějak následovně:



Automatické přihlašování

Kdykoliv zpřístupníte uživatelům automatické přihlašování, měli byste zamezit přenositelnosti cookie, které tuto službu zajišťuje. Proto hash, který uživatele jednoznačně identifikuje (unikátní řetězec nebo v horším případě hash hesla, viz výše) osolte částí uživatelovy IP adresy a User-Agenta. Pokud se tedy útočníkovi podaří cookie odcizit, nebude jej moci zneužít.

Zmíněný bezpečnostní prvek má dva malé nedostatky, a sice, bude-li se útočník přihlašovat ze stejné sítě s podobným prohlížečem, respektive bude-li IP a prohlížeč oběti znát, pak se mu autentizace s odcizeným cookie podaří. Navíc, aktivuje-li si takové automatické přihlašování mobilní uživatel ve svém notebooku, na různých sítích bude z bezpečnostních důvodů automaticky odhlašován, což se mu nemusí po určité době líbit.


Závěr

Doufám, že jste v tomto článku našli odpověď na některé své otázky a stal se tak pro vás přínosem v oblasti zabezpečení webových aplikací. Pokud máte jakékoliv připomínky nebo znáte jiné zajímavé tipy a triky, neostýchejte se o ně podělit s ostatními v komentářích, čtenáři to zcela jistě ocení.