CA2100: SQL-Abfragen auf Sicherheitsrisiken überprüfen.
Eigenschaft | Wert |
---|---|
Regel-ID | CA2100 |
Titel | SQL-Abfragen auf Sicherheitsrisiken überprüfen. |
Kategorie | Security |
Fix führt oder führt nicht zur Unterbrechung | Nicht unterbrechend |
Standardmäßig in .NET 9 aktiviert | No |
Ursache
Eine Methode legt die System.Data.IDbCommand.CommandText Eigenschaft mithilfe einer Zeichenfolge fest, die von einem Zeichenfolgenargument auf die Methode basiert.
Standardmäßig analysiert diese Regel die gesamte Codebasis, aber dieses Verhalten ist konfigurierbar.
Regelbeschreibung
Bei dieser Regel wird davon ausgegangen, dass jede Zeichenfolge, deren Wert zur Kompilierungszeit nicht bestimmt werden kann, Benutzereingaben enthalten kann. Eine SQL-Befehlszeichenfolge, die aus der Benutzereingabe erstellt wird, ist anfällig für SQL-Einfügungsangriffe. Bei einem Angriff durch Einschleusung von SQL-Befehlen liefert ein böswilliger Benutzer Eingaben, die den Entwurf einer Abfrage verändern, um die zugrunde liegende Datenbank zu beschädigen oder ohne Autorisierung darauf zuzugreifen. Typische Techniken sind die Einschleusung eines einfachen Anführungszeichens oder Apostrophs, bei dem es sich um das SQL-Trennzeichen für Literalzeichenfolgen handelt, zwei Bindestriche, die für einen SQL-Kommentar stehen, und ein Semikolon, das angibt, dass ein neuer Befehl folgt. Wenn Benutzereingaben Teil der Abfrage sein müssen, verwenden Sie eine der folgenden (nach Effektivität aufgeführt), um das Risiko von Angriffen zu verringern.
- Gespeicherte Prozedur verwenden.
- Eine parametrisierte Befehlszeichenfolge verwenden
- Die Benutzereingaben auf Typ und Inhalt überprüfen, bevor Sie die Befehlszeichenfolge erstellen
Die folgenden .NET-Typen implementieren die Eigenschaft CommandText oder stellen Konstruktoren bereit, mit denen die Eigenschaft mithilfe eines Zeichenfolgenarguments festgelegt wird.
- System.Data.Odbc.OdbcCommand und System.Data.Odbc.OdbcDataAdapter
- System.Data.OleDb.OleDbCommand und System.Data.OleDb.OleDbDataAdapter
- System.Data.OracleClient.OracleCommand und System.Data.OracleClient.OracleDataAdapter
- System.Data.SqlClient.SqlCommand und System.Data.SqlClient.SqlDataAdapter
In einigen Fällen bestimmt diese Regel möglicherweise nicht den Wert einer Zeichenfolge zur Kompilierzeit, auch wenn dies möglich ist. In diesen Fällen liefert diese Regel falsch positive Ergebnisse, wenn diese Zeichenfolgen als SQL-Befehle verwendet werden. Das folgende Beispiel zeigt eine solche Zeichenfolge.
int x = 10;
string query = "SELECT TOP " + x.ToString() + " FROM Table";
Dasselbe gilt, wenn ToString()
implizit verwendet wird.
int x = 10;
string query = String.Format("SELECT TOP {0} FROM Table", x);
Behandeln von Verstößen
Verwenden Sie eine parametrisierte Abfrage, um einen Verstoß gegen diese Regel zu korrigieren.
Wann sollten Warnungen unterdrückt werden?
Sie können eine Warnung dieser Regel unterdrücken, wenn der Befehlstext keine Benutzereingaben enthält.
Unterdrücken einer Warnung
Um nur eine einzelne Verletzung zu unterdrücken, fügen Sie der Quelldatei Präprozessoranweisungen hinzu, um die Regel zu deaktivieren und dann wieder zu aktivieren.
#pragma warning disable CA2100
// The code that's violating the rule is on this line.
#pragma warning restore CA2100
Um die Regel für eine Datei, einen Ordner oder ein Projekt zu deaktivieren, legen Sie den Schweregrad in der Konfigurationsdatei auf none
fest.
[*.{cs,vb}]
dotnet_diagnostic.CA2100.severity = none
Weitere Informationen finden Sie unter Vorgehensweise: Unterdrücken von Codeanalyse-Warnungen.
Konfigurieren des zu analysierenden Codes
Mithilfe der folgenden Optionen können Sie konfigurieren, für welche Teile Ihrer Codebasis diese Regel ausgeführt werden soll.
Sie können diese Optionen nur für diese Regel, für alle zutreffenden Regeln oder für alle zutreffenden Regeln in dieser Kategorie (Sicherheit) konfigurieren. Weitere Informationen finden Sie unter Konfigurationsoptionen für die Codequalitätsregel.
Ausschließen bestimmter Symbole
Sie können bestimmte Symbole, z. B. Typen und Methoden, von der Analyse ausschließen. Sie können beispielsweise festlegen, dass die Regel nicht für Code innerhalb von Typen namens MyType
ausgeführt werden soll, indem Sie einer EDITORCONFIG-Datei in Ihrem Projekt das folgende Schlüssel-Wert-Paar hinzufügen:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Zulässige Formate für Symbolnamen im Optionswert (durch |
getrennt):
- Nur Symbolname (schließt alle Symbole mit dem Namen ein, unabhängig vom enthaltenden Typ oder Namespace)
- Vollqualifizierte Namen im Format der Dokumentations-ID des Symbols Jeder Symbolname erfordert ein Symbolartpräfix, z. B.
M:
für Methoden,T:
für Typen undN:
für Namespaces. .ctor
für Konstruktoren und.cctor
für statische Konstruktoren
Beispiele:
Optionswert | Zusammenfassung |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Trifft auf alle Symbole namens MyType zu |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Trifft auf alle Symbole namens MyType1 oder MyType2 zu |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Trifft speziell auf die Methode MyMethod mit der angegebenen vollqualifizierten Signatur zu |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Trifft speziell auf die Methoden MyMethod1 und MyMethod2 mit den jeweiligen vollqualifizierten Signaturen zu |
Ausschließen bestimmter Typen und von diesen abgeleiteten Typen
Sie können bestimmte Typen und von diesen abgeleitete Typen aus der Analyse ausschließen. Wenn Sie z. B. festlegen möchten, dass die Regel nicht für Methoden innerhalb von MyType
-Typen und von diesen abgeleiteten Typen ausgeführt werden soll, fügen Sie einer EDITORCONFIG-Datei in Ihrem Projekt das folgende Schlüssel-Wert-Paar hinzu:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Zulässige Formate für Symbolnamen im Optionswert (durch |
getrennt):
- Nur Typname (schließt alle Typen mit dem Namen ein, unabhängig vom enthaltenden Typ oder Namespace)
- Vollqualifizierte Namen im Dokumentations-ID-Format des Symbols mit einem optionalen Präfix
T:
Beispiele:
Optionswert | Zusammenfassung |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Stimmt mit allen MyType -Typen und allen von diesen abgeleiteten Typen überein. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Stimmt mit allen MyType1 - oder MyType2 -Typen und allen von diesen abgeleiteten Typen überein. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Stimmt mit einem bestimmten MyType -Typ mit einem angegebenen vollqualifizierten Namen und allen von diesem abgeleiteten Typen überein. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Stimmt mit bestimmten MyType1 - und MyType2 -Typen mit den entsprechenden vollqualifizierten Namen und allen von diesen abgeleiteten Typen überein. |
Beispiel
Das folgende Beispiel zeigt eine Methode, UnsafeQuery
die gegen die Regel verstößt. Außerdem wird eine Methode angezeigt, SaferQuery
die die Regel mithilfe einer parametrisierten Befehlszeichenfolge erfüllt.
Imports System
Imports System.Data
Imports System.Data.SqlClient
Namespace ca2100
Public Class SqlQueries
Function UnsafeQuery(connection As String,
name As String, password As String) As Object
Dim someConnection As New SqlConnection(connection)
Dim someCommand As New SqlCommand()
someCommand.Connection = someConnection
someCommand.CommandText = "SELECT AccountNumber FROM Users " &
"WHERE Username='" & name & "' AND Password='" & password & "'"
someConnection.Open()
Dim accountNumber As Object = someCommand.ExecuteScalar()
someConnection.Close()
Return accountNumber
End Function
Function SaferQuery(connection As String,
name As String, password As String) As Object
Dim someConnection As New SqlConnection(connection)
Dim someCommand As New SqlCommand()
someCommand.Connection = someConnection
someCommand.Parameters.Add(
"@username", SqlDbType.NChar).Value = name
someCommand.Parameters.Add(
"@password", SqlDbType.NChar).Value = password
someCommand.CommandText = "SELECT AccountNumber FROM Users " &
"WHERE Username=@username AND Password=@password"
someConnection.Open()
Dim accountNumber As Object = someCommand.ExecuteScalar()
someConnection.Close()
Return accountNumber
End Function
End Class
Class MaliciousCode
Shared Sub Main2100(args As String())
Dim queries As New SqlQueries()
queries.UnsafeQuery(args(0), "' OR 1=1 --", "[PLACEHOLDER]")
' Resultant query (which is always true):
' SELECT AccountNumber FROM Users WHERE Username='' OR 1=1
queries.SaferQuery(args(0), "' OR 1=1 --", "[PLACEHOLDER]")
' Resultant query (notice the additional single quote character):
' SELECT AccountNumber FROM Users WHERE Username=''' OR 1=1 --'
' AND Password='[PLACEHOLDER]'
End Sub
End Class
End Namespace
public class SqlQueries
{
public object UnsafeQuery(
string connection, string name, string password)
{
SqlConnection someConnection = new SqlConnection(connection);
SqlCommand someCommand = new SqlCommand();
someCommand.Connection = someConnection;
someCommand.CommandText = "SELECT AccountNumber FROM Users " +
"WHERE Username='" + name +
"' AND Password='" + password + "'";
someConnection.Open();
object accountNumber = someCommand.ExecuteScalar();
someConnection.Close();
return accountNumber;
}
public object SaferQuery(
string connection, string name, string password)
{
SqlConnection someConnection = new SqlConnection(connection);
SqlCommand someCommand = new SqlCommand();
someCommand.Connection = someConnection;
someCommand.Parameters.Add(
"@username", SqlDbType.NChar).Value = name;
someCommand.Parameters.Add(
"@password", SqlDbType.NChar).Value = password;
someCommand.CommandText = "SELECT AccountNumber FROM Users " +
"WHERE Username=@username AND Password=@password";
someConnection.Open();
object accountNumber = someCommand.ExecuteScalar();
someConnection.Close();
return accountNumber;
}
}
class MaliciousCode
{
static void Main2100(string[] args)
{
SqlQueries queries = new SqlQueries();
queries.UnsafeQuery(args[0], "' OR 1=1 --", "[PLACEHOLDER]");
// Resultant query (which is always true):
// SELECT AccountNumber FROM Users WHERE Username='' OR 1=1
queries.SaferQuery(args[0], "' OR 1=1 --", "[PLACEHOLDER]");
// Resultant query (notice the additional single quote character):
// SELECT AccountNumber FROM Users WHERE Username=''' OR 1=1 --'
// AND Password='[PLACEHOLDER]'
}
}
Wichtig
Microsoft empfiehlt, immer den sichersten Authentifizierungsflow zu verwenden. Wenn Sie eine Verbindung mit Azure SQL herstellen, ist Managed Identities for Azure Resources die empfohlene Authentifizierungsmethode.