Většina útoků, kterých se článek dotýká, opět přímo souvisí s uživatelským vstupem. Jejich vážnost a rozsah možného poškození jsou ovlivněny tím, v jaké části programu se vstupní údaj promítne. Ve většině případů jde o podstrčení škodlivého kódu nebo serverového skriptu, které může mít v nejhorších případech nedozírné následky. Pozornost je také třeba věnovat nastavení serverového skriptovacího jazyka (PHP / ASP) a samotného serveru, neboť vhodné nastavení direktiv a parametrů prostředí nám přímo zajistí ochranu před určitými typy útoků.
Problém se týká především skriptovacího jazyka PHP. Ten je totiž z principu procedurálně skriptovací jazyk bez nutnosti kompilace, což je na jedné straně zjednodušení práce pro vývojáře (za cenu nižšího výkonu programů), na straně druhé tento fakt představuje nebezpečí z hlediska okamžité změny kódu aplikace. U ASP.NET tento problém odpadá kvůli nutnosti kompilace objektově orientovaného kódu.
Podstrčení proměnných Jde o specifický útok pro jazyk PHP, který využívá
bezpečnostní díry (v počátcích vývoje PHP šlo spíše o hodnotnou vlastnost),
vzniklé při použití direktivy register_globals
.
Tato direktiva automaticky převádí všechny hodnoty, získané z tzv.
superglobálních proměnných (GET
a POST
data,
SESSIONS
, COOKIES
) na globální proměnné pod patřičným
názvem. Ačkoliv se na jednu stranu zdá, že direktiva zjednoduší situaci přímým
zavedením proměnných, ve skutečnosti jde o snadnou cestu, jak do kódu zvenčí vložit vlastní
proměnné a jejich hodnoty. Vezměme si hypotetický příklad na obr.1:
Obr. 1 Útok s využitím podstrčení proměnné
Nejlepší obranou je, pokud máme tuto možnost, direktivu
register_globals
úplně vypnout a postarat se o příchozí data ze
superglobálních proměnných pomocí polí $_GET
, $_POST
,
$_SESSION
a $_COOKIE
.
Pokud tuto možnost nemáme, je nutné tento problém ošetřit
pomocí důsledné inicializace proměnných na jejich výchozí hodnoty. To se týká i
polí, která bychom měli vždy inicializovat jako prázdná formou přiřazení $pole
= Array();
.
Extrémně nebezpečný útok spočívá v podstrčení škodlivého
kódu do webové aplikace. Tímto neduhem mohou být postiženy velmi špatně
zabezpečené aplikace, které dovolí uživateli měnit data, která jsou parametrem
funkcí exec()
– sloužící k vykonání externího programu, a eval()
, která vykoná
jakýkoliv vložený PHP kód. Následky takového útoku mohou být nedozírné, neboť
PHP skript má poměrně vysokou úroveň kontroly nad serverem, nehledě na možnost
získání zrojového kódu aplikace.
Typickým příkladem jsou redakčně / publikační systémy, které
přímo dovolují spouštět v uživatelem zadaném obsahu PHP příkazy formou značek
<?php
a ?>
. Toto řešení je pochopitelně
obrovský bezpečnostní problém a je nutné zajistit, aby k takovým možnostem měli
přístup pouze oprávnění lidé, kteří mohou obsah měnit (a naopak z tohoto řešení
těží).
Vždy je tedy nutné kontrolovat všemi dostupnými prostředky,
aby se k parametrům výše zmíněných funkcí nedostal uživatel bez patřičného
oprávnění. Riziková je i funkce preg_replace()
, určená k záměně
řetězce za využití regulárních výrazů, pokud ji použijeme ve spojitosti s
modifikátorem regulárního výrazu /e
, který vykoná přepsaný řetězec
jako PHP kód a následně ho uloží. Všechny tyto cesty je třeba zabezpečit, a
pokud je to možné, vůbec do nich uživatelský vstup nepromítat.
Další metodou je vzdálené spouštění cizích skriptů. Souvisí
opět s PHP a spočívá v nedokonalém zabezpečení interních příkazů
include
, include_once
, require
a
require_once
. Problém nastane, pokud tyto funce čerpají vstup např. z
URL. Útočník může dostupný parametr, např. stranka4.php
, nahradit
výrazem /etc/pass
, která na UNIXovém serveru provede vložení souboru
s hesly (pokud proti tomu není server zabezpečen). Nebo se může pohybovat
ve stromové adresářové struktuře pomocí návratu na předchozí úroveň
../
, příp. vložit kód z vlastní stránky.
Vhodným ošetřením je, pokud už musíme vkládaný soubor
specifikovat v URL, použít v PHP funkce basename()
, která odstraní
veškerou cestu kromě názvu souboru. Daleko lepším řešením je však nepoužívat
vkládání pomocí uživatelského parametru, případně povolit jen vkládání souborů
z nějakého předdefinovaného seznamu (čímž se velice přibližujeme vkládání
souborů v kompilovaných jazycích, kde toto je součástí preprocesoru a není
možné parametr uživatelsky měnit). U jednodušších prezentací je vhodný způsob
založen na samostatném souboru pro každou sekci aplikace, přičemž společné
části se vloží pomocí include. Tyto části obsahují jen definice funkcí bez
jakéhokoliv kódu, který by se spustil po vložení (kromě např. inicializace
globálních proměnných).
Za vhodné zabezpečení nelze považovat direktivu
allow_url_include
, jejímž vypnutím zabráníme vkládání souborů z cizích
URL; jednak může skript útočníka běžet na stejném stroji a jednak ošetření
nepamatuje na všechny možnosti vložení cizích dat (např. pomocí
php://input
– standardní vstup PHP).
V originále se setkáme s označením response splitting [1].
Útok je založen na změně hlavičky HTTP (nebo SMTP v případě emailů), proti
kterému není aplikace zabezpečena. Tímto útokem lze přidávat do hlavičky
vlastní řádky, nebo – a to je zdaleka největší riziko – hlavičku prázdným
řádkem ukončit – čímž protokol přejde na zpracování samotných dat (která mu
tímto řešením podstrčíme ještě v rámci hlavičky). U HTTP hlavičky je
nejproblémovějším parametrem Location
, který slouží k přesměrování
na jinou stránku.
Řešením v PHP je důsledně kontrolovat data, která do
hlavičky vstupují a nepovolit dělení řádků (znakem \n
se jednotlivé parametry
hlavičky oddělují). Od PHP 4.4.2 a 5.1.2 není možné v rámci funkce header()
poslat více než jeden řádek.
U emailů problém spočívá v editaci hlavičky v příkazu
mail()
, kde nevhodným zásahem můžeme opět hlavičku předčasně ukončit a
vložit do mailu podstrčená data. V žádném případě bychom neměli umožnit
uživateli přístup k hlavičce emailu. Ani v případě pole From:
,
protože právě díky možnosti editace tohoto pole velmi usnadníme situaci těm
lidem, kteří chtějí využívat náš formulář k rozesílání spamu.
Tento útok (session fixation) spočívá v přesvědčení uživatele, aby pro přihlášení použil útočníkovu předgenerovanou session ID. Jakmile se nic netušící uživatel zaloguje do systému a tento není proti útoku chráněn, použije se jako session ID identifikátor poskytnutý útočníkem. Ten pak může pod tímto ID přistoupit na stránku také a bude systémem chápán jako napadený uživatel. Technicky se předání session ID provede např. pomocí URL nebo POST dat z formuláře. Typické schéma útoku je na obr.7.
Obr. 2 Princip session fixation
Session fixation se dá ve skriptovací jazyce PHP předcházet
pomocí direktivy session.use_only_cookies
, která nedovolí, aby se session ID
předávala jinak, než pomocí cookies. Další způsob spočívá v častém regenerování
SID pomocí funkce session_regenerate_id()
(pozor, je třeba mít na serveru aktualizovanou
verzi PHP - nejlépe 4.3.2 a vyšší). Tuto funkci je vhodné volat alespoň
po zalogování do systému. Po ukončení práce je dobré session zničit pomocí
session_destroy()
. Útok je podrobně popsán např. v [2].
VIEWSTATE je vlastnost specifická pro ASP.NET stránky [3]. Jedná se o nástroj umožňující uchování stavu stránky a serverových objektů na ní umístěných mezi jejím opakovaným zpracováním. Narozdíl od jiných metod uchování stavu v ASP.NET aplikacích, které je možno použít v rozsahu platnosti uživatele aplikace (Session) nebo celé aplikace (Application, Cache apod..) je tedy jeho platnost omezena pouze po dobu tohoto opakovaného zpracování jedné stránky. VIEWSTATE je využívána zejména pro uchování hodnot vlastností ovládacích prvků umístěných na stránce, ale lze ji samozřejmě také použít v kódu stránky.
Problémem VIEWSTATE je, že standardně není šifrován. Proto není vyloučenou, že někdo může data ve VIEWSTATE pozměnit či přečíst. Z tohoto důvodu existují další dvě úrovně zabezpečení dat ve VIEWSTATE. Pokud jsou v těchto datech přenášeny citlivé informace je vhodné tyto úrovně do aplikace přidat, aby bylo minimalizováno nebezpečí odposlechu či změny dat ve VIEWSTATE. Jedná se o:
Tamper-proofing nechrání VIEWSTATE proti přečtení obsahu nepovolanou osobou. Místo toho poskytuje možnost určit, zda-li někdo nepozměnil data uložená ve VIEWSTATE. Při využití tamper-proofing je, ještě předtím než jsou data ve VIEWSTATE poslány klientovy, vytvořen na serveru jejich otisk pomocí některé z hashovaních funkcí (např. MD5 nebo SHA1). Když pak klient odešle stránku zpět na server je opět vytvořen otisk dat ve VIEWSTATE a ten je poté porovnán s prvním otiskem. Samotná aktivace tamper-proofing je velmi jednoduchá a nastaví se v počátečním tagu stránky:
<%@ Page EnableViewStateMac="true"%>
Bohužel tamper-proofing umožní pouze detekci změn ve
VIEWSTATE, ale nezabrání případnému přečtení dat nepovolanou osobou. Pokud
tomuto chcete zabránit musíte natavit další úroveň zabezpečení. V tomto případě
musíte data ve VIEWSTATE zašifrovat. Jako šifrovací algoritmus se používá 3DES.
Nastavení tohoto šifrovaní pro VIEVSTATE musíte provést v souboru
machine.config pomocí kódu <machineKey validation=3Des />
. Umístění tohoto
souboru je:
x:\<windows>\Microsoft.NET\Framework\<version>\config\machine.config
Před samotným závěrem je vhodné uvést obecná bezpečnostní doporučení, která v naprosté většině již vychází z toho, co bylo v článku popsáno výše. Situace je pochopitelně odlišná v případě skriptovacího jazyka PHP a prostředí ASP.NET
Jazyk PHP Pokud používáme jazyk PHP, je nutné v první řadě správně
nastavit prostředí, na kterém pracuje. V naprosté většině případů jde o webový
server Apache. Je nutné pomocí konfigurace znemožnit např. prohlížení
zdrojových kódů PHP přímo z webu a takto zabezpečit všechny ostatní datové typy,
které by mohly způsobovat problémy. Také výpis adresáře pomocí HTTP požadavku
je dobré dovolovat jen lokálně a to pomocí souboru .htaccess
s místním
nastavením.
Velmi důležité je mít správně nastavenou adresářovou strukturu a manipulovat s oprávněními s extrémní opatrností. Správné řešení tohoto problému je však nad rámec rozsahu tohoto článku, proto je vhodné např. čerpat z [4].
Co se týče samotného skriptovacího jazyka, zde je především nutné správně nakonfigurovat direktivy. Následující direktivy by měly být z bezpečnostního hlediska vypnuty:
safe_mode
– nastavuje bezpečný režim, je však nespolehlivá a do PHP 6 se s ní nepočítá.display_errors
– zobrazování chyb je nebezpečné, může útočníkovi značně pomoci. Pokud je to nutné, nastavovat lokálně pomocí error_reporting()
.magic_quotes_sybase
– mění zásadním způsobem ošetřování speciálních znaků v SQL dotazu.register_globals
– opět velmi nevhodné, otevírá možnost útoku pomocí vložených proměnných.Naopak, následující direktivy je vhodné používat (nastavit):
open_basedir
– zamezuje ze skriptu přístup mimo zadaný adresář
disable_functions
– můžete specifikovat zakázání určitých funkcí (exec
)
session.use_only_cookies
– nebudou se brát v potaz session ID přicházející z GET
nebo POST
dat.
session.save_path a upload_tmp_dir
– nastavují cestu k ukládání sessions a s dočasných dat. Vhodné nastavit na bezpečné místo.
Více informací k tématu lze načerpat např. v [5].
Prostředí ASP.NETStránky ASP.NET jsou úzce spjaty s IIS severem, proto také bezpečnost ASP.NET stránek velmi souvisí se zabezpečeným tohoto serveru. Možnosti zabezpečení IIS serveru jsou velmi rozsáhlé, proto zde nebudou rozebírány. Pro podrobnější informace odkazujeme např. na [5], [6].
Pokud vyžadujete od uživatelů autentizaci je doporučeno
použít některý z autentizačních módů ASP.NET. Jedná se o módy None
, Windows
,
Passport
a Form
. Mód autentizace se natavuje v souboru web.config
pomoci
následujcího kódu:
<authentication mode="Typ_modu"> // další volby v závislosti na zvoleném režimu autentizace </authentication>
Mód None
je základní mód, ve kterém nedochází k
žádné autentizaci, proto se jeho používání nedoporučuje. Nejflexibilnějí je mód
Form
. Jde o režim, který si může vývojář upravit k obrazu svému.
Při ověřování identity uživatele se nemusíme omezovat pouze na uživatele
definované v doméně či na serveru, ale můžeme provádět ověřování vůči seznamu
uživatelů v souboru web.config
.
Dále je doporučeno mít pro všechny stránky mít nastavenu
vlastnost ValidateRequest
na hodnotu true
. Dalším
obecný doporučením je, aby se při práci s databázemi používaly parametrizované
SQL dotazy a parametrizované uložené procedury. Zásadně se nedoporučuje skládat
SQL dotazy jako řetězce za použití vstupů od uživatelů.
Nastavení parametru mode tagu <customErrors>
v souboru web.config
na hodnotu On
bude mít
za následek, že se k uživateli nedostanou citlivá data v případě vyvolání
výjimky.
Doporučuje se také chránit autenzační cookie proti případným
změnám jejího obsahu uživateli. Toto se provádí v tagu <roleManager>
:
cookieProtection
na hodnotu All
cookieRequireSSL
na hodnotu true
createPersistentCookie
na hodnotu false
cookieSlidingExpiration
na hodnotu true
a atribut cookieTimeout
v rozsahu 10-20 minutPoslední část článku se věnovala ostatním typům útoků na
webovou aplikaci. Tyto útoky z velké části využívají skriptovacího charakteru
jazyka PHP; Je nutné, pracujeme-li v tomto prostředí, dobře promyslet důsledky
použití funkcí jako eval
nebo exec
. Obecně lze říci,
že opět platí pravidlo důsledné kontroly uživatelem zadaných dat. Problémy se
nevyhýbají ani daleko lépe zabezpečenému prostředí ASP.NET - viz např. část o
bezpečnosti VIEWSTATE. Pro dokonalé zabezpečení rovněž doporučujeme správně
nastavit chování serveru - v tomto případě ISS nebo Apache. V jednotlivých
kapitolách jsou odkazy k další literatuře, která se touto problematikou
zabývá.
Článkem popsaný výčet útoků pochopitelně není vyčerpávající. Další spočívají např. přímo ve využití bezpečnostních děr v softwaru (prohlížeče) nebo v operačních systémech. Dále může jít o útoky typu DoS (Denial of Service), příp. horší varianta - DDoS, které představují nejnebezpečnější typy útoků, mnohdy bez rozumných možností obrany. Tyto útoky mohou být namířeny i proti základním kamenům celého internetu - byl například zdokumentován pokus o vyřazení páteřních DNS serverů [8]. Článek se také nezabýval zabezpečením pomocí protokolu HTTPS, protože to je dosti rozsáhlé téma, které je vhodné řešit samostatně.
Nezbývá než doufat, že článek bude přínosný zejména začínajícím programátorům, kteří se vývoji webových aplikací chtějí v budoucnu věnovat. Jedině lepší informovaností tvůrců aplikací lze totiž docílit toho, že podobné útoky se jednou stanou minulostí.
PoděkováníAutoři článku chtějí touto cestou poděkovat panu Jakubovi Vránovi za velmi přínosné školení "Bezpečnost aplikací v PHP", ze kterého získali velké množství informací zejména o praktické realizaci útoků z pohledu napadající strany. Mnoho užitečných rad k dané problematice lze nalézt přímo na webových stránkách [5].
[1] Securiteam.com: Introduction to HTTP Response Splitting, SecuriTeam™ 2005, online, dostupné z: http://www.securiteam.com/securityreviews/5WP0E2KFGK.html
[2] Kolšek, M.: Session Fixation Vulnerability in Web-based Applications, ACROS d.o.o. 2002
[3] Drlík, Z.: ViewState v ASP.NET aplikacích - implementace a použití, online, dostupné z: http://interval.cz/clanky/viewstate-v-asp-net-aplikacich-implementace-a-pouziti/
[4] Ristic, I.: Apache Security, O'Reilly 2005
Další zdroje
[5] Jakub Vrána - PHP triky (webová stránka), dostupné z: http://php.vrana.cz/
[6] Windows Server 2003 Security Guide (webová stránka), dostupné z: http://www.microsoft.com/technet/security/prodtech/windowsserver2003/w2003hg/sgch00.mspx
[7] Security Guidelines: ASP.NET 2.0 (webová stránka), dostupné z: http://msdn2.microsoft.com/en-us/library/ms998258.aspx
[8] SSAC Advisory SAC008 DNS Distributed Denial of Service (DDoS) Attacks, zpráva výboru ICANN pro stabilitu a bezpečnost, březen 2006