SQL Injection, come difendersi

Leave a comment
Share

Che cos’è la SQL Injection

Che cos’è il SQL Injection? viagra online canada pharmacy È la tecnica per cui un utente malintenzionato utilizza la parte di input per creare SQL dinamico per poter accedere al database. La pericolosità dell’attacco poi aumenta se la connessione al database si ha senza definizione accurata di un livello di privilegi. Molte applicazioni infatti tendono ancora ad accedere alla base dati tramite la classica e famosa combinazione user/pass sa/sa o utenti amministratori. Se la nostra applicazione permette SQL Injection la sicurezza è del tutto compromessa e i danni potenziali sono infiniti.

Scenario tipico

Immaginiamo di avere una semplice applicazione che effettua ricerche su una lista di utenti, costituita da una sola pagina .aspx con due TextBox ed un Button che invia i dati al server.
Inoltre avremo un database Utili con all’interno una tabella così definita e popolata:

Listato SQL n°1

CREATE TABLE dbo.Utenti ( IDUtente int IDENTITY(1,1) NOT NULL , Nome varchar(30) NOT NULL , Cognome varchar(30) NOT NULL , CONSTRAINT PK_dboUtenti PRIMARY KEY CLUSTERED ( IDUtente ) ) GO INSERT INTO dbo.Utenti (Nome, Cognome) VALUES ('Alessandro', 'Alpi') INSERT INTO dbo.Utenti (Nome, Cognome) VALUES ('Marco', 'Rossi') INSERT INTO dbo.Utenti (Nome, Cognome) VALUES ('Michael', 'Denny') INSERT INTO dbo.Utenti (Nome, Cognome) VALUES ('Daniele', 'Zanella') INSERT INTO dbo.Utenti (Nome, Cognome) VALUES ('Manuele', 'Carra') GO La pagina è la seguente:

Listato n°1

<body>
<form id=”form1″ runat=”server”>
<div>
<asp:TextBox ID=”txtNome” runat=”server” />

<asp:Button ID=”btnCercaProtetto” runat=”server” Text=”Ricerca Protetta” OnClick=”btnCercaProtetto_Click” />
<asp:Button ID=”btnCercaInjection” runat=”server” Text=”SQL Injection” OnClick=”btnCercaInjection_Click” />
<asp:GridView ID=”GWRisultati” runat=”server” AutoGenerateColumns=”true”>
</asp:GridView>
</div>
</form>
</body>

La ConnectionString definita per connetterci al nostro SQL Server 2005 prevede accesso tramite l’utente sa (pratica da evitare assolutamente, ma utile per l’esempio).
Ipotizziamo inoltre di utilizzare un metodo scritto da noi per effettuare la connessione e la ricerca sulla tabella sopra definita:

Listato n°2

private void BindRicerca(String strNome, String strConn)
{
DataTable dt = new DataTable(“Risultati”);
SqlConnection oConn = new SqlConnection(strConn);
SqlCommand oCmd = new SqlCommand(“SELECT * FROM dbo.Utenti WHERE Nome = ‘” + strNome + “‘”, oConn);

SqlDataAdapter da = new SqlDataAdapter(oCmd);
da.Fill(dt);

GWRisultati.DataSource = dt;
GWRisultati.DataBind();
}

Come avviene un SQL Injection Attack

Eseguendo una ricerca utilizzando la nostra TextBox txtNome avremo il risultato sperato, ovvero una griglia con tante righe quante sono quelle che hanno il campo nome che eguaglia il nostro input.

La query restituita dalla concatenazione tra il nostro codice e l’input sarà simile a questa:

SELECT * FROM dbo.Utenti WHERE Nome = ‘Alessandro’

Ma con una semplice modifica, un utente malintenzionato, anche se non particolarmente “skillato” in materia di database, può effettuare una richiesta pericolosissima. Immaginiamo di inserire nella TextBox il valore “x’ OR ‘a’='a”, ecco la SELECT risultante:

SELECT * FROM dbo.Utenti WHERE Nome = ‘x’ or ‘a’='a’

Come si vede subito la query risponderà sempre con tutto l’elenco dei record della tabella, in quanto ‘a’='a’ è una condizione sempre vera.

Questo è un primo esempio, molto semplice ma allo stesso tempo molto
pericoloso. Pensate solo ad una query che deve controllare la login di
un utente durante la fase di autenticazione. Normalmente la query si
aspetta come risultato una sola riga. A questo punto concatenando
statement SQL opportunamente seguendo l'esempio precedente è possibile
avere accesso ad un sito Internet o ad un'area riservata amministrativa
senza conoscerne la password. Questo esempio non viene mostrato perchè
l'articolo non è un Tutorial o una guida per diventare Hacker ma è a scopo didattico.

Ricordiamo inoltre che la ConnectionString è basata su "sa" e quindi un sysadmin, con il massimo delle permission. Proviamo ora a mettere questa la stringa come Input:

"x’; DROP TABLE dbo.Utenti; --"

nella textbox. Eseguiamo la prima ricerca senza ottenere nulla e appena lanciamo la seconda ?

N.B. Ricordiamo che tramite l'uso del punto e virgola (;) è possibile concatenare più statement SQL da passare in un'unica volta a SQL Server. Mentre l'uso del doppio meno (--)
consente di commentare/remmare ciò che viene dopo nella stringa di
comandi, quindi ignora completamente eventuali statement SQL successivi.

L'errore, che probabilmente gli sviluppatori ed i DBA non avevano previsto è drammatico. La tabella dbo.Utenti non esiste più. È vero che per trovare il nome della tabella, bisogna fare alcuni tentativi (o usare altri metodi di SQL Injection).
Però una volta arrivati lì, il gioco è fatto ed è grave che un utente
che naviga possa arrivare fino a quel punto. Fortunatamente esistono
tanti rimedi.

Come difendersi dal SQL Injection

Come fare? L’oggetto è andato perduto. Se esiste un piano di Backup, il restore ci permette di ricaricare lo stato del database all’ultimo backup effettuato. Ma tutto quello che intercorre tra quest’ultimo e l’attacco dell’utente malintenzionato è andato perso completamente.
Quindi la vera risposta è pensare a come difendersi la prossima volta. E le soluzioni ci sono:

1) Stored Procedures

Col passaggio di parametri si riduce di molto l’attacco di malintenzionati, ma è necessario richiamare le Stored Procedures sfruttando la collection Parameters dell’oggetto SqlCommand e non tramite codice SQL (CommandType = Text). Nel secondo caso infatti è possibile passare input non filtrato per effettuare con semplicità un attacco SQL Injection.
La Stored Procedure potrebbe essere simile a questa:

Listato SQL n°2

CREATE PROCEDURE dbo.proc_GetUsers ( @Nome varchar(20) ) AS BEGIN SET NOCOUNT ON; SELECT * FROM dbo.Utenti WHERE Nome = @Nome END

La chiamata da codice sarà questa:

Listato n°3

private void BindRicercaSP(String strNome, String strConn)
{
DataTable dt = new DataTable(“Risultati”);
SqlConnection oConn = new SqlConnection(strConn);

// nome Stored Procedure
SqlCommand oCmd = new SqlCommand(“dbo.proc_GetUsers”, oConn);
// Tipo comando Stored Procedure
oCmd.CommandType = CommandType.StoredProcedure;

SqlDataAdapter da = new SqlDataAdapter(oCmd);

// collection Parameters
oCmd.Parameters.Add(“@Nome”, SqlDbType.VarChar, 20).Value = strNome;

Response.Write(oCmd.CommandText);
da.Fill(dt);

GWRisultati.DataSource = dt;
GWRisultati.DataBind();
}

2) Query parametriche

Allo stesso modo l’attacco viene ridotto se si utilizzano le Query Parametriche. Indicare parametri con i PlaceHolder “@nomeparametro” ed utilizzare la collection Parameters dell’oggetto SqlCommand è necessario per ridurre la superficie di attacco.
Ecco come modificare il nostro codice per le Query Parametriche:

Listato n°4

private void BindRicerca(String strNome, String strConn)
{
DataTable dt = new DataTable(“Risultati”);
SqlConnection oConn = new SqlConnection(strConn);

// parametro indicato con @NomeParametro
SqlCommand oCmd = new SqlCommand(“SELECT * FROM dbo.Utenti WHERE Nome = @Nome”, oConn);
SqlDataAdapter da = new SqlDataAdapter(oCmd);

// collection Parameters
oCmd.Parameters.Add(“@Nome”, SqlDbType.VarChar, 20).Value = strNome;

Response.Write(oCmd.CommandText);
da.Fill(dt);

GWRisultati.DataSource = dt;
GWRisultati.DataBind();
}

3) Utilizzo degli oggetti forniti da Visual Studio e dal Framework

Alcuni oggetti, come il SQLDataSource o l’AccessDataSource, forniscono un buon livello di protezione da attacchi di tipo SQL Injection. Quindi, appena possibile, si consiglia il loro utilizzo con la definizione dei Parameters:

Listato n°5

<asp:SqlDataSource ID=”SQLDS1″ runat=”server” SelectCommand=”SELECT * FROM dbo.Utenti WHERE Nome = @Nome” ConnectionString=”<%$ ConnectionStrings:UtiliConnectionString %>”>
<SelectParameters>
<asp:ControlParameter ControlID=”txtNome” Name=”Nome” />
</SelectParameters>
</asp:SqlDataSource>

4) Validazione dell’Input

La gestione della sicurezza di un’applicazione e del rischio di eventuali danni dall’esterno non è una cosa che si risolve rapidamente come per accendere una luce, sicurezza on/sicurezza off, è una cosa graduale che si raggiunge man mano nel lifecycle della costruzione di un’applicazione e bisognerebbe tenerne conto sin dall’inizio quando si disegna o progetta l’applicazione stessa.

La validazione dell’Input dell’utente riveste un ruolo di fondamentale importanza, perchè bloccando già lì eventuali tentativi d’attacco, si interrompe subito la catena che può portare danni nei livelli inferiori.

Per esempio è sempre buona norma nelle applicazioni Web ASP.NET e non applicare la proprietà MaxLength alle TextBox e quindi limitare il numero di caratteri. In questo modo eventuali query maligne o malformate non riuscirebbero a passare perchè troncate alla sorgente.

Utilizzare i Page Validators è un’altra tecnica molto utile. Se abbiamo una TextBox che accetta in Input un CAP quindi numerico, mi aspetto che il mio validatore Javascript verifichi che nella TextBox ci siano 5 numeri nè più nè meno.

Qualcuno potrebbe semplicemente disabilitare il Javascript e bypassare la validazione Client-side. Fortunatamente via codice ASP.NET si può comunque richiedere una validazione di tutti i validatori della Webform richiamando il Page.IsValid e verificare prima di procedere oltre se è tutto ok.

5) Livello di sicurezza ed autorizzazione su database

Progettare bene il livello di sicurezza e di accesso degli utenti al database è una pratica fondamentale che chi progetta l’architettura del database e la sua security dovrebbe tenere sempre a mente.

Come abbiamo visto esistono vari modi per evitare il SQL Injection.
Vorrei ripetere che è del tutto fondamentale la progettazione di un livello di sicurezza direttamente sulla base dati, con tanto di definizione di utenti e ruoli e con diversi livelli di autorizzazione/profilazione.
Molti di noi trovano che quest’ultima parte sia “inutile”, ma al contrario è fondamentale per la protezione delle proprie applicazioni. E’ un po come per i backup, è certamente inutile fare il backup, perchè richiede tempo e voglia, ma tutta l’utilità viene recuperata istantaneamente nel momento in cui perdiamo tutti o parte dei dati.

Il caso del Virus da SQL Injection

Un’errata programmazione delle applicazioni sul fronte della security ha consentito per esempio al virus o pseudo-virus di cui parlo adesso di creare ingenti danni a livello planetario. Il funzionamento del virus è molto banale, sfrutta la SQL Injection e fa delle chiamate HTTP o POST alle pagine modificando i valori dei parametri e inserendo un blocco di codice T-SQL opportunamente modificato e codificato in Base64 che una volta in esecuzione enumera tutte le colonne di tipo text,varchar,char e omologhi Unicode e va ad appendere al testo di ogni campo uno script Javascript che una volta renderizzato nella pagina Web a sua volta dovrebbe collegarsi in remoto e installare un ulteriore virus sulla macchina locale o comunque qualcosa di maligno che probabilmente aumenta la diffusione del fenomeno stesso su scala mondiale. Qui trovate un post su dove provengono gli attacchi a livello geografico:
Analisi geografica degli IP del virus da SQL Injection Attacks (Blog MVP David De Giacomi)

Il Virus in sè non causa gravi danni, se non il fatto che va a “sporcare” il database e nel caso dei campi text fa un CAST a varchar(4000) quindi tronca il testo e quindi vi fa perdere parte del contenuto del campo. Quindi in questo caso bisogna avere un backup a disposizione per recuperare i dati perduti.

Il meccanismo del Virus è ben spiegato in questo Bullettin:
SANS SQL Injection: More of the same

Tools per combattere il Virus SQL Injection su SQL Server

Dopo che il danno è stato fatto e non si riesce in breve tempo a fixare tutti i problemi e le falle di sicurezza bisogna cercare rapidamente di arginare il problema, ma in che modo ?
Per difendersi da questo pseudo-virus anche Microsoft ha dovuto rapidamente e/o aggiornare dei tools per i suoi clienti colpiti ripetutamente da questi attacchi.

Ripulitura del Database SQL Server
L’esecuzione di questo Virus “sporca” il database, riempiendo tutti i campi text,varchar,char e omologhi Unicode, con del codice HTML. La prima cosa da fare è restorare un backup recente oppure eseguire una ripulitura manuale del database ove possibile. La ripulitura può essere fatta riga per riga (se poche sono le righe/tabelle infettate) oppure semi-automatica, sfruttando la stessa tecnica del virus ma al contrario, con l’uso dei cursori, del Dynamic SQL e enumerando le colonne e le tabelle usando le tabelle di sistema (syscolumns e sysobjects) facendo dei REPLACE. Se non siete capaci di eseguire un’operazione del genere meglio farla fare ad altri perchè potreste creare più danni di quelli che già ci sono.

URLScan Filter 3.0 Beta
Questo tool consente di filtrare, limitare e bloccare certi tipi di HTTP Request che arrivano su IIS. Per installarlo e utilizzarlo è necessario avere il controllo del server su cui è ospitata la nostra soluzione. Nel caso di spazi shared hosting ciò non è possibile a meno chè il vostro Hoster provveda ad installarlo e a configurarlo per voi.

Download URL Scan Filter3.0 Beta

Istruzione per l’uso di URL Scan Filter

Microsoft Source Code Analyzer for SQL Injection
Un Tool per analizzare pagine .asp statiche e rilevare eventuali punti critici e vulnerabilità che possono compromettere la sicurezza e la stabilità dell’applicazione web. Stranamente pare che non analizzi pagine ASP.NET ma solo le vecchie ASP 3.0. Richiede installato sulla macchina il .NET Framework 3.0.

Se ne parla anche sul mio blog e su quello del collega MVP Lorenzo Benaglia:
Prova di Source Code Analyzer per SQL Injection (Blog MVP Alessandro Alpi)
Source Code Analyzer for SQL Injection (Blog MVP Lorenzo Benaglia)

Download URL Scan Filter3.0 Beta
Istruzione per l’uso di Source Code Analyzer for SQL Injection

Costruzione di un HttpModule che filtri le richieste HTTP
Se non avete accesso a IIS potete sempre costruirvi un HttpModule personalizzato in .NET che fa praticamente la stessa cosa dell’URLScan Filter 3.0 e lo potete deployare facilmente nella root della vostra applicazione web e abilitare. In questo modo eventuali richieste non conformi possono essere bloccate.

Costruzione di un HttpModule che blocchi a livello di IP
In questo caso questa tecnica non dà nessun risultato significativo, perchè il virus si distribuisce su vari client (attacco distribuito) nel mondo quindi gli attacchi possono provenire da blocchi di IP appartenenti a nazioni diverse, quindi si rischierebbe di tagliare fuori dal proprio sito anche ignari utenti che appartengono a un certo IP netblock bloccato. C’è da dire però che a seguito di un’analisi fatta sugli IP che effettuano gli attacchi si può desumere facilmente che questi provengono da stati non industrializzati ma emergenti dove probabilmente non c’è nessun tipo di legislazione in merito.

Qui trovate una dimostrazione del perchè una soluzione basata sul blocco degli IP potrebbe non essere efficiente per questo tipo di minaccia:
Analisi geografica degli IP del virus da SQL Injection Attacks (Blog MVP David De Giacomi)

Link Utili sulla sicurezza delle applicazioni e sul SQL Injection

Per finire vorrei indicare alcuni link utili a mio avviso da leggere se non si ha bene a mente come si scrive codice sicuro e quindi non violabile:

Creazione di codice di accesso ai dati protetto
Injection Protection
Preventing SQL Injections in ASP
How To: Protect From SQL Injection in ASP.NET
Coding techniques for protecting against Sql injection
Filtering SQL injection from Classic ASP
SQL Injection Attack

Un articolo del collega italiano MVP Raffaele Rialdi:
Una piaga chiamata SQL Injection

E per finire ancora da un collega MVP Erland Sommarskog un trattato sul Dynamic SQL molto interessante:
The Curse and Blessings of Dynamic SQL

Disclaimer

Tutte le tecniche mostrate in questo articolo sono a solo scopo didattico e tese a sensibilizzare Developers, WebMasters e DBA al tema della Security e a migliorare la loro conoscenza in questo ambito. Gli attacchi portati a termine dal Virus o manualmente da voi comportano comunque un danno per chi li riceve e nonostante il fatto che questi attacchi possano essere messi a segno su applicazioni non sicure o dove c’è qualche falla aperta a causa della scarsa competenza o disattenzione di chi le ha sviluppate, ciò non toglie che qualcuno potrebbe richiedervi un risarcimento danni, quindi prestate attenzione alle vostre azioni e magari evitate di ritrovarvi a dover risarcire il danno con gli sviluppatori incauti che hanno sviluppato l’applicazione. ;-)

Articolo tratto da http://www.dotnethell.it

Lascia un Commento