Živimo v informacijski dobi ko lahko z enim klikom dosežemo karkoli hočemo. Počasi bo postalo vse elektronsko. Tudi redovalnice… Sicer še ni tako daleč – ampak je to dobro ali slabo?
Po eni strani nam e-redovalnica omogoča, da dostopamo do ocen na računalniku, staršem ni treba v šolo gledat ocene, otrok jim ne more prikrivati ocene… V e-redovalnici so lahko napisane pripombe, prikazani grafi, itd. To je vse lepo in prav ter marsikomu olajša življenje. Ampak! Kot vemo so vse spletne aplikacije bolj ali manj ranljive. Večina jih je bolj kot manj.
In ker nameravam narediti svojo e-redovalnico za seminarsko na maturi, sem prvo vprašal Google kakšne so bile že narete, in prvi rezultat ki sem ga našel je bil Spletna redovalnica 1.0. Moram reči da je funkcionalnost sodeč po seznamu na prvi strani zelo privlačna. Je pa par zelo zastrašujočih stvari že na prvi pogled, pa gremo kar na prvo, najbolj osnovno napako.
1. Stran ne uporablja povezav SSL: Čeprav je že na prvi strani obrazec za prijavo, stran ne uporablja SSL povezave. Kaj pa to pomeni? Prvo za laike: recimo da imate soseda, in da si z sosedom izmenjujete podatke / informacije tako, da kričite na drugo stran ulice. Sedaj, kaj je tu narobe? Recimo da morate sosedu povedati nekakšno skrivnost, sedaj, če bi nekdo bil prisoten ob izmenjavi sporočila / informacije, bi ta posameznik vedel ta podatek in bi ga morebitno lahko zlorabil. Uporabljati SSL je kot uporabljati skriven jezik medtem ko se ti pogovori izvajajo, da tudi če bi kdo slišal, ne bi mogel nič, ker ne bi mogel razvozlati pomena pogovora.
Sedaj pa bolj strokovna razlaga. Ko zahtevate spletno stran se klient poveže na HTTP strežnik ki obdela zahtevo in vrne vsebino zahtevane strani. Sedaj, ko vi vpišete podatke v obrazec jih ponavadi pošljete preko nešifrirane povezave. Tukaj pa je sedaj problem, če ste na omrežju v katerem je vključenih več računalnikov, lahko pride do manjše težave. Napadalec lahko na enega izmed računalnikov namesti “sniffer” ki bere vse podatke ki jih vsi računalniki pošiljajo in sprejemajo. Program lahko nastavi tako da se ujamejo samo podatki ki se prenašajo prek HTTP protokola in ki izvirajo/prihajajo na vaš računalnik. To pomeni, da takoj ko bi izpolnili in poslali obrazec z uporabniškim imenom in geslom, bi imel podatke… Recimo:
http://www.vegasmetisce.com/index.php?action=login
POST /index.php?action=login HTTP/1.1
Host: www.vegasmetisce.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; sl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: sl,en-gb;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-2,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://www.vegasmetisce.com/index.php?action=login
Content-Type: application/x-www-form-urlencoded
Content-Length: 31
user=primer&password=mojpass123
In že ima napadalec vašo geslo in uporabniško ime. Če b stran uporabljala SSL povezavo, se to ne bi zgodilo. Najbolj me preseneča to, da kot zgleda, je stran dejansko v uporabi. Že povsem običajne spletne strani bi morale imeti za prijavo in pošiljanje občutljivih podatkov omogočen SSL, kaj šele spletna redovalnica ki hrani vse ocene določenega posameznika… Včasih je celo upanje, tako da če spremenite tip protokola v naslovni vrstici iz http v https se da vklopit SSL povezavo če jo strežnik le podpira, tukaj tega ne gre narediti.
Rešitev:
Z Apache HTTP strežnikom je zelo enostavno narediti SSL certifikat s katerim omogočimo SSL povezavo. Sicer brskalniki pri tako rekoč “domačih” certifikatih javijo da stran ni zaupanja vredna, šifriranje pa je vseeno prisotno. Če pa so prisotne finance pa lahko certifikat damo podpisati zaupanja vredni organizaciji tako da se potem tudi brskalniki strinjajo (recimo VeriSign, ipd.).
2. Stran je ranljiva na (Blind)SQL injection napade:
OK pa bom hitro sprobal razložiti kaj to pomeni… Recimo da imamo naslednji SQL stavek ki iz baze dobi seznam vseh uporabnikov ki se imenujejo “Miha”:
SELECT * FROM users WHERE ime = 'Miha'
In ker je ta poizvedba v bistvu neuporabna in je skoraj nikoli ne bomo uporabljali pa gremo na drug primer. Naslednja poizvedba bo iz baze dobila tistega uporabnika, ki ima uporabniško ime ‘Miha’ in geslo ‘geslo123′ (haširano). Če poizvedba vrne vrstico, pomeni da takšen uporabnik obstaja, če pa ne vrne nobene, pa takšen uporabnik ne obstaja. Če vrne več vrstic kot eno, je nekaj hudo narobe z programerjem ki je spisal SQL stavek. :P
SELECT id FROM users
WHERE username='Miha' AND password=SHA1('geslo123')
Ampak spet, takšne poizvedba v realnem svetu ni, ker so podatki podani (’Miha’ in ‘geslo123′) statični. Ponavadi takšne podatke dobimo od uporabnika preko obrazcev. To so tisti obrazci ki jih vidite pri prijavi in registraciji itd. Pa si poglejmo kako bi vse to izgledalo kot zelo slabo napisana PHP skripta:
$username = $_POST['username'];
$password = $_POST['password'];
$rezultat = mysql_query ("
SELECT id FROM users
WHERE username='$username' AND password='$password'
", $db);
Sedaj, to sploh ne izgleda tako napačno, s tem da ima samo eno smrtno napako – programer zaupa uporabniku. Sedaj, saj vem, vi ki to berete, saj nebi nič zlonamernega delali, saj vem, ampak vseeno, načelo vsakega programerja bi moralo biti “vse kar pride od uporabnika, ni zaupanja vredno” – vedno in povsod, pri vseh parametrih, GET, POST, COOKIE – vseh. Saj, omenjena stran ob poskusu SQL injectiona na GET parameter izpiše “hacking attempt”… Problem je v tem da ne filtrira POST parametra.
Kaj pomeni to za stran? Preprosto, prvi obrazec na strani se da uporabit da dobimo različne podatke o sistemu. Pa ne samo različne podatke o sistemu, z napadom sem prišel v sistem brez da bi se sploh registriral… Berite dalje in boste ugotovili da se da priti tudi do podatkov kot so uporabniška imena, in če vem uporabniško ime, se lahko brez da bi vedel geslo prijavim v sistem kot ta uporabnik.
Torej, kaj naj zdaj s tem? Vem ime tabele, pa kaj? No, lahko izvem še več. Namreč, takoj ko je en parameter ranljiv na SQL injection to ponavadi pomeni da je ranljiv tudi na Blind SQL injection. Malo ljudje ve za takšen tip napada, pa vendar je genialen, če smem tako reči.
In kaj naredi? No, ponavadi če napademo z stavkom kot
'; SELECT * FROM tabela_ocen;--
nam nič ne pokaže, ker prijavna stran sploh ne vsebuje kode za prikazovanje uporabnikov. Tu pride v poštev Blind (slepi) SQL injection. Kaj sploh to pomeni? No, s to tehniko pošiljamo poizvedbe za imena baz/tabel/podatkov črko za črko tako dolgo dokler ne dobimo vse kar hočemo. Deluje tako, da ker če je SQL stavek pravilni, bo prikazana stran drugačna kot če ni pravilni (če ni pravilni bo ponavadi pisalo sporočilo za napako ipd.). Tako da lahko dobimo čisto vse podatke na ta način… Črko po črko.
Meni recimo je uspelo dobiti imena vseh baz, imena stolpcev v tabeli uporabnikov v bazi za to spletno stran… OK dobil sem samo eno vrstico, torej podatke o enem uporabniku. To pa zato ker je delo precej zamudno, sicer je res da delo opravlja program ampak vseeno dolgo traja. Kar je zelo lepo videt je to da so vsi občutljivi podatki v bazi šifrirani (geslo, ocene, nastavitve) oz. vsaj tako izgleda, dalje nisem raziskoval te točke.
Rešitev:
Rešitev za SQL napade je preprosta… Nikoli zaupat uporabniku. Gremo z časom naprej in uporabimo pripravljene poizvedbe. PHP ponuja to možnost za vse baze z PDO. Na tak način je sanitacija podatkov prepuščena gonilniku baze. Še dodaten korak je to, da recimo preverimo da je up. ime samo alfa-numerično, ipd. Gesla načeloma ne čistimo ker se tako ali tako hašira in je boljše če vsebuje posebne znake…
3. Omejitev poskusa prijav:
Ko sem delal na strani in poskušal razne stvari sem ugotovil, da še vedno lahko nadaljujem delo… Kaj s tem mislim? Vsakič ko sem poskusil določeno tehniko se to šteje kot poskus prijave v sistem, in te niso omejene. Ali pa je omejitev nastavljena na zelo veliko vrednost. To pa me malo moti. Zakaj? Kot vemo, nimajo vsi uporabniki tako zelo močnih gesel, nekateri imajo svoje ime kot geslo, nekateri določeno žival ali pa kaj druga banalnega. To lahko napadalec izkoristi tako da izvede dictionary attack… torej, če ve uporabniško ime (in to lahko tudi dobi, glej sql injection ) mora vedeti še samo geslo in to lahko dobi da gre po slovarju (ni mišljeno dobesedno) in sproba čimveč gesel v čimkrajšem času. To bi seveda opravljal z programom ki bi lahko poskusil 100/m ali celo več…
Rešitev:
Rešitev je seveda zelo preprosta, omejimo število prijav v sistem… Če jih uporabnik prekorači mu onemogočimo dostop do strani.
Zaključek:
Lahko bi še nadaljeval v nedogled o tem kar bi lahko vse naredil pa kako in kateri program sem vse uporabil in katere tehnike ipd… Ampak, moram reči, že zdaj je več kot 1400 besed in sem se pravkar spomnil, nazadnje ko sem pisal toliko sem bil plačan (sem nekaj prevajal)… Pa grem raje svojo verzijo redovalnice delat, ki se bo vseh napak te redovalnice izognila.
Torej… Kar sem zdaj hotel v tem prispevku povedati (razen tega da če bi uporabljali navedeno redovalnico bi vaš sin lahko imel same 5ke!!). Hotem sem povedati, da so v marsikaterem primeru ‘ta stare’ redovalnice še vedno boljše. Kje ste že slišali za SSL in SQL injection pri običajni redovalnici? ;)
P.S. Avtorja redovalnice bom tudi enkrat kontaktiral da ga opozorim na napake.
Lep pozdrav.