Pagrindiniai web sistemų pažeidžiamumai Ir saugos būdai


1. Injekcija

 

Injekcija – pažeidžiamumo išnaudojimas interpretatoriui vykdant pateiktuose duomenyse įterptą kodą. Viena dažniausiai pasitaikančių injekcijos pažeidžiamumo rūšių – SQL injekcija[6], kurios metu įvestyje yra įterpiama SQL išraiškos dalis ar forma, siekiant įvykdyti naujai suformuotą išraišką (pvz. iš duomenų bazės gauti informaciją apie vartotojus, įterpti kenkėjiškus įrašus ir pan.). Injekcijos pažeidžiamumai taip pat gali būti aptinkami LDAP, Xpath užklausose, operacinės sistemos komandose, programų argumentuose ir t.t. Paprastai tokio tipo pažeidžiamumai lengviausiai aptinkami analizuojant programos kodą, naudojantis jau minėtu pasitikėjimo ribos modeliu (ieškoma vietų, kuriose yra interpretuojama galimai nepatikima įvestis).

SQL injekcijos pavyzdžiui naudosime Damn Vulnerable Web App aplikacija, kurioje pateikiama forma, grąžinanti duomenis apie pasirinktą vartotoją:

sqli-observe

Žvilgtelėjus į formos duomenų apdorojimo kodo fragmentą pasidaro aišku, kad aplikacija reikiamai nefiltruoja vartotojo įvesties:

$id = $_GET['id'];
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
$result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );

Tolesnioje iliustracijoje bandome įterpti paprastą SQL kodą:

sqli-test

Grąžinami visų sistemos vartotojų duomenis, toks elgesys aplikacijoje nėra numatytas. Pavyzdyje id parametrui pateiktas SQL kodas efektyviai pakeitė interpretuojamos
užklausos logiką. Interpretatorius aplikacijoje įvykdė šią SQL eilutę:

SELECT first_name, last_name FROM users WHERE user_id = '' or 1=1 #'

Specialus viengubos kabutės simbolis čia yra naudojamas SQL parametro uždarymui, tolimesni simboliai yra tiesiogiai vykdomi interpretatoriaus. Grotelės yra naudojamos komentaro pažymėjimui, todėl toliau sekantis kodas nėra vykdomas.

Įsilaužėlis norėdamas gauti MySQL vartotojo „admin” slaptažodžio maišos kodą (hash) galėtų įterpti šį „User ID” parametrą:

' union SELECT user, password FROM mysql.user where user='admin' #

sqli-exploit

„UNION” raktinio žodžio pagalba dvi užklausos gali būti sujungiamos į vieną, o gražinami rezultatai yra kombinuojami. Pirminiam slaptažodžio tekstui iš maišos kodo gauti šiuo atveju gali būti naudojamos įvairios nulaužinėjimo technikos (pvz. Jėgos metodu slaptažodžius parenkanti Cain&Abel programa[27]).

Dar viename, žemiau pateiktame pavyzdyje programa formuoja SQL užklausą, grąžinančia duomenis apie pasirinktą vartotoją, naudojant jo vardą bei slaptažodį (toks kodas yra dažnai aptinkamas autentifikacijos modulyje):

$statement = "SELECT * FROM users WHERE name='$username' AND pass='$password'";

Įsilaužėlis pakeitęs ‘name’ arba ‘pass’ parametrus vėlgi gali lengvai manipuliuoti pačia užklausa.  Tarkime, kad pavyzdys viršuje yra skirtas autentifikuoti vartotoją naudojant paprastą HTML formą. Išnaudojant injekcijos pažeidžiamumą vietoje vartotojo vardo galėtų būti įvedama ši reikšmė:

abc' OR 1 = 1 --

Viršuje esanti eilutė naudoja du specialiuosius SQL simbolius – viengubą kabutę bei dvigubą brūkšnį. Eilutė prasideda atsitiktiniais simboliais, kurie užpildo vartotojo vardo parametrą. Vienguba kabutė yra naudojama pažymėti eilutės, pateikiamos kaip SQL užklausos parametro, galui. Dvigubas brūkšnys čia yra naudojamas pažymėti SQL komentarą, todėl po jo dešinėje likęs kodas, skirtas slaptažodžio patikrai, nėra vykdomas. Sėkmingai išnaudojant šį SQL injekcijos pažeidžiamumą DB interpretatorius, leisdamas įsilaužėliui autentifikuotis sistemoje ‘abc’ vardu, vykdytų tokią užklausą:

SELECT * FROM users WHERE name='abc' OR 1 = 1 - ' AND pass='password'

Pavojingesnės atakos gali kilti kombinuojant keletą SQL užklausų. Išnaudojant viršuje pateiktą spragą, įsilaužėlis, norėdamas ištrinti visą users lentelę galėtų suformuluoti šią užklausą:

SELECT * FROM users WHERE name='abc' OR 1=1; DROP TABLE users --

Apsisaugojimui nuo injekcijos atakų siūloma naudotis saugiomis API sąsajomis, užuot tiesiogiai pateikiant parametrus interpretatoriui. Tokiose sąsajose paprastai dinaminės išraiškos yra parametrizuojamos, užtikrinant, kad bet kokia įvestis bus apdorojama nustatytose ribose.
Dauguma duomenų bazių sąsajų tam palaiko parametrų saistymą (binding). Žemiau pateiktame pavyzdyje PHP kodas naudoja mysqli[24] plėtinį:

$query = $dbConnection->prepare('SELECT * FROM users WHERE name = ?');
$query->bind_param('s', $name);
$query->execute();
$result = $query->get_result();

Vykdant šį kodą SQL užklausa serveryje yra apdorojama ir paruošiama be vartotojo parametro. Duotas parametras su užklausa yra susiejamas tik tolimesniame vykdymo etape, todėl į jį visada žiūrima kaip į standartinį eilutės tipo parametrą.

Modernūs Web karkasai (Web Frameworks) dažnai pateikia abstrakcijos bibliotekas, tokias kaip ORM (Object Relational Manager), siekiant, kad programuotojas tiesiogiai
nesinaudotų interpretatoriumi. Jei tokiomis sąsajomis pasinaudoti galimybiu nėra, tuomet visi specialiai interpretuojami simboliai privalo būti išskirti, pvz. PHP
atveju galėtų būti naudojama mysql_real_escape_string() funkcija[7]