Netikėtas SQL Injection

Kai Pabėgusi Nėra Pakankamai

Anotacija:
Mes bus pažvelgti į keletą scenarijų, pagal kurį SQL injekcijos gali atsirasti,
nors mysql_real_escape_string() buvo panaudota. Yra du
pagrindinių žingsnių, kurie ne rašyti SQL injekcijos atsparus kodas: teisingą patvirtinimo
ir pabėgti iš įvesties ir tinkamai naudoti SQL sintaksė. Nevykdymas
su bet kuriuo iš jų gali būti kompromisas. Daug konkrečių klausimų yra
jau žinoma, tačiau ne vienas dokumentas, mini juos visus.
Nors pavyzdžių yra pastatytas ant PHP/MySQL, taikomi tie patys principai
ASP/MSSQL ir kiti deriniai kalbas ir duomenų bazes.

0. Turinys

1. Įvadas ir pagrindimas
2. Įrengimas
3. Gauti mysql_real_escape_string()
4. Sveikojo skaičiaus vertės
5. Grįžti į sveikojo Skaičiaus Vertės
6. Sveiki, kokia jūsų stulpelio pavadinimas?
7. Ar Jums PATINKA Mano %Pakaitos%?
8. Kitos duomenų Bazės ir Kitais Klausimais
9. Santrauka Paprastasis
10. Apie
11. Nuorodos

 

1. Įvadas ir pagrindimas

Yra daug straipsnių ([1],[2],[3],[4]) ir dirbiniai ([5],[6]) apie
SQL injekcijos dinamiškai pastatytas SQL užklausas (kaip priešprieša parengė
ataskaitų arba saugomas procedūras), ir dar daugiau apie tai, kaip apsaugoti
prieš jį ([7],[8]). Ir dar web programuotojai ir toliau labai svarbu
klaidų rašydami savo SQL susijusių kodas; iš tiesų yra atvejų,
nėra aiškiai nurodyta, populiarūs vadovėliai, kurie turi būti
elgtis atsargiai. Kaip PHP dokumentaciją ([9])
mysql_real_escape_string() sako: “Ši funkcija visada turi
(su nedidelėmis išimtimis) būti panaudoti duomenų saugumą prieš siunčiant užklausą
prie MySQL.”. Šis straipsnis bando išvardyti minėtos išimtys ir
suteikti pilnas checkpoint sąrašą apsaugos priemones. Mes nustatyti
kai kurių bendrų taškų gedimo ir suteikia teisę (ir kai
kartais, dažniausiai taikomas negerai) sprendimų tikimės, kad naujokas
programuotojų ir pen-testeriai išmoksite atpažinti juos jų pačių
kodas jie turėtų atsirasti.

Pateikti pavyzdžiai yra skirtos atrodo kaip kai kurių bendrų web programavimas
užduotis, susijusias su paieškos ir pateikiami naudotojo informaciją. Kita vertus,
jie yra šiek tiek dirbtinis, ta prasme, kad jie yra pernelyg supaprastinta.
Kai kurie pavyzdžiai SQL injekcijos negali dirbti su sudėtingesnėmis
užklausos (pavyzdžiui, naudodami UŽSAKYMO ir SĄJUNGOS reikalauja specialių skliaustuose
sintaksė, kuriuos paprastai sunku pasiekti, kai bando įleisti SQL).
Vis dėlto, jei taškai injekcijos yra jūsų kodas, gerai išmanantis
puolėjas turės naudos iš jų, nesvarbu, kaip “priešiškų” SQL injection
aplinkinių užklausą.

Mes ne aptarti galimo mažinimo strategijas, kai SQL
įpurškimo atsiranda, pvz., PHP ir MySQL konfigūravimo galimybių, duomenų
šifravimas ir pan., tačiau skaitytojas skatinamas skaityti daugiau šia tema.

Mes tikimės, kad skaitytojas galėtų būti susipažinęs su pagrindai, PHP/MySQL
sąveika ir turėti ne mažiau kaip paviršutiniškas idėja, ką SQL injekcija.
Nuoroda skyriuje pateikiama keletas gerų patarimų, pastarajai.

Taip pat reikia pažymėti, kad daugelis pateikti klausimai buvo
atskirai paminėjo saugumo tyrėjų prieš, pvz., [14]
ir [15] ir valstybės poreikį citatos apie vertybes, PHP manual ([9])
minima, PAVYZDŽIUI, wildcards, ir [16] sąrašus tiek; [17] trumpai pataria
prieš naudojant dinaminę lentelę, vardai.

2. Įrengimas

http://www.webappsec.org/projects/articles/091007.zip
arba
http://mordred.logris.org/articles/091007.zip

Straipsnyje pateikiamas pavyzdžių rinkinys, kiekvienas siūlo
bandymų skaičius, kuris gali būti paleisti ant localhost serverio. Praktika
rodomi pavyzdžiai yra tik rekomenduojamas, jų dalis, susijusi su
SQL injekcijos. Poilsio kodas paskubomis (ir tingiai) iki lopas
“tiesiog atlikti darbą”. Tai rodo SQL klaidų, HTML, neleidžia pabėgti
verčių iš duomenų bazėje, prieš rodant juos arba, HTML
pati yra labiausiai minimalistinis negraži gatvės HTML, kad būtų gauti lydyti.
Tai nėra geras pavyzdys, kodavimo stiliaus, todėl nereikia imituoti it (I don ‘ t
abiejų). Tai daroma tyčia, nes ne atitraukti skaitytojas
svarbu kodą. Stenkitės suprasti ir taikyti priemones prieš
SQL injekcijos nors, ir, jei jus domina pen bandymus, kaip gerai
kaip web programavimas, žaisti su sąlyga, įpurškimo vektorių.

Open [db.inc.php] su jūsų mėgstamu redaktoriumi ir parašyti teisingą
ryšys su duomenų baze info. Duomenų bazėje pasirinkote bandymo,
importo [sql_injection_test.sql], failas, kuris yra paprastas stalo
schema su trijų eilių informaciją. Įkelti index.php jūsų naršyklėje
ir atlikite pavyzdžiai, kaip jie sakė apie tai šiame straipsnyje. Jei jūs
nori žaisti su url parametrais už nustatytą bandymo atvejais,
spustelėkite mygtuką [naujas] nuorodos įkelti pavyzdžių, nauji langai.

DĖMESIO!

Įdiegti šie scenarijai tik dėl savo vietos testavimo aplinkoje. Jei jūs
palikite juos viešai prieinama priimančiosios, jie (ir, priklausomai nuo
konfigūracija, priimančioji pati), bus pasinaudota. Jūs buvote įspėti.

Vardan savęs izoliavimo, esminius kodo fragmentus bus
taip pat inlined straipsnio. Bandymo stalo turi šiuos duomenis:

mysql> select * nuo sql_injection_test;

| id | vardas | slaptažodis |
+——–+————-+———-+
| 1 | Winnie | Pooh |
| 2 | Edward | Sanders |
| 3 | Christopher | Robin |
+——–+————-+———-+

RunQuery($query) yra naudingumo funkcija, kuri rodo ir veikia pateikta
užklausos ir rodo arba grąžinti klaida, ar visi grįžo eilučių.

3. Gauti mysql_real_escape_string()

———[ Pavyzdys 1 . (finduser.php) ]————

$username = isset($_GET[‘u’]) ? $_GET[‘u’] : ”;
RunQuery(“SELECT userid, username FROM sql_injection_test
WHERE username=’$username'”);
———[ Tests: ]——————————
1. u=Winnie
2. u=Edward
3. u=Christopher
4. u=Schneier
5. u=’
6. u=’ OR ”=’
7. u=’ UNION ALL SELECT userid, CONCAT(username, ‘ ‘, password)
FROM sql_injection_test WHERE ”=’
————————————————–

Pavyzdys 1 rodo, kad dauguma pagrindinių (blogai) tvarkymo būdas dinaminis
SQL užklausas. Url parametras ” u ” turėtų būti vardas,
ir pirmasis keturių bandymų nuorodas parodyti, kaip ji dirba su esamų
ir ne esamus vardus. Penktas bandymas, kabutes (
“karščiausios citata”), yra pagrindinis bandymas, jei scenarijus yra pažeidžiami
(arba bent jau, jei tai bus pertrauka), ir, kaip matome, mūsų pavyzdys iš tiesų bando
vykdyti neteisingas SQL. Bandymo 6 manipuliuoja užklausą sąrašą visų galimų
vartotojai, o ne tik vieną. Ir pagaliau SĄJUNGOS užklausą bandymo 7 sąrašus
visi vartotojai kartu su savo slaptažodžius.

———[ Pavyzdys 2. (finduser_fixed.php) ]———

$username = isset($_GET[‘u’]) ? $_GET[‘u’] : ”;
$username = mysql_real_escape_string($username);
RunQuery(“SELECT `userid`, `username` FROM `sql_injection_test`
WHERE `username` = ‘$username'”);
—————————————————–

Pažeidžiamumas čia atsiranda galimybė užpuolikas švirkšti
viena citata, todėl uždarymo tiesiogine styginių ir žodžiu poilsio
vartotojo įvestis SQL sintaksė. Gerai žinomas ištaisyti, kad yra
pabėgti visus kintamuosius, kad bus taikoma dinaminė užklausa su
mysql_real_escape_string(). 2 pavyzdys rodo, kad tas pats išpuolių nr.
ilgiau dirbti.

>Nuo šiol mes pabėgti mūsų parametrų su mysql_real_escape_string()
ir bus stebėti, kaip ir kai tai nepavyksta apsaugoti mus nuo SQL injection.
Atkreipkite dėmesį, kad net neteisingai ([10]) pabėgti su funkcijų, pavyzdžiui,
addslashes() (arba magic_quotes funkciją, PHP) turi panašų poveikį.

4. Sveikojo skaičiaus vertės

———[ Pavyzdys 3 . (viewprofile.php) ]————

$userid = isset($_GET[‘id’]) ? $_GET[‘id’] : 0;
$userid = mysql_real_escape_string($userid);
RunQuery(“SELECT userid, username FROM sql_injection_test WHERE userid=$userid”);
———[ Tests: ]——————————
1. id=0
2. id=1
3. id=2
4. id=3
5. id=’
6. id=0 or 1
7. id=0 UNION ALL SELECT userid, CONCAT(username, ‘ ‘, password)
FROM sql_injection_test WHERE 1
8. id=0 UNION ALL SELECT userid, CONCAT(username, CHAR(32), password)
FROM sql_injection_test WHERE 1
————————————————–

Pavyzdys 3 priima skaitinė parametras, userid, ir rodo informaciją
apie tai vartotojo. Keturis pirmuosius bandymus, kaip ir anksčiau, parodyti, kaip
scenarijus yra tikėtinas, kaip elgtis, ir 5-bandymas rodo, kad net
pabėgo parametras gali pakelti klaida. Bėda čia yra ta, kad užklausos
daroma prielaida, kad parametras bus sveikojo skaičiaus, ir taip yra parašyta be
citatos. Užpuolikas, nors, nereikia “karščiausios citata”, kaip
ką jis patenka eina tiesiai į užklausą ” reikia aiškinti taip,
SQL sintaksė. Bandymo 6 manipuliuoja KAI sąlyga grįžta į visus
vartotojo įrašus. Kaip matome iš 7, mysql_real_escape_string() neleidžia
sėkmės švirkščiamas užklausų, kurios apima kabučių. Bet tokios užklausos gali
galima perrašyti taip, ne naudoti kabučių, nors, todėl bandymas 8 pavyksta
jei 7 nepavyko.

———[ Pavyzdys 4. (viewprofile_fixed_1.php) ]————
$userid = isset($_GET[‘id’]) ? $_GET[‘id’] : 0;
$userid = mysql_real_escape_string($userid);
RunQuery(“SELECT `userid`, `username` FROM `sql_injection_test`
WHERE `userid` = ‘$userid'”);
————————————————————

———[ Pavyzdys 5. (viewprofile_fixed_2.php) ]————
$userid = isset($_GET[‘id’]) ? $_GET[‘id’] : 0;
userid = intval($userid);
//…
$userid = mysql_real_escape_string($userid);
RunQuery(“SELECT `userid`, `username` FROM `sql_injection_test`
WHERE `userid` = ‘$userid'”);
————————————————————

Yra du problemos sprendimo būdus, naudokite kabutes užklausą
kaip Pavyzdys 4 ar, arba konvertuoti įvesties vertės int. Labiausiai patikimas
pasirinkimas yra parodyta Pavyzdys 5, kur abu sprendimai yra derinami. Jei
skaitinė vertė reikalavimas yra keičiamas tam tikru momentu ateityje
ir įvesties parametrų yra ne ilgesnis priversti būti int, užklausos bus
dar reikia apsaugoti.

Skaitytojas turi suprasti, kad įvesties patvirtinimo (mūsų atveju, įsitikinkite,
kad tai, ką mes tikėtis, kad būti int yra tikrai int) ir pabėgti parametras
prieš pateikdami ją į užklausą yra du skirtingi saugumo priemonių. Šiame
konkrečiu atveju vienos ir pakanka, bet apskritai, giluminiai
apsaugos, jūs visada turite padaryti tiek. Be to, dvi užduotis bus tikriausiai
bus atliekamas pagal dviejų skirtingų posistemių savo realaus gyvenimo kodas, todėl
vertinti ir pabėgti kodas nebus šalia, kaip parodyta šioje
supaprastintas atveju. Šis klausimas yra gana plačiai taikomi kiti
autoriai ([8]) taigi mes ne tęsti jį toliau.

5. Grįžti į sveikojo Skaičiaus Vertės

———[ Pavyzdys 6. (members.php) ]————
$offset = isset($_GET[‘o’]) ? $_GET[‘o’] : 0;
$offset = mysql_real_escape_string($offset);
RunQuery(“SELECT userid, username FROM sql_injection_test LIMIT $offset, 10”);
———[ Tests: ]——————————
1. o=0
2. o=1
3. o=2
4. o=3
5. o=’
6. o=999999, 10 UNION ALL SELECT username, password FROM sql_injection_test LIMIT 0
————————————————–

Pavyzdys 6 rodo, kita situacija, kai sveikojo skaičiaus reikšmės yra naudojamos –
ofsetinės ir suskaičiuoti parametrai RIBINĖS sąlygos. Scenarijų įgyvendina
paprasta puslapiai funkcija – jis rodo sąrašą nariai puslapius
10, priimdamas pradeda kompensuoti url parametras.

Atsižvelgdama į tai, kad ankstesniuose pavyzdžiuose, yra nenuostabu, kad
“karščiausios citata” 5-ojo bandymo tikrai pertraukas užklausos, ir kad
6-oji bandymo SĄJUNGOS injekcijos gali suteikti užpuolikas sąrašą
naudotojų vardų ir jų slaptažodžius.

———[ Pavyzdys 7. (members_fixed.php) ]————
$offset = isset($_GET[‘o’]) ? $_GET[‘o’] : 0;
$offset = intval($offset);
RunQuery(“SELECT `userid`, `username` FROM `sql_injection_test` LIMIT $offset, 10”);
——————————————————

———[ Pavyzdys 8 . (members_not_fixed.php) ]————
$offset = isset($_GET[‘o’]) ? $_GET[‘o’] : 0;
if (is_numeric($offset))
RunQuery(“SELECT userid, username FROM sql_injection_test LIMIT $offset, 10”);
———[ Tests: ]——————————

7. o=0.0001
8. o=0x53514c
————————————————–

Skirtumas, palyginti su ankstesne situacija, kad šis sveikojo skaičiaus reikšmė
vaidina ir kitą vaidmenį, sintaksines-protingas. Dviejų RIBINIŲ parametrų reikia
sveikojo skaičiaus reikšmės, todėl mes negali naudoti jokių kabučių ar bet pabėgti mechanizmas
išskyrus intval() (arba liejimo int), kaip Pvz. 7. Ji turi būti
pažymėjo, kad, naudojant is_numeric() (pavyzdžiui, kaip senas versijas ([18])
PHP manual patarė) tvirtinimo dalis scenarijaus nėra
pakankamai tikrinti, ir 8 Pavyzdys rodo du būdai, kaip nutraukti užklausą
(nors jokių kenkėjiškų SQL kodas gali būti švirkščiamas tokiu būdu). Antras
tų, bandymo 8, yra įdomi, nes, o tai “skaitinių”
PHP požiūriu, tai eilutė pažodžiui (‘SQL’) MySQL.
Tai yra tik akademinių interesų šioje situacijoje, nors, literals
užkoduotas tokiu būdu ir ilgiau nei keturis simbolius nebus perduoti
is_numeric().

Kitas skirtumas tarp pavyzdžių, 3-5 ir 6-8, kad nekilnojamojo
pasaulio TVARKA KURIĄ, greičiausiai, bus naudojami kartu su RIBINĖ sąlyga.
Tai sukels SĄJUNGOS įpurškimo ne į darbą, ir kūrėjas
gali nuspręsti, kad kodas yra saugus. Tai yra tiek naivus ir negerai, viena turi
visada naudokite tinkamą pabėgti, prieš dėdami vertybes dinaminių SQL
užklausos, nesvarbu, kas užklausą atrodo. Kitame skyriuje bus
paaiškinti, kaip tokie “priešiškų” SQL injection klausimų vis dar gali būti
išnaudojami ir vis dar reikia gauti tinkamai apsaugoti.

Kitas patikimas būdas išvengti tokių klaidų nėra nurodyti
“kompensuoti” scenarijų parametrai, tačiau “puslapis”. Scenarijus bus
tada turi apskaičiuoti poslinkį remiantis skaičius elementus
kiekvieno puslapio, ir pateikti jį į užklausą. Būtinybė šis skaičiavimas
užtikriname, kad nuokrypis bus sveikasis skaičius, kai ji pasiekia užklausą.

6. Sveiki, kokia jūsų stulpelio pavadinimas?———[ 9 pavyzdys. (members2.php) ]————
$order = isset($_GET[‘o’]) ? $_GET[‘o’] : ‘userid’;
$order = mysql_real_escape_string($order);
RunQuery(“SELECT userid, username FROM sql_injection_test ORDER BY $order”);
———[ Tests: ]——————————
1. o=userid
2. o=username
3. o=password
4. o=honey_eaten
5. o=’
6. o=userid ASC UNION ALL SELECT username, password FROM sql_injection_test
ORDER BY userid
7. o=IF ( (SELECT userid FROM sql_injection_test
WHERE username=0x57696e6e6965 AND password=0x506f6f68),
userid, username)
8. o=IF ( (SELECT userid FROM sql_injection_test
WHERE username=0x57696e6e6965 AND password=0x31323334),
userid, username)
————————————————–Taigi, mes matėme atakas, nukreiptas į PHP kintamųjų žaisti vaidmenys
eilutės reikšmes, sveikųjų reikšmių ir sveikojo skaičiaus parametrų RIBĄ. Kartais
tingus kūrėjas nori, kad kita dalis savo užklausą dinaminis:
stulpelių pavadinimai. 9 pavyzdys rodo, “tipiškas” naudoti: norime sąrašą
nariai, ir mes norime, kad vartotojas galėtų pasirinkti stulpelį, ant kurio juos surūšiuoti.
Bandymai 1-3 yra paprasta (nors saugumo bendraminčių turėtų padidinti
antakių bandymo 3 … ji naudoja stulpelio pavadinimą, kad nėra užklausos,
neprieštaraujate, kad dabar). Testas 4 rodo, kas atsitinka, jei lentelėje nėra
tokia skiltis, bandymas 5 rodo, kad, nors kabučių pabėgo, jie gali
dar “pertrauka” sintaksės užklausą. Bandymo 6 bandymai naudoti SĄJUNGA
įpurškimas, tik rasti, kad teisingai naudoti SĄJUNGA ir TVARKA reikalauja
skliaustuose aplink dvi PASIRENKA, kad mes norime, SĄJUNGA, kuri nėra
galima čia, nes mes turime tik vieno taško injekcijos.Taigi, ką gali užpuolikas? Atsakymas yra “Blind SQL injection” ([3], [4]).
Kadangi užpuolikas negalite naudoti kabučių, jis turi arba naudoti šešioliktainis
formatas minėta ankstesniame skyriuje, arba naudoti a derinys CONCAT()
ir CHAR(). Bandymo 7 tikrinimus, jei yra username “Mikė pūkuotukas” ir slaptažodžiu
‘Pūkuotukas”, ir jei taip, užsakymų rezultatus pagal id, jei ne – pagal vartotojo vardą.
(Tai yra, JEI() MySQL funkcija [19], neturi būti painiojama su IF
ataskaita saugoma rutinos, sintaksė), Nes akivaizdu, kad yra
userid, puolėjas daro išvadą, kad teiginys jis patikrinta tiesa.
Bandymo 8 bandoma Mikė/1234, nes rezultatai yra užsakomi pagal vartotojo vardą,
tai turi būti negerai. 

———[ Pavyzdžiui A. (members2_not_fixed.php) ]————
$order = isset($_GET[‘o’]) ? $_GET[‘o’] : ‘userid’;
$order = mysql_real_escape_string($order);
RunQuery(“SELECT userid, username FROM sql_injection_test ORDER BY `$order`”);
———[ Tests: ]——————————

9. o=userid`,IF ( (SELECT userid FROM sql_injection_test
WHERE username=0x57696e6e6965 AND password=0x506f6f68),
BENCHMARK(300000,MD5(1)), username), `userid
10. o=userid`,IF ( (SELECT userid FROM sql_injection_test
WHERE username=0x57696e6e6965 AND password=0x31323334),
BENCHMARK(300000,MD5(1)), username), `userid
————————————————–

Problema čia, atrodo, panašus į Pavyzdys 3 – skiltyje vardas
netinkamai cituojamas (MySQL vadovas ([11]) teigia, kad “vardas
citata ženklas yra backtick (`)” ). Iš tiesų, tinkamai nurodant
Pvz., sustabdo atakos vektorius bandymus, 7 ir 8. Ką mes galime ‘ t stop
yra užpuolikas tiesiog uždarymo backtick citata ir švirkščiamųjų SQL po
stulpelio pavadinimas, kaip mysql_real_escape_string() ne pabėgti backticks.
Kaip mes pažymėjo, SĄJUNGOS neveiks po UŽSAKYMO, todėl užpuolikas kurortai
į kitą aklas įpurškimo technika – lėtėja užklausą būklės.
Mano mašina bandymo 9 trunka apie 3 sekundes (tai reiškia, kad išbandyti būklės
yra tiesa), kadangi bandymo 10 apdailos su jokio uždelsimo.

———[ Pavyzdžiui B. (members2_fixed.php) ]————
$order = isset($_GET[‘o’]) ? $_GET[‘o’] : ‘userid’;
if (!in_array($order, Array(‘userid’,’username’)))
$order = ‘userid’;
RunQuery(“SELECT `userid`, `username` FROM `sql_injection_test`
ORDER BY `$order`”);
——————————————————–

Tikrosios problemos užklausos yra ne tik cituodamas stulpelio
vardas, pavardė (nors jis yra geras stilius visada naudokite tinkamą kabučių), bet
tai, kad naudotojui tiekiami įvesties naudojamas kaip stulpelio pavadinimą. Testas (4)
neegzistuojantis skiltyje buvo signalas-auga koeficientas, net iki
turintys įrodymų, kad SQL injekcijos yra įmanoma. B pavyzdys rodo
galimas sprendimas, kai tik fiksuotą funkcijos yra leidžiama.

Atkreipkite dėmesį, kad tas pats pasakytina apie kitų identifikatorių ir sintaksės elementai
kad programuotojas gali norėti dinamiškai nukopijuoti iš įvesties į užklausų,
pavyzdžiui, stalo vardus, skiltyje slapyvardžiai, ASC/DESC raktinius žodžius ir pan.

7. Ar Jums PATINKA Mano %Pakaitos%?

MySQL (ir kitų duomenų bazių) turi keletą atitikimo operatoriai ([12], [13])
kad naudoti pakaitos simbolius ar reguliarios išraiškos, tai yra labiausiai
dažnai naudojama tvarkyti paieškos formos. Tai reiškia, kad per
SQL užklausą, mes turime dalis (pakaitos simbolis arba regexp atitikimo seka)
kurie elgiasi kitaip, nei įprasta SQL sintaksė. Mūsų bandymai mes
bus padaryti du dalykus. Pirma, papildomas indeksas, su ilgis 3 papildoma
dėl “username” srityje. Antra, o ne grįžti rezultatai
užklausą, mes naudosime PAAIŠKINTI, sintaksė ir stebėti, kaip mūsų indeksas yra naudojamas.

———[ Pavyzdžiui, C. (search.php) ]————
$search = isset($_GET[‘s’]) ? $_GET[‘s’] : ”;
if ($search!=”) {
$search = mysql_real_escape_string($search);
RunQuery(“EXPLAIN SELECT userid, username FROM sql_injection_test
WHERE `username` LIKE ‘$search%'”);
}
———[ Tests: ]——————————
1. s=Wi
2. s=%Wi
————————————————–

Pavyzdys C rodo tipišką pakaitos paieška vardus. Mūsų pirmasis
bandymo elgiasi taip, kaip tikėtasi:

———[ Testas 1 rezultatas: ]————————————————————id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE sql_injection_test range username username 11 1 Using where
———————————————————————————————–

Kaip matome iš “possible_keys” ir “raktas” vertes, mūsų indeksas
(pavadintas “username”) buvo naudojami nustatant rezultatų rinkinį (mes taip pat pranešimas
kad “eilučių” yra 1, tai reiškia, kad indekso padėjo MySQL susiaurinti paiešką
tik vieną eilutę, nereikia eiti per visus eilėmis į mūsų lentelę).

———[ Testas 2 rezultatas: ]————————————————————
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE sql_injection_test ALL 3 Using where
———————————————————————————————–

Testas 2 yra labai skirtingi, nors – ne indeksą buvo naudojami ir visi 3 eilėmis
lentelės turi būti patikrinta prieš pakaitos. Dėl šios priežasties
tai, kad svarbiausias pakaitos simbolis (%) daro mūsų priešdėlis indeksas nenaudingas,
kadangi string mes ieškome gali prasidėti bet kokio pobūdžio. Tai atsitiko,
nes mes sėkmingai švirkščiamas %, kuris turi ypatingą reikšmę
aplinkybės, PAVYZDŽIUI, operatoriaus (ir taip yra ne objektas
mysql_real_escape_string() pabėgti). Ji gali atrodyti problema mūsų 3
eilučių duomenų, tačiau įsivaizduokite, duomenų bazės, tūkstančiai ar milijonai eilučių
kurios staiga negalima naudoti indeksas, bet turi eiti per visus, kad duomenų.
Priklausomai nuo to, kaip scenarijus parašytas, net vienas vartotojas gali
atlikti DOS ataka.

———[ Pavyzdžiui D. (search_fixed.php) ]————
$search = isset($_GET[‘s’]) ? $_GET[‘s’] : ”;
if ($search!=”) {
$search = mysql_real_escape_string($search);
$search = addcslashes($search, “%_”);
RunQuery(“EXPLAIN SELECT `userid`, `username` FROM `sql_injection_test`
WHERE `username` LIKE ‘$search%'”);
}
———[ Tests: ]——————————
1. s=Wi
2. s=%Wi
3. s=\%Wi
————————————————–

Sprendimas įrodo, Pvz., D yra padaryti antra pabėgti pass
po mysql_real_escape_string (), kad visi kintamieji, kurie yra pakeičiamas
per, PAVYZDŽIUI, operatorius. Dabar testai 1 ir 2 elgtis teisingai. Į
addcslashes() funkcija yra naudinga, nes ji vietų brūkšnį ( \ ), prieš
atsižvelgiant simbolių, o brūkšnį atsitinka būti numatytasis pabėgti
simbolių išraiška dešinėje pusėje, KAIP operatorius.

Atkreipkite dėmesį, kad MySQL leidžia pasirinkti kitos escape pobūdis
(… WHERE `username` LIKE ‘*%’ ESCAPE ‘*’ atitiks pažodinis %), bet jei
jums tai padaryti, jūs negalite naudotis addcslashes() funkcija nebėra, jums bus
reikia pakeisti funkcija. Minėtame keitimo funkcija, jums būtų
taip pat reikia pabėgti naujas, KAIP pabėgti charakteris, ar jis gali būti naudojamas
už pakaitos įpurškimas (nors ir ne eilutės pradžios, todėl
DOS poveikis nebūtų toks didelis).

Testas 3 įrodo, kad mūsų atveju, mums nereikia pabėgti PATINKA
pabėgti pobūdžio, pvz., mysql_real_escape_string (), jau pabėgo.

Kai sprendžiami su reguliarias išraiškas (REGEXP/RLIKE operatorius) pabėgti
metodas negali būti taip paprasta, kaip addcslashes(), taigi programuotojas, kuris nori
norėdami naudotis šia operatorius turėtų būti dvigubai atsargūs, kaip ji tvarko vartotojo įvestį.

8. Kitos duomenų Bazės ir Kitais Klausimais

Taip pat yra požymių, ne MySQL duomenų bazės, kuri taip pat gali būti vartojamas, kai
švirkščiamųjų SQL, kurie gali būti išspręsti, taip pat kontrolinis sąrašas,
tiesiog pakeiskite mysql_real_escape_string (), tinkamą duomenų bazę, specifinių
pabėgti funkcijas. PostgreSQL pratęsti, pavyzdžiui, turi
pg_escape_string(), ir jei nėra jokių panašių funkcija, jūsų duomenų bazėje
sistema, jūs turėtumėte patikrinti jo dokumentai apie tai, kaip padaryti tinkamą pabėgti.

MSSQL, PostgreSQL, o gal ir kitos duomenų bazės (įskaitant MySQL su
mysqli pratęsimo) paramą išdavimo daug užklausų į vieną skambutį.
Kadangi sintaksines personažas, naudojamas pareiškimas, terminator, kabliataškį,
nėra pabėgęs standartinis pabėgti funkcijas, nekotiruojamas parametrai
SQL užklausos gali būti naudojama siekiant nutraukti dabartinės pareiškimą ir klausimas
kitos. Žinoma, jei visi parametrai yra tinkamai cituojamas ir tipo priversti,
į kabliataškiu bus arba gali būti atimta, arba tai gali būti dalis reikšmę pažodinis,
taigi ne laužyti užklausą. MSSQL taip pat turi rezervuotą žodį, VIRŠUJE, panaudota
panašiai, kaip MySQL RIBA, kadangi PostgreSQL yra RIBOS/KOMPENSUOTI.
Aplinkybes skirsnis 5 straipsnis turėtų būti taikoma, kai
naudojant šiuos.

9. Santrauka Paprastasis

Kaip matėme, mysql_real_escape_string (), yra būtina, bet nepakankama
priemonė. Čia yra kontrolinis sąrašas taisykles, reikia sekti, įsitikinkite, kad
dinaminių SQL kodas nėra pažeidžiami SQL injection:

1. Rašyti tinkamai kotiruojamos SQL:
1.1. Vieną kabutes aplink vertės (string literals ir skaičius)
1.2. Backtick citatos apie identifikatorius (duomenų bazes, lenteles, stulpelius, slapyvardžiai)
2. Tinkamai pabėgti eilutes, ir skaičius:
2.1. mysql_real_escape_string(), visi dydžiai (string literals ir skaičius)
2.2. intval() visų skaičių reikšmės ir skaitmeniniai parametrai RIBINĖS
2.3. Pabėgti pakaitos/regexp metacharacters
(addcslashes (‘%_ ” ), PAVYZDŽIUI, ir jums geriau vengti REGEXP/RLIKE)
2.4. Jei identifikatorius (kolonos, lenteles ar duomenų bazes) ar raktažodžiai
(pvz ASC ir DESC), yra nurodyti scenarijų parametrai,
įsitikinkite, (ir galią) jų vertės pasirinktas tik kaip vieną iš
aiškiai nustatykite funkcijos
2.5. Nesvarbu, ką patvirtinimo veiksmų galite imtis, kai perdirbimo vartotojas
įvesties jūsų scenarijų, visada daryti pabėgti veiksmus prieš
išduodanti užklausą. Patvirtinimo nėra pakaitalas pabėgti!

(Užuomina: ar jūs pastebėjote, kaip “stacionarių” versijos buvo pedantiškas, jų naudojimo
iš backticks? Autorius yra asmeniškai įsitikinęs, kad jis didina
aiškumą klausimus priėmimo aiškiau atskirti
identifikatoriai ir vertybes. Ji taip pat padeda tais atvejais, kai naujokas
programuotojas bando naudoti raktinį vardas, sutrumpinimas
“aprašymas” “desc” yra dažniausiai pasitaikantis atvejis. Nuo šaltinio kodas
skaityti daugiau kartų, nei ji yra parašyta, skaitomumas yra tiesiogiai susijęs
saugumo. Pedantiškas, cituodamas todėl turi dvigubą premiją, kai raštu
secure code.)

10. Apie

Aleksandras “Mordred” Andonov yra nepriklausomas saugumo tyrėjas ir
konsultantas. Savo saugumo interesų melas kuriant metodikas
secure web programavimo ir mokosi, kaip realaus pasaulio paraiškas kovoti
(arba nesugeba spręsti) su saugumo problemomis.
Jis gali būti pasiektas bent sir(point)mordred(on)gmail.

11. Nuorodos

[1] “SQL Injection: Are your web applications vulnerable?” iki Kevin Spett[1] “SQL Injection: Are your web applications vulnerable?” iki Kevin Spett http://www.spidynamics.com/support/whitepapers/WhitepaperSQLInjection.pdf

[2] “Advanced SQL Injection In SQL Server Applications” iki Chris Anley http://www.ngssoftware.com/papers/advanced_sql_injection.pdf

[3] “Blind SQL Injection: Are your web applications vulnerable?” iki Kevin Spett http://www.spidynamics.com/support/whitepapers/Blind_SQLInjection.pdf[

4] “Blind Sql-Injection in MySQL Databases” iki Zeelock http://seclists.org/bugtraq/2005/Feb/0288.html

[5] “SQL Injection Cheat Sheet” iki Ferruh Mavituna http://ferruh.mavituna.com/makale/sql-injection-cheatsheet/

[6] “SQL Injection Cheat Sheet” iki David Kierznowski http://michaeldaw.org/sql-injection-cheat-sheet/

[7] “PHP Manual :: SQL Injection” http://php.net/manual/en/security.database.sql-injection.php

[8] “Security Corner: SQL Injection” by Chris Shiflett http://shiflett.org/articles/sql-injection

[9] “PHP Manual :: mysql_real_escape_string()” http://php.net/mysql_real_escape_string

[10] “addslashes() Versus mysql_real_escape_string()” by Chris Shiflett http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string

[11] “MySQL Reference Manual :: Identifiers” http://dev.mysql.com/doc/refman/5.1/en/identifiers.html

[12] “MySQL Reference Manual :: String Comparison Functions :: LIKE” http://dev.mysql.com/doc/refman/5.1/en/string-comparison-functions.html#operator_like

[13] “MySQL Reference Manual :: Regular Expressions :: REGEXP / RLIKE” http://dev.mysql.com/doc/refman/5.1/en/regexp.html

[14] “PHP Security Guide” by Chris Shiflett http://shiflett.org/php-security.pdf

[15] “SQL Injection Attacks” by Prof. Jim Whitehead http://www.cse.ucsc.edu/classes/cmps183/Spring06/lectures/SQL%20Injection%20Attacks.pdf

[16] “Guide to PHP Security: Chapter 3. SQL Injection” iki Ilia Alshanetsky http://dev.mysql.com/tech-resources/articles/guide-to-php-security-ch3.pdf

[17] “OWASP :: Avoiding SQL Injection” http://www.owasp.org/index.php/Avoiding_SQL_Injection#WARNING:_Escaping_table_names

[18] “PHP Manual :: mysql_real_escape_string()”, interneto archyvo nukopijuoti Gruodis 2005 http://web.archive.org/web/20051217125937/us3.php.net/mysql_real_escape_string[19] “MySQL Reference Manual :: Control Flow Functions :: IF()” http://dev.mysql.com/doc/refman/5.1/en/control-flow-functions.html#function_if

 

Grįžti į pagrindinį

Leave a Reply

Your email address will not be published. Required fields are marked *