Tarkim turime puslapį, kuriame yra tam tikra forma (pvz: registracijos,
prisijungimo), kurioje įvesti duomenys tikrinami/įrašomi i SQL bazę
(Kaip pavyzdį naudosiu prisijungimo formą). Vieno iš formos įvedimo
laukelio vardas yra 'NAME', kuriame reikia įvesti prisijungimo vardą.
Taigi, tokio puslapio, kuris tikrina įvestus duomenis, SQL užklausa turėtų atrodyti daug maž taip:
(PHP pvz: mysql_query("'SELECT name,pass,email FROM users WHERE name='$name'");)
Čia $NAME yra puslapio kintamasis, kuris sudarytas iš formoj įrašyto prisijungimo vardo (PHP pvz: $NAME = $_POST['NAME'];).
Tikslų laukelių ar 'stalo' pavadinimo mes nežinom, bet tai tam tikromis užklausomis ir spėliojimais galima juos sužinuot.
Pamėginus į prisijungimo formą įvesti atsitiktinius vardą ir
slaptažodį, mums turėtų parodyti klaidą apie neteisingą slaptažodį ar
vartotojo vardą. Jeigu pamėgintume vietoje vartotojo vardo įvesti Vardas', tada SQL užklausa atrodytų taip:
Tokia užklausą turėtų mums gražinti pranešimą apie sintaksės klaidą,
kadangi užklausos pabaigoje yra dvi apostrofos. Jeigu tikrai gražino
tokį pranešimą, reiškia puslapio informaciją nėra filtruojama ir
puslapis pažeidžiamas, jei gražino kitokį pranešimą - puslapis saugus.
Dabar pasidarome užklausą kuri visada gražntų teigiamą reikšmę:
SELECTlaukeliu_pavadinimai FROMtable_pav WHERElaukelio_pav = 'Vardas' OR 'x'='x';
Kadangi x visados bus lygu x, tai ir ši užklausa visada bus 'true'. Su
tokia užklausa praeinamas tik vartotojo vardo patikrinimas, iš tiesų ką
gražins puslapis neaišku, tai lieka pačiam išssiaiškint pamėginus.
Tarkim kad sistema mums gražino pranešima kad netinkamas slaptažodis
(Vartotojo vardas atitiko, kadangi užklausa visa gražins 'true' tai
neturi reikšmės kas parašytas vardas)
Taigi turime tris pranešimų tipus:
1. Neteisingas vardas. (paprasta, teisinga SQL užklausa)
2. Neteisingasa slaptažodis. (kai vartotojo vardas apeitas)
2. Sintaksės klaida. (blogai suformuluota SQL užklausa)
Iki šiol yra nežinomi lakuų pavadinimai ir nėra funkcijos kurį juos
parodytų. Tad dabar prasideda spėliojimas. Pirma pasidaroma užklausa,
kuri mums parodys ar SQL užklausa teisinga ir leis atspėti laukelių
pavadinimus.
SELECTlaukeliu_pavadinimai FROMtable_pav WHERElaukelio_pav = 'x' AND email IS NULL; --';
Kadangi mums dabar vardas nerūpi, tai jis yra x. Čia 'email' yra
spėjamo lauko pavadinimas. Jei gauname pranešimą kad SQL sintaksė
bloga, vadinasi laukelio pavadinimas netoks, o jei gražina kad
neteisingas vartotojas - vadinasi jau žinomas laukelio pavadinimas.
Taigi taip atspėti galima ir kitus laukeliu pavadinimus.
Kadangi šis straipsins skirtas apsisaugoti nuo SQL Injection, tad
nematau prasmės aiškint kaip viskas vyksta toliau, tik pateiksiu keletą
pavyzdžių. Iš viso to jau turėtumete susidaryti bendrą vaizdą, kaip
viskas vyksta.
SELECTlaukeliu_pavadinimai FROMtable_pav WHERElaukelio_pav = 'x'; UPDATE users SET email = 'lauzinetojo@email.addr' WHERE user = 'admin' ';
SELECTlaukeliu_pavadinimai FROMtable_pav WHERElaukelio_pav = 'x'; DROP TABLE users; --';
Apsisaugojimas.
Nuo viso to galima apsisaugoti labai paprastai - naudojant tam tikras funkcijas, kurios neleidžia kartotis apostrofom.
PHP tam skirta funkcija yra mysql_escape_string(); - ši funkcija visas apostrofas pakeis į \', todėl šios apostrofos nebus skaitomos kaip užklausos sintaksės dalis.
Žinoma yra ir kitų būdų kaip apsisaugot. Pvz.: galima su Regular
Expresions patikrint ir neleisti įvesti tokių simbolių kaip apostrofos,
arba dar galima iš įvedamo teksto ištrinti tokius simbolius.