Injectia SQL
Multi developeri web nu stiu cum pot fi manipulate query-urile SQL, si acorda toata increderea unei asemenea comenzi. Query-urile SQL pot ocoli controalele de acces, in consecinta sa treaca peste metodele de autentificare si verificarile de autorizatie, iar cateodata pot chiar sa faciliteze accesul la comenzile de sistem.
Injectia directa prin comanda SQL este o tehnica in care atacatorul creaza sau modifica comenzile SQL pentru a scoate la iveala datele sensibile, sau pentru a suprascrie o anumita valoare, sau chiar pentru a executa comenzi periculoase la nivel de sistem. Acest lucru este infaptuit de catre aplicatia care preia inputul utilizatorului si combinata cu parametrii statici formeaza un query SQL. Urmatoarele exemple sunt bazate pe greseli italnite la web developeri.
Datorita lipsei validarii inputului si conectarii la baza de date cu drepturi de superuser, sau a unui user care poate crea la randul lui alti useri, atacatorul poate crea un superuser in baza de date.
Example#1 Impartirea rezultatelor in mai multe pagini ... si crearea de superuser (PostgreSQL and MySQL)
<?php
$offset = argv[0]; // atentie, nu se face validarea inputului!
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
// cu PostgreSQL
$result = pg_exec($conn, $query);
// cu MySQL
$result = mysql_query($query);
?>
// in cazul PostgreSQL 0; insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd) select 'crack', usesysid, 't','t','crack' from pg_shadow where usename='postgres'; -- // in cazul MySQL 0; UPDATE user SET Password=PASSWORD('crack') WHERE user='root'; FLUSH PRIVILEGES;
Notă: Exista o tehnica de a forta parserul SQL sa ignore restul queryului scris de developer, cu ajutorul -- care este simbolul pentru comentariu in SQL.
O reala posibilitate de a afla parole este de a manipula rezultatele din paginile de cautare. Singurul lucru de care are nevoie atacatorul este sa vada daca exista variabile in declaratiile SQL care nu sunt protejate corespunzator. Se pot manipula variabilele din formularele care utilizeaza WHERE, ORDER BY, LIMIT sau conditiile OFFSET din declaratiile SELECT Daca baza de date suporta UNION, atacatorul poate incerca sa lipeasca un query diferit la cel original pentru a lista parolele dintr-o tabela arbitrara. Folosirea parolelor criptate este pe deplin incurajata.
Example#2 Listarea unor articole ... si a unor parole (orice server de baze de date)
<?php
$query = "SELECT id, name, inserted, size FROM products
WHERE size = '$size'
ORDER BY $order LIMIT $limit, $offset;";
$result = odbc_exec($conn, $query);
?>
' union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable; --
Comanda SQL UPDATE nu este nici ea ocolita de probleme. Aceste query-uri sunt amenintate de atacurile prin taierea si alipirea unui nou query. In plus, atacatorul se mai poate juca si cu declaratia SET. In acest caz, atacatorul trebuie sa cunoasca schema SQL a tabelului din care doreste sa extraga sau sa manipuleze informatia. Acest lucru poate fi facut prin examinarea codului sursa, deci a variabilelor unui formular, sau prin procedeul brute-force. Nu exista multe conventii prin care se delimiteaza campurile pentru user sau parola.
Example#3 Formular de resetare a parolei ... si de castigare a unor privilegii (orice baza de date)
<?php
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
?>
<?php
// $uid == ' or uid like'%admin%'; --
$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --";
// $pwd == "hehehe', admin='yes', trusted=100 "
$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE
...;";
?>
Un exemplu inspaimantator despre cum poti rula comenzi la nivel de sistem de operare pe unele servere de baze de date.
Example#4 Atacarea sistemului de operare pe care lucreaza baza de date (MSSQL Server)
<?php
$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";
$result = mssql_query($query);
?>
<?php
$query = "SELECT * FROM products
WHERE id LIKE '%a%'
exec master..xp_cmdshell 'net user test testpass /ADD'--";
$result = mssql_query($query);
?>
Notă: Unele dintre exemplele de mai sus sunt legate de animite baze de date. Acest lucru nu inseamna ca atacuri similare nu pot avea loc pe produse similare lor. Baza de date poate fi vulnerabila intr-o maniera asemanatoare, fiind exploatabila prin metode asemanatoare.
Tehnici de evitare
Puteti spune ca un atacator trebuie sa detina informatii despre baza de date si schema acesteia in majoritatea exemplelor. In maoritatea cazurilor asa este, dar nu se stie niciodata cum poate fi descoperita aceasta, in mod direct sau indirect. Daca folositi un soft open source, sau alt pachet disponibil publicului larg (content management system sau forum), atacatorii pot duplica cu usurinta codul dumneavoastra. De asemenea un risc il reprezinta si designul necorespunzator al bazei de date.
Aceste atacuri sunt de obicei bazate pe exploatarea codului scris de developeri fara a lua in calcul securitatea lui. Niciodata nu aveti incredere in nici un fel de input, mai ales cand acesta provine de la partea client side, sau camp select, camp ascuns sau cookie.Primul exemplu arata ca asemenea scapari pot duce la query-uri dezastruoase.
- Niciodata nu va conectati la baza de date ca superuser sau ca orice alt utilizator care poate manipula mai multe baze de date decat cea folosita. Folositi intotdeauna useri cu privilegii limitate.
- Verificati daca un input contine tipul de date corect. PHP are o varietate de functii de validare, de la cele mai simple, care pot fi gasite in Variable Functions si in Character Type Functions (e.x. is_numeric(), ctype_digit()) si pana la Expresiile regulate compatibile Perl.
-
Daca aplicatia asteapta un input numeric, incercati sa verificati datele cu functia is_numeric(), sau schimbati tipul variabilei utilizand functia settype(), sau folositi reprezentatia numerica prin sprintf().
Example#5 O metoda mai sigura metoda de query pentru paginare
<?php
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
// observati %d din query care inseamna formatul integer, folosirea %s (string) ar fi fara sens
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;",
$offset);
?> - Adauga functia addslashes() sau addcslashes() fiecarui input care nu este numeric. Vezi primul exemplu. Dupa cum arata exemplul, eliminarea ghilimelelor in partea statica a query-ului, nu este de ajuns.
- Nu afisati informatii specifice bazei de date, in special despre schema acesteia. Vezi de asemenea Raportul erorilor si Manipularea Erorilor si a functiilor de logare.
- Se pot folosi proceduri si seturi de functii stocate sau metode predefinite, pentru ca utilizatorii sa nu interactioneze direct cu tabelele, dar aceste metode au alte consecinte.
In afara de acestea, puteti loga query-urile in interiorul scriptului si in baza de date, daca aceasta suporta acest lucru. Bineinteles, fenomenul de logging nu poate preveni atacurile sau incercarile de a vatama baza de date, dar pot fi folositoare pentru a lua urmele intruziunilor. Acestea se pot dovedi foarte eficiente in gasirea potentialelor gauri din aplicatii. Mai multa informatie despre script este cu atat mai bine venita.