=/= Race condition i Veb Tehnologije =/= _ 2006-10-22 19:17:19 _ Race condition i Veb Tehnologije Ivan Markovic Koliko god se razvijale nove tehnologije uvek cemo se susretati sa nekim sigurnosnim problemima kod implementacije samih resenja neke tehnologije ili kod neadekvatnog koriscenja iste. Postoji mnogo resenja koja sluze da odklone dobro poznate propuste u samim okruzenjima kao sto su razni prelivi bafera i ubacivanja nezeljenog koda kao i resenja koja sluze da upozore programera na greske ili da mu uskrate mogucnost da istu napravi. Ali, opet postoji mogucnost da se greska napravi kao sto cemo i videti u nastavku texta. Race condition je poznat pojam svim programerima i on se pojavljuje kada dva ili vise procesa\niti pristupa jednom zajednickom\globalnom resursu i vrsi neke operacije nad njim. T.j. mi predvidjamo i ocekujemo da nam se redosled operacija nad nekim resursom izvrsi prethodno definisanim\predvidjenim redosledom ali usled desihronizacije i\ili nepostojanja zastitnog sistema redosled operacija se moze pomeriti tako da na kraju ne dobijemo zeljeni rezultat. * Svrha ovog texta nije da se detaljno bavimo proucavanjem ovog problema pa shodno time preporucujem onima koji su manje upuceni u ovaj problem da procitaju sledeci text . Jednostavan primer pojave ovog problema je kod koriscenja sesija u php-u. Ako bi vise scriptova koristilo jednu istu varijablu iz sesije istovremeno, uskoro bi doslo do velike greske u rezultatima nasih scripti\aplikacija. Zato, u php-u postoji sistem koji zakljucava podatak iz sesije prilikom pristupa pojedinacnog scripta i tek posle zavrsetka tog scripta podatak se odkljucava i daje na obradu sledecem. Vise o ovom sistemu procitajte ovde. Slican problem se javlja i prilikom koriscenja nekog polja u bazi. Problem se takodje resava sistemom "zakljucavanja" i vise o njemu (kod mysql-a) mozete procitati na sledecem linku. Jos jedan primer sa kojim se srecemo svakog dana je kod editovanja strana u raznim CMS-ovima i slicnim aplikacijama. Sa obzirom da u ovakvim aplikacijama postoji mogucnost da se vise korisnika uloguje istovremeno i zeli da edituje jednu istu stranicu moze doci do pojave Race Condition-a. Jednostavno resenje za ovaj problem ima aplikacija DocuWiki: Prilikom zahteva za editovanje neke stranice postavlja se flag koji oznacava da je stranica zauzeta tj zakljucana. Posle 15 minuta (po default podesavanjima) neaktivnosti ili submitovanja izmena, skida se flag zakljucavanja ili se prebacuje na sledeceg korisnika. Dummy primer: Sa obziorm da se u vecini slucajeva ova greska javlja zbog previda programera a ne zbog same platforme i alata koji su korisceni zelim da vam demonstriram pojavu ovog propusta kod tehnologije koja se danas veoma cesto koristi a to je AJAX. Necu vam govoriti sta je AJAX i gde ga treba koristiti ili ne, vec cu vam samo dati jedan banalan primer njegove lose upotrebe tj pojave Race Condition propusta. Zamislimo da imamo sistem u kome je korisnik ulogovan tj ima privilegije da pozove odredjene funkcije. Te privilegije se cuvaju u sessiji. Dalje, korisnik zeli da pozove funkciju koja ce da mu generise sifru i da ga zatim izloguje, da bi se ulogovao sa novom. Krenimo od trenutka poziva ove funkcije tj user.php fajla koji je zaduzen za generisanje nove sifre, logout-a, ... : Test page ... var zahtev1; // Ovaj zahtev treba da generise novu sifru var zahtev2; // A ovaj da nas izloguje ... function onLoad() { zahtev1 = new XMLHttpRequest(); zahtev2 = new XMLHttpRequest(); zahtev1.open('GET', 'func.php?com1', true); zahtev2.open('GET', 'func.php?com2', true); zahtev1.onreadystatechange = handleResponse1; zahtev2.onreadystatechange = handleResponse2; zahtev1.send(''); zahtev2.send(''); } function handleResponse1() { document.getElementById('test1').innerHTML = zahtev1.responseText; } function handleResponse2() { document.getElementById('test2').innerHTML = zahtev2.responseText; } Kao sto vidimo imamo dva zahteva za koje ocekujemo da se izvrse sledecim redosledom: zahtev1, zahtev2. Dalje, da vidimo sta se desava u func.php : Ovde imamo if uslov koji u zavisnosti od zadatog argumenta (com1,com2) izvrsava odredjene akcije. T.j. kako ocekujemo izvrsice se prvo zahtev1 i deo koda u kome se generise sifra jer jos uvek u sessiji imamo varijablu 'test' u kojoj su zapisane nase privilegije (u nasem slucaju to je vrednost 1). Zatim treba da se izvrsi zahtev2 tj deo koda u kome se brisu nase privilegije iz 'test' varijable i deo u kome se odjavljujemo sa sistema. Takodje u prvom delu koda, deo u kome se generise sifra, imamo i proveru privilegija i ako kojim slucajem nemamo odredjene privilegije ('test' == 1) dobicemo poruku da nismo ulogovani. * Imamo i deo koda koji sluzi da trosi procesorsko vreme da bi se ova greska cesce pojavljivala. Ako probate da pokrenete ovu test aplikaciju na vasem serveru videcete da necete dobiti uvek iste rezultate. T.j. nece se uvek prvo izvrsiti zahtev1 vec ce se u nekim slucajevima prvo izvrsiti zahtev2, i samim tim ne dobijamo zeljeni rezultat. Ova pojava se ispoljava zbog same prirode rada racunara tj procesora i procesa. Za svaki zahtev koji smo inicijalizovali kreiran je odvojen proces koji dobija svoje vreme kod procesora. Usled nekih drugih radnji dodela vremena ne mora uvek teci redosledom koji mi ocekujemo pa samim tim moze doci do ukrstanja raznih stadijuma izvrsenja odredjenih funkcija nekih procesa, a koji su usko vezani za neki zajednicki resurs, i pojave gresaka koji smo demonstrirali. Savet kao resenje: Sa ovim propustom se susrecemo svakog dana, vecina CMS-ova koji se vrte na vebu nema sistem za hendlovanje visetrukog pristupa korisnika prilikom editovanja zajednickih stranica, sa pojavom AJAX-a se sve vise pojavljuju propusti kao u primeru koji sam demonstrirao. Ako vec koristite ovakve tehnologije ili ako razvijate sistem koji opsluzuje vise korisnika istovremeno onda morate razviti i sistem koji ce da upravlja ovakvim akcijama. Zapamtite da se vas script\program ne izvrsava neprekidno vec iz delova i da se moze prekinuti izmedju bilo koje dve instrukcije. Zato prilikom pisanja vitalnih funkcija pripazite na delove koji se moraju izvrsiti bas tim redosledom tj bez interakcije sa nekim drugim funkcijama. Takodje, zapamtite da se istovremeno moze pokrenuti vise instanci vaseg programa\scripta i da u tim slucajevima obavezno implementirate sistem zakljucavanja zajednickih resursa.