Vodič za PHP bezbednost (PHP Security Guide): Sesije
< PreviousNext >Deljeni hosting (Shared Hosts)Baze podataka i SQL
Fiksacija sesija (Session Fixation)
Bezbednost sesija je sofisticirana tema, i ne predstavlja iznenađenje da sesije predstavljaju čestu metu napada. Većina napada preko sesija u sebe uključuju oponašanje, gde napadač pokušava da ostvari pristup sesiji drugog korisnika oponašajući tog korisnika.
Najznačajnija informacija za napadača je identifikator sesije, zato što je neophodan za bilo kakav napad oponašanjem. Postoje tri uobičajena načina za pribavljanje ispravnog identifikatora sesije:
Predviđanje
Zaplena
Fiksacija
Predviđanje se oslanja na pogađanje ispravnog indetifikatora sesije. PHP-ov prirodni mehanizam sesija, identifikator sesije je ekstremno nasumičan, i ovo je najmanje verovatno najslabija tačka vaše primene.
Zaplena ispravnog identifikatora sesije je najčešći tip napada preko sesija, i postoje brojni pristupi. S obzirom da se identifikatori sesija tipično prenose preko cookie-ja ili kao GET promenljive, različiti pristupi se orijentišu na napadanje tih metoda prenosa. Iako su postojalo nekoliko ranjivosti u čitačima, i to većinom u u Internet Explorer-u, cookie-ji su neznatno manje eksponirani nego GET promenljive. Stoga, za korisnike koji uključe cookie-je, možete obezbediti sigurniji način za prenošenje identifikatora sesije cookie-jem.
Fiksacija je najjednostavniji način pribavljanja ispravnog identifikatora sesije. Iako se nije teško odbraniti, ako vaš sistem sesija sadrži samo session_start(), vi ste ranjivi.
Da bi demonstrirali fiksaciju sesija, koristiću sledeći skript, session.php:
<?php
session_start();
if (!isset($_SESSION['visits']))
{
$_SESSION['visits'] = 1;
}
else
{
$_SESSION['visits']++;
}
echo $_SESSION['visits'];
?>
Po prvoj poseti ove stranice, videli bi ste 1 ispis na ekranu. Prilikom svake sledeće posete, ovo bi trebalo da se uvećava da bi prikazalo koliko puta ste posetili stranicu.
Da bi prikazali fiksaciju sesije, prvo se pobrinite da nemate izlazeći identifikator sesije (recimo obrišite cookie-je), onda posetite ovu stranu sa ?PHPSESSID=1234 pridruženom URL-u. Sledeće, sa potpuno drugim čitačem (ili čak sa drugog kompjutera), posetite isti URL ponovo sa pridruženim ?PHPSESSID=1234. Videćete da ne vidite ispis 1 po vašoj prvoj poseti, nego da brojanje nastavlja sesiju koju ste prethodno pokrenuli.
Zašto ovo može biti problematično? Većina napada fiksacijom sesija jednostavno koriste link ili preusmeravanje na nivou protokola da pošalju korisnika na udaljeni sajt sa identifikatorom sesija pridruženim URL-u. Korisnik verovatno neće primetiti, s obzirom da će se sajt ponašati identično. Izbor identifikatora sesije od strane napadača, već je poznato, i može biti iskorišćeno za napad oponašanjem poput otmicom sesije (session hijacking).
Dosta lako je odbraniti se od jednostavnog napada poput ovog. Ako nema aktivne sesije asocirane sa identifikatorom sesije koju korisnik predstavlja, obnovite je da bi bili sigurni:
<?php
session_start();
if (!isset($_SESSION['initiated']))
{
session_regenerate_id();
$_SESSION['initiated'] = true;
}
?>
Problem sa ovakvom jednostavnom odbranom je taj što napadač može pokrenuti sesiju sa specifičnim identifikatorom sesije, i onda da iskoristi taj identifikator za napad.
Da bi se zaštiti od ove vrste napada, prvo razumite da je otmica sesije jedino korisna nakon što se korisnik prijavio ili na drugi način obezbedio veći nivo privilegija. Zato, ako izmenimo pristup da obnovimo identifikator sesije kada god se izmeni nivo privilegija (na primer, nakon potvrđivanja korisničkog imena i šifre), imaćemo praktično eliminisan rizik od uspešnog napada fiksacijom sesija.
Otmica sesije (Session Hijacking)
Ubedljivo najčešći napad preko sesija, otmici sesija pripadaju svi napadi koji pokušavaju da preuzmu pristup sesiji drugog korisnika.
Kao i kod fiksacije sesija, ako se vaš sistem sesija sastoji samo od session_start(), vi ste ranjivi, iako zloupotreba nije tako jednostavna.
Umesto da se fokusiram na to kako da sačuvate identifikator sesije od hvatanja, fokusiraću se na to kako da takvo hvatanje učinite manje opasnim. Cilj je da iskomplikujete imitiranje, s obzirom da svaka komplikacija povećava bezbednost. Da bi ovo ostvarili, ispitaćemo korake neophodne za uspešnu otmicu sesije. U svakom scenariju, pretpostavićemo da je identifikator sesije kompromitovan.
U najjednostavnijem, sistemu sesija ispravni identifikator sesije je sve što je potrebno za uspešnu otmicu sesije. Da bi ovo unapredili, treba da vidimo da li postoji još nešto u HTTP zahtevu što možemo koristiti za dodatnu identifikaciju.
Note
Nije mudro osloniti se na bilo šta na nivou TCP/IP, poput IP adresu, zato što su ov protokoli nižeg nivoa koji nisu namenjeni da preduzimaju aktivnosti koje se odigravaju na nivou HTTP. Pojedinačni korisnik može imati više različitih IP adresa za svaki zahtev, a više korisnika mogu imati potencijalno istu IP adresu.
Podsetimo se tipičnog HTTP zahteva:
GET / HTTP/1.1 Host: example.org User-Agent: Mozilla/5.0 Gecko Accept: text/xml, image/png, image/jpeg, image/gif, */* Cookie: PHPSESSID=1234
Samo je Host neophodan deo zaglavlja po HTTP/1.1, tako da se ne čini pametnim oslanjati se na bilo šta drugo. Međutim, doslednost je sve što nam treba, zato što smo samo zainteresovani za otežavanje imitiranja bez da se ometaju legitimni korisnici.
Zamislite prethodni zahtev koji je praćen zahtevom sa drugačijim User-Agent-om:
GET / HTTP/1.1 Host: example.org User-Agent: Mozilla Compatible (MSIE) Accept: text/xml, image/png, image/jpeg, image/gif, */* Cookie: PHPSESSID=1234
Iako je cookie prisutan, treba li predpostaviti da je ovo isti korisnik? Čini se veoma malo verovatnim da bi čitač promenio User-Agent zaglavlje između zahteva, zar ne? Hajde da izmenimo sistem sesije da izvrši dodatnu proveru:
<?php
session_start();
if (isset($_SESSION['HTTP_USER_AGENT']))
{
if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT']))
{
/* Prompt for password */
exit;
}
}
else
{
$_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
}
?>
Sada napadač mora prezentovati pored ispravnog identifikatora sesije, i ispravno User-Agent zaglavlje koje nije povezano sa sesijom. Ovo dodatno komplikuje stvari, i stoga je dodatno sigurnije.
Možemo li ovo poboljšati? Razmotrite najčešći metod korišćen za pribavljanje vrednosti cookie-a iskorišćavanjem ranjivosti čitača kakav je Internet Explorer. Ovi propusti uključuju da žrtva poseti napadačev sajt, tako da napadač može da nabavi ispravno User-Agent zaglavnje. Nešto dodatno je potrebno da bi se zaštitili od ovakvih situacija.
Zamislte da je potrebno da korisnik prosledi MD5 User-Agent zaglavlja u svakom zahtevu. Napadač ne bi mogao da ponovi zaglavlja koje sadrži žrtvin zahtev, nego bi takođe bilo neophodno da prosledo i ovu dodatnu informaciju. Dok pretpostavimo da pravljenje ovog posebnog znaka nije previše teško, možemo dodatno zakomplikovati ovaj posao pogađanja jednostavnim dodavanjem delića nasumičnosti načinu kako pravimo znak:
<?php $string = $_SERVER['HTTP_USER_AGENT']; $string .= 'SHIFLETT'; /* Add any other data that is consistent */ $fingerprint = md5($string); ?>
Imajući u vidu da prosleđujemo identifikator sesije preko cookie-ja, i da već ovo zahteva da napad uključi i kompromitovanje ovaj cookie (i verovatno sva HTTP zaglavlja), trebalo bi da prosleđujemo ovaj otisak prsta kao URL varijablu. Ovo mora da postoji u svim URL-ovima kao da je identifikator sesije, zato što oba trebaju biti zahtevani da bi se sesija automatski nastavljena (u nastavku prolaska svih provera).
Da bi se pobrinuli da se legitimni korisnici ne tretiraju kao kriminalci, jednostavno zatražite za šifru ako provera propadne. Ako postoji greška u vašem sistemu koj pogrešno posumnja da korisnik pokušava napad oponašanjem, traženje šifre pre nastavka je najmanje uvredljiv način rukovođenja situacijom. U suštini, vaši korisnici će ceniti dodatni nivo sigurnosti koju će taj zahtev označava.
Postoji mnogo načina koje možete primeniti da zakomplikujete imitiranje i zaštitite svoju aplikaciju od otmice sesija. Nadam se da ćete makar nešto dodatno uraditi pored session_start() kao i da ćete doći i do nekih svojih ideja. Samo zapamtite da učinite stvari teškim za loše momke i lake sa dobre momke.
Note
Neki stručnjaci tvrde da User-Agent zaglavlje nije dovoljno dosledno da bi se koristilo na opisani način. Argument je da HTTP proksi u grupi može izmeniti User-Agent zaglavlje nedosledno sa ostalim proksijima u istoj grupi. Iako nikad nisam opazio ovo ponašanje (i osećam se komforno oslanjajući se na doslednost User-Agent), i to je nešto što trebate da razmotrite.
Za Accept zaglavlje je poznato da se menja od zahteva do zahteva u Internet Explorer-u (u zavisnosti od toga da li korisnik osvežava stranicu u čitaču), tako da se na njegovu doslednost ne bi trebalo oslanjati.
< PreviousNext >Deljeni hosting (Shared Hosts)Baze podataka i SQL