Freigeben über


Richtlinien für das Schreiben von sicherem ADO.NET-Code

Das Sichern von Anwendungen umfasst das Schreiben von sicherem Code. Code darf lediglich Informationen und Funktionen offen legen, die vom Clientcode benötigt werden. Übliche Angriffe in Verbindung mit ADO.NET sind SQL-Einfügeangriffe und das Ermitteln geheimer Datenbankinformationen unter Ausnutzung der von der Anwendung zurückgegebenen Ausnahmen.

Vermeiden von SQL-Einfügeangriffen

Bei einem SQL-Einfügeangriff fügt ein Angreifer zusätzliche SQL-Anweisungen in Befehle ein, die in der Datenquelle verarbeitet werden. Mit diesen Befehlen können vertrauliche Informationen abgerufen sowie in der Datenquelle enthaltene Informationen geändert bzw. zerstört werden. Code ist für einen SQL-Einfügeangriff anfällig, wenn Befehlszeichenfolgen mit externen Eingaben verkettet werden. Der folgende Code ist beispielsweise anfällig für SQL-Einfügeangriffe.

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

Ein Angreifer kann z. B. den Wert "1;DROP TABLE Customers" für die abzufragende CustomerID eingeben. In diesem Fall wird der folgende Befehl für die Abfrage ausgeführt.

SELECT * FROM Customers WHERE CustomerID = 1;DROP TABLE Customers

Sie können sich gegen SQL-Einfügeangriffe schützen, indem Sie Eingaben aus externen Quellen überprüfen und Spaltenwerte als Parameter weiterleiten, anstatt Werte zum Erstellen einer SQL-Anweisung zu verketten.

Überprüfen der Eingabe

Wenn Sie die Übereinstimmung der Eingabe mit einem bestimmten Format überprüfen möchten, können Sie reguläre Ausdrücke verwenden. .NET Framework stellt das Regex-Objekt zum Überprüfen eines Wertes mit einem regulären Ausdruck zur Verfügung. Mit dem folgenden Code kann z. B. sichergestellt werden, dass der Wert für eine Benutzer-ID aus einer alphanumerischen Zeichenfolge mit fünf Zeichen besteht.

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

Verwenden von Parametern

Parameter stellen eine geeignete Methode zum Organisieren von Werten dar, die mit einer SQL-Anweisung weitergeleitet bzw. an eine gespeicherte Prozedur übergeben werden. Darüber hinaus bietet die Verwendung von Parametern Schutz gegen einen SQL-Einfügeangriff, da sichergestellt ist, dass Werte aus einer externen Quelle lediglich als Werte und nicht als Bestandteil einer SQL-Anweisung weitergeleitet werden. In einen Wert eingefügte SQL-Befehle werden daher nicht an der Datenquelle ausgeführt. Die weitergeleiteten Werte werden stattdessen nur als Parameterwert verarbeitet. Das folgende Codebeispiel veranschaulicht die Verwendung eines Parameters zum Weiterleiten eines Wertes.

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

Schützen von Ausnahmeinformationen

Für eine bestimmte Art von Angriffen auf ein System verwenden Angreifer häufig Informationen aus einer Ausnahme, z. B. den Namen eines Servers, einer Datenbank oder Tabelle. Da Ausnahmen spezifische Informationen über eine Anwendung bzw. Datenquelle enthalten können, können Sie Ihre Anwendung bzw. Datenquelle besser schützen, indem Sie lediglich Informationen zur Verfügung stellen, die vom Client explizit angefordert werden.

Vermeiden Sie das Offenlegen privater Informationen durch Ausnahmen, indem Sie den Inhalt von Systemausnahmen nicht an Benutzer zurückgeben. Verarbeiten Sie die Ausnahme stattdessen intern. Verwenden Sie für erforderliche Nachrichten an Benutzer eigene benutzerdefinierte Meldungen mit minimalen Informationen (z. B. "Die Verbindung ist fehlgeschlagen. Wenden Sie sich an den Systemadministrator."), und protokollieren Sie die jeweiligen Informationen für den Administrator.

Mit dem folgenden Beispielcode werden Ausnahmen beim Öffnen einer Verbindung ermittelt und in das Ereignisprotokoll geschrieben.

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

Siehe auch

Schreiben von sicherem ADO.NET-Code