top

[Tutorial]Anti SQL Inject

 
Acest forum este inchis, nu se pot scrie, crea, raspunde sau modifica subiecte   Acest subiect este inchis, nu se pot crea sau raspunde la mesaje    Pagina de start a forumului R-Zone Community -> Cum sa faci server de MuOnline
Autor Mesaj
rZone
Owner
Owner
rZone

Data inscrierii: 27/Iul/2010
Mesaje: 65

MesajTrimis: 28/07/2010 23:27    Titlul subiectului: [Tutorial]Anti SQL Inject Raspunde cu citat (quote)

*Am vazut foarte multe servere in ultima vreme "picand" ...acesta este mai mult ca un sfat!

Folositi unul din web-urile de mai jos:
*Aceste web-uri nu pot fi injectate sau pana la momentrul de fata nu sau gasit hole-uri (gauri) pentru a le injecta...deci va recomand:
-MuWeb 0.3
-MuWeb 0.6
-MuWeb 0.9
-DMG Team WebSite v0.1
*DMG Team WebSite v0.2 coming soon

Pentru inceput sa vorbim putin despre Injection:

Citat:

Un mit despre SQL Injection

În prezent, cea mai mare parte a aplicaţiilor dezvoltate la noi şi în mulțimea largă folosesc pe undeva şi o bază de date, iar limbajul favorit pentru interacţiunea cu diferitele implementări de motoare relaţionale este SQL (Structured Query Language). În condiţiile în care securitatea are prioritate maximă în absolut orice aplicaţie, nu e de mirare că noţiunea de SQL Injection, un atac foarte comun asupra bazelor de date, a fost tratată pe larg în distincte materiale.

În debutantul rând, să clarificăm puţin ce înseamnă injectarea de cod în general şi SQL Injection în particular. Injectarea de cod este procesul prin care cod executabil străin este introdus în memoria unui proces, de obicei deghizat în date, prin intermediul unei vulnerabilităţi oarecare. Un exemplu tradițional de injectare de cod este exploatarea vulnerabilităţilor de tip buffer overrun, cu injectarea de cod executabil prin intermediul unui şir de caractere invalid şi neverificat de aplicaţie.

SQL Injection reprezintă introducerea de comenzi SQL într-un script întrebuințat de o aplicaţie de baze de date. Vectorul de atac îl reprezintă instrucţiunile SQL generate dinamic de aplicaţie, mai târziu cum vom vedea în detaliu puţin mai jos. Un atac SQL Injection poate avea consecinţe variate, de la divulgarea de informaţii confidenţiale şi până la preluarea controlului perfect asupra serverului de baze de date, în funcţie de prezenţa altor vulnerabilităţi.

Problema îşi are originile în modalitatea tradiţională de a scrie interogările SQL: Direct în codul aplicaţiei, sub variantă de şiruri de caractere concatenate pentru obţinerea interogării care va fi trimisă serverului. De exemplu, pentru a vedea dacă o combinaţie utilizator + parolă se află în baza de date, am putea scrie:

SELECT COUNT(*) FROM [dbo].[Users]
WHERE [Username] = 'user' AND [Password] = 'pass'

(Să trecem peste faptul că stocarea parolelor direct în baza de date e o idee foarte proastă). Într-o aplicaţie scrisă în C# cu ADO.NET, o astfel de comandă ar putea fi formulată în felul următor:

// Codul de mai jos nu tine cont de necesitati
// ale aplicatiilor reale: eliberarea resurselor, prinderea
// exceptiilor samd. Nu il folositi ca atare in aplicatii
// de productie
string connectionString;
string userName, password;
// ...
// Initializarile de rigoare
// ...
SqlConnection sqlConn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = sqlConn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT COUNT(*) FROM [dbo].[Users] " +
"WHERE [Username] = '" + userName + "' AND [Password] = '" +
password + "'";
sqlConn.Open();
cmd.ExecuteNonQuery();
// ... Alte comenzi

Un exerciţiu mic pentru cititori: Să spunem că pe urmă apelarea procedurii stocate, într-o variabilă întreagă numită userCount avem numărul de utilizatori pentru care combinaţia utilizator + parolă există în baza de date. Cum e mai bine să scriem testul: if (userCount != 0) sau if (userCount == 1)? De ce?

Ce se întâmplă dacă, dintr-un pretext sau altul, în loc de numele de utilizator, cineva introduce ' OR 1 = 1 --?

Comanda SQL devine:

SELECT COUNT(*) FROM [dbo].[Users]
WHERE [Username] = '' OR 1 = 1 -- AND [Password] = '...'

Problema e că întâiul apostrof devine perechea celui care deschidea şirul reprezentând numele utilizatorului, 1 = 1 este întotdeauna adevărat, OR este adevărat dacă unul din operanzi este adevărat, şi atunci expresia din clauza WHERE e adevărată tot timpul. (Şirul -- reprezintă un comentariu în Transact SQL - varietatea de SQL din Microsoft SQL Server - şi textul de după acest şir este ignorat.)

Exemplul de mai sus e un fel de "Hello, World!" al SQL Injection şi îl găsiţi în nenumărate materiale. O aplicaţie ce îşi construieşte interogările în mod dinamic în acest fel e o gaură de securitate aşteptând să fie exploatată, iar exemplul dat este inocent în comparaţie cu ce se poate obţine prin SQL Injection.

În general vulnerabilităţi de acest gen apar în aplicaţii web, fiindcă prototipul aplicaţie web + bază de date este extraordinar de popular. Nu vă lăsaţi păcăliţi, asta nu înseamnă că doar aplicaţiile web sunt vulnerabile. Orice aplicaţie care îşi construieşte cererile în mod dinamic ca în exemplul dat expune acest gen de vulnerabilităţi. Dar nu aici doream să ajung.

Mitul pe care vreau să îl scutur puţin este "Prin întrebuințarea procedurilor stocate riscul atacurilor de tip SQL Injection dispare". Această afirmaţie ascunde de fapt o altă afirmaţie cu care nu sunt de acord: Cererile formulate dinamic sunt în mod inerent "diabolice". Mai mult, unii adoptă afirmaţia de mai sus ca atare şi o susţin cu fervoare religioasă, excluzând să ştie toate aspectele problemei.

Nu mă înţelegeţi greşit: Sunt un fan uriaş al procedurilor stocate. Motivele pentru care folosesc aproape exclusiv proceduri stocate ţin de modularizarea codului (care duce la localizarea modificărilor şi la uşurinţa în întreţinere), de posibilitatea de a testa procedurile stocate individual, de securizarea lor prin liste de control al accesului, de eleganţa aplicaţiei pe ansamblu.

Cu toate acestea, există unele lucruri pe care procedurile stocate nu le pot face în mod elegant. Să vă dau un exemplu simplu: Să presupunem că avem o tabelă cu utilizatori care conţine printre altele două coloane (varchar de o extindere oarecare, pentru simplitate), numite FirstName şi LastName. Să presupunem că pe undeva prin aplicaţia construită pe această bază de date am un câmp text în care utilizatorii pot introduce nume care să fie căutate în baza de date. Pentru că avem o aplicaţie extrem de simplă nu folosim Full Text Search sau alte artificii spectaculoase, ci recurgem la o interogare banală.

Dacă un utilizator introduce "Ioan Popescu" în câmpul text, presupunem că doreşte să vadă acele persoane din baza de date care au în componenţa numelui complet cele două cuvinte. Atunci, o interogare ar putea arăta în felul următor:

SELECT * FROM [dbo].[Users]
WHERE (([FirstName] LIKE '%Ioan%') OR ([LastName] LIKE '%Ioan%')) AND
(([FirstName] LIKE '%Popescu%') OR ([LastName] LIKE '%Popescu%'))

Dacă, însă, utilizatorul introduce "Ioan Gigel Popescu", interogarea devine:

SELECT * FROM [dbo].[Users]
WHERE (([FirstName] LIKE '%Ioan%') OR ([LastName] LIKE '%Ioan%')) AND
(([FirstName] LIKE '%Gigel%') OR ([LastName] LIKE '%Gigel%')) AND
(([FirstName] LIKE '%Popescu%') OR ([LastName] LIKE '%Popescu%'))

Aşa ceva nu e tocmai banal de implementat într-o procedură stocată, ţinând cont că nu se poate şti în avans cum va arăta clauza WHERE. Cum nu dorim să formulăm cererea în mod dinamic, am cam rămas fără opţiuni, nu? Ei bine, nu. Soluţia o reprezintă cererile parametrizate. Presupunând că folosim C#, ADO.NET şi SQL Server, iată cum ar arăta o cerere parametrizată pentru prima interogare:

// Sa presupunem ca tabloul e deja initializat
// si ca am verificat validitatea datelor
// (tabloul are cel putin un element,
// nu exista nici un null, nici un sir
// vid, am testat fiecare cuvant cu
// expresii regulate pentru a ne asigura
// ca avem doar litere samd).
string[] keywords;
string connectionString = "...";

SqlConnection sqlConn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = sqlConn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM [dbo].[Users] WHERE ";
// ATENTIE: Codul de mai jos este doar un exemplu
// In cod real va recomand sa folositi StringBuilder
// pentru a concatena siruri numeroase si sa scrieti
// cod mai putin criptic.
for (int i = 0; i < keywords.Length; ++i)
{
if (i > 0)
{
cmd.CommandText += " AND ";
}
cmd.CommandText += string.Format(
"(([FirstName] LIKE @Argument{0}) OR ([LastName] LIKE @Argument{0}))", i);
cmd.Parameters.Add(
string.Format("@Argument{0}", i),
SqlDbType.VarChar, 80).Value = keywords[i];
}
sqlConn.Open();
SqlDataReader reader = cmd.ExecuteReader();
// ... samd

Cu o abordare de genul acesta, prima interogare devine

SELECT * FROM [dbo].[Users]
WHERE (([FirstName] LIKE @Argument0) OR ([LastName] LIKE @Argument0)) AND
(([FirstName] LIKE @Argument1) OR ([LastName] LIKE @Argument1))

iar a doua devine

SELECT * FROM [dbo].[Users]
WHERE (([FirstName] LIKE @Argument0) OR ([LastName] LIKE @Argument0)) AND
(([FirstName] LIKE @Argument1) OR ([LastName] LIKE @Argument1)) AND
(([FirstName] LIKE @Argument2) OR ([LastName] LIKE @Argument2))

În exemplele date, Argument0 .. Argument2 conţin "%Ioan%", "%Gigel%", respectiv "%Popescu%" (fără ghilimele, evident). Avantajul este că indiferent ce ar conţine, şirurile de caractere nu vor modifica în nici un fel căutarea aşa cum o face un atac SQL Injection.

Repetaţi după mine: "Prin utilizarea cererilor parametrizate riscul atacurilor de tip SQL Injection dispare". În general, vă recomand să folosiţi proceduri stocate cu cea mai mare încredere, pentru că au o listă întreagă de avantaje. Ţineţi cont, însă, că invocarea procedurilor stocate este un caz particular de invocare al unei cereri parametrizate. Dacă ajungeţi într-o situaţie când trebuie neapărat să compuneţi dinamic o interogare, aceasta este modalitatea corectă de a o face.

Atrag atenţia asupra acestui aspect dintr-un motiv simplu: Unii oameni asociază procedurile stocate cu eliminarea SQL Injection fără a înţelege că parametrizarea este cea care duce la securizarea aplicaţiei. În aceste condiţii, respectivele persoane adoptă politici de genul "folosim doar proceduri stocate în aplicaţie", ajung în situaţii în care cererile formulate dinamic constituie singura soluţie, aşa că scriu o procedură stocată care acceptă un argument de tip şir de caractere, pe care îl execută în interior cu EXECUTE sau cu sp_executesql, minus să realizeze că au ajuns de unde au plecat.

Pentru a nu mai destul de lungi vorba, să recapitulăm:

* NU concatenaţi şiruri de caractere pentru a forma comenzi SQL şi NU executaţi aceste comenzi prin nici un mijloc.
* Folosiţi numai cereri parametrizate. Încercaţi să folosiţi proceduri stocate în cât mai multe situaţii, iar când acest lucru nu este posibil creaţi interogările dinamic, dar cu argumentele transmise ca parametri.

Sper să vă fie de folos sfatul meu. Dacă mai aveţi alte sugestii legate de acest subiect, aştept comentarii.
Sus
Vezi profilul utilizatorului Trimite mesaj privat
Afiseaza mesajele pentru a le previzualiza:    Subiectul anterior : Subiectul urmator  
Acest forum este inchis, nu se pot scrie, crea, raspunde sau modifica subiecte   Acest subiect este inchis, nu se pot crea sau raspunde la mesaje    Pagina de start a forumului R-Zone Community -> Cum sa faci server de MuOnline Ora este GMT + 2 ore
Pagina 1 din 1

 
Mergi direct la:  
Nu puteti crea un subiect nou in acest forum
Nu puteti raspunde in subiectele acestui forum
Nu puteti modifica mesajele proprii din acest forum
Nu puteti sterge mesajele proprii din acest forum
Nu puteti vota in chestionarele din acest forum

Fa-ti si tu propriul forum GRATUIT, pe www.myforum.ro