Forum und email

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);

?>
Utilizatorii obisnuiti fac click pe linkurile 'next', 'prev' unde este variabila $offset encodata in URL. Scriptul se asteapta ca variabila $offset sa fie un numar decimal. Cu toate acestea, ce se intampla daca cineva incerca sa modifice URL-ul si s-ar folosi de urlencode() pentru a insera urmatorul URL:
// 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;
Daca se executa, atunci scriptul va schimba parola superuserului root. Observati ca 0; este pentru a oferi un offset corect query-ului si pentru a-l termina.

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);

?>
Partea statica a queryului poate fi combinata cu inca un SELECT care sa arate parolele:
'
union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from usertable;
--
In acest query (ne-am jucat cu ' si --) care au fost asignate variabilei $query, adica query-ului cu probleme.

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';";
?>
Dar un utilizator rau voit introduce ' or uid like'%admin%'; -- in locul $uid pentru a schimba parola utilizatorului admin, sau pentru a seta valoarea $pwd in "hehehe', admin='yes', trusted=100 " (cu spatiu la sfarsit) pentru a castiga mai multe privilegii. Apoi queryul ar arata in felul urmator:
<?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);

?>
Daca un atacator introduce valoarea a%' exec master..xp_cmdshell 'net user test testpass /ADD' -- in loc de $prod, atunci variabila $query va deveni:
<?php

$query  
"SELECT * FROM products
                    WHERE id LIKE '%a%'
                    exec master..xp_cmdshell 'net user test testpass /ADD'--"
;
$result mssql_query($query);

?>
Serverul MSSQL executa declaratia SQL incluzand si comanda de adaugare de user nou in baza de date cu conturi locale. Daca aceasta aplicatie rula ca sa si serviciul MSSQLSERVER rula cu destule privilegii, atacatorul avea acum un cont pe serverul respectiv unde sa execute comenzi.

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.