Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Proteggere un'applicazione significa anzitutto scrivere codice protetto. Il codice deve esporre solo le informazioni e le funzionalità indispensabili al codice client. Violazioni comuni riguardanti ADO.NET sono le intrusioni SQL e l'acquisizione di informazioni riservate sul database tramite le eccezioni restituite da un'applicazione.
Protezione dalle intrusioni SQL
Si definiscono intrusioni SQL le violazioni basate sull'aggiunta di ulteriori istruzioni SQL ai comandi che vengono eseguiti sull'origine dati. Tali comandi possono recuperare informazioni riservate così come modificare o distruggere le informazioni contenute nell'origine dati. Il codice è vulnerabile alle intrusioni SQL quando le stringhe di comando vengono concatenate con input esterno. Il codice riportato di seguito, ad esempio, è vulnerabile alle intrusioni SQL.
' Retrieve CustomerID to search for from external source.
Dim custID As String = GetCustomerID()
' The following line of code allows for SQL Insertion attack.
Dim selectString As String = "SELECT * FROM Customers WHERE CustomerID = " & custID
Dim cmd As SqlCommand = New SqlCommand(selectString, conn)
conn.Open()
Dim myReader As SqlDataReader = cmd.ExecuteReader()
' Process results.
myReader.Close()
conn.Close()
[C#]
// Retrieve CustomerID to search for from external source.
string custID = GetCustomerID();
// The following line of code allows for SQL Insertion attack.
string selectString = "SELECT * FROM Customers WHERE CustomerID = " + custID;
SqlCommand cmd = new SqlCommand(selectString, conn);
conn.Open();
SqlDataReader myReader = cmd.ExecuteReader();
' Process results.
myReader.Close();
conn.Close();
Un intruso potrebbe immettere "1;DROP TABLE Customers" come valore per CustomerID. In tal modo, la query da eseguire assumerebbe la seguente forma:
SELECT * FROM Customers WHERE CustomerID = 1;DROP TABLE Customers
Per proteggersi da intrusioni SQL, convalidare l'input ricevuto da fonti esterne e passare i valori dei campi come parametri anziché concatenare valori per creare un'istruzione SQL.
Convalida dell'input
Per verificare che l'input corrisponda a un determinato formato, è possibile utilizzare le espressioni regolari. Con .NET Framework viene fornito l'oggetto Regex che permette di convalidare un valore confrontandolo con un'espressione regolare. Con il codice riportato di seguito, ad esempio, è possibile verificare che il valore immesso sia una stringa alfanumerica di 5 caratteri.
Public Static Function Validate(inString As String) As Boolean
Dim r As Regex = New Regex("^[A-Za-z0-9]{5}$")
Return r.IsMatch(inString)
End Function
[C#]
public static bool Validate(string inString)
{
Regex r = new Regex("^[A-Za-z0-9]{5}$");
return r.IsMatch(inString)
}
Utilizzo dei parametri
L'uso dei parametri rappresenta una valida soluzione al problema di organizzare i valori passati con un'istruzione SQL o a una stored procedure. Con l'uso dei parametri si pone inoltre un argine alle intrusioni SQL in quanto si è certi che i valori ricevuti da una fonte esterna verranno passati come semplici valori e non come parte di un'istruzione SQL. I comandi SQL inseriti in un valore non verranno pertanto eseguiti sull'origine dati. I valori passati vengono infatti trattati come semplici valori di parametro. Nel codice che segue viene mostrato come utilizzare un parametro per passare un valore.
' Retrieve CustomerID to search for from external source.
Dim custID As String = GetCustomerID()
Dim selectString As String = "SELECT * FROM Customers WHERE CustomerID = @CustomerID"
Dim cmd As SqlCommand = New SqlCommand(selectString, conn)
cmd.Parameters.Add("@CustomerID", SqlDbType.VarChar, 5).Value = custID
conn.Open()
Dim myReader As SqlDataReader = cmd.ExecuteReader()
' Process results.
myReader.Close()
conn.Close()
[C#]
// Retrieve CustomerID to search for from external source.
string custID = GetCustomerID();
string selectString = "SELECT * FROM Customers WHERE CustomerID = @CustomerID";
SqlCommand cmd = new SqlCommand(selectString, conn);
cmd.Parameters.Add("@CustomerID", SqlDbType.VarChar, 5).Value = custID;
conn.Open();
SqlDataReader myReader = cmd.ExecuteReader();
' Process results.
myReader.Close();
conn.Close();
Segretezza delle informazioni riguardanti le eccezioni
Gli intrusi utilizzano spesso informazioni carpite da un'eccezione, quali un nome di server, database o tabella per condurre attacchi specifici al sistema. Poiché le eccezioni possono presentare informazioni specifiche sull'applicazione o sull'origine dati, è possibile conferire all'applicazione e ai dati una maggior protezione esponendo al client solo le informazioni necessarie.
Per evitare di esporre informazioni riservate tramite le eccezioni, non restituire il contenuto di un'eccezione di sistema all'utente. Gestire invece l'eccezione internamente. Se occorre inviare un messaggio all'utente, utilizzare un messaggio personalizzato contenente solo informazioni essenziali quali "Connessione non riuscita. Rivolgersi all'amministratore di sistema." e memorizzare l'informazione specifica, che potrà essere poi consultata da un amministratore.
Il codice che segue, ad esempio, intercetta le eccezioni che si verificano all'apertura di una connessione e le trascrive nel log eventi.
Dim conn As SqlConnection = New SqlConnection("Data Source=localhost;Initial Catalog=Northwind;")
Try
conn.Open()
Catch e As SqlException
Dim log As System.Diagnostics.EventLog = New System.Diagnostics.EventLog()
log.Source = "My Application"
log.WriteEntry(e.ToString())
If conn.State <> ConnectionState.Open Then _
Console.WriteLine("Connection was not opened.")
Finally
conn.Close()
End Try
[C#]
SqlConnection conn = new SqlConnection("Data Source=localhost;Initial Catalog=Northwind;");
try
{
conn.Open();
}
catch (SqlException e)
{
System.Diagnostics.EventLog log = new System.Diagnostics.EventLog();
log.Source = "My Application";
log.WriteEntry(e.ToString());
if (conn.State != ConnectionState.Open)
Console.WriteLine("Connection was not opened.");
}
finally
{
conn.Close();
}