CA3001: Przegląd kodu pod kątem luk w zabezpieczeniach polegających na wstrzyknięciu kodu SQL
Właściwości | Wartość |
---|---|
Identyfikator reguły | CA3001 |
Tytuł | Przegląd kodu pod kątem luk umożliwiających wstrzyknięcie kodu SQL |
Kategoria | Bezpieczeństwo |
Poprawka powodująca niezgodność lub niezgodność | Niezgodność |
Domyślnie włączone na platformie .NET 9 | Nie. |
Przyczyna
Potencjalnie niezaufane dane wejściowe żądania HTTP docierają do tekstu polecenia SQL.
Domyślnie ta reguła analizuje całą bazę kodu, ale można to skonfigurować.
Opis reguły
Podczas pracy z niezaufanymi poleceniami wejściowymi i sql należy pamiętać o atakach polegających na wstrzyknięciu kodu SQL. Atak polegający na wstrzyknięciu kodu SQL może wykonywać złośliwe polecenia SQL, co narusza bezpieczeństwo i integralność aplikacji. Typowe techniki obejmują użycie pojedynczego cudzysłowu lub apostrofu do rozdzielania ciągów literału, dwóch kreski dla komentarza i średnika na końcu instrukcji. Aby uzyskać więcej informacji, zobacz Iniekcja SQL.
Ta reguła próbuje znaleźć dane wejściowe z żądań HTTP docierających do tekstu polecenia SQL.
Uwaga
Ta reguła nie może śledzić danych między zestawami. Jeśli na przykład jeden zestaw odczytuje dane wejściowe żądania HTTP, a następnie przekazuje go do innego zestawu, który wykonuje polecenie SQL, ta reguła nie generuje ostrzeżenia.
Uwaga
Istnieje konfigurowalny limit sposobu, w jaki ta reguła będzie analizować przepływ danych między wywołaniami metod. Zobacz Konfiguracja analizatora, aby dowiedzieć się, jak skonfigurować limit w pliku EditorConfig.
Jak naprawić naruszenia
Użyj sparametryzowanych poleceń SQL lub procedur składowanych z parametrami zawierającymi niezaufane dane wejściowe.
Kiedy pomijać ostrzeżenia
Można bezpiecznie pominąć ostrzeżenie z tej reguły, jeśli wiesz, że dane wejściowe są zawsze weryfikowane względem znanego bezpiecznego zestawu znaków.
Pomijanie ostrzeżenia
Jeśli chcesz po prostu pominąć pojedyncze naruszenie, dodaj dyrektywy preprocesora do pliku źródłowego, aby wyłączyć, a następnie ponownie włączyć regułę.
#pragma warning disable CA3001
// The code that's violating the rule is on this line.
#pragma warning restore CA3001
Aby wyłączyć regułę dla pliku, folderu lub projektu, ustaw jego ważność na none
w pliku konfiguracji.
[*.{cs,vb}]
dotnet_diagnostic.CA3001.severity = none
Aby uzyskać więcej informacji, zobacz Jak pominąć ostrzeżenia dotyczące analizy kodu.
Konfigurowanie kodu do analizowania
Użyj poniższych opcji, aby skonfigurować, które części bazy kodu mają być uruchamiane w tej regule.
Możesz skonfigurować te opcje tylko dla tej reguły, dla wszystkich reguł, do których ma ona zastosowanie, lub dla wszystkich reguł w tej kategorii (Zabezpieczenia), których dotyczy. Aby uzyskać więcej informacji, zobacz Opcje konfiguracji reguły jakości kodu.
Wykluczanie określonych symboli
Z analizy można wykluczyć określone symbole, takie jak typy i metody. Aby na przykład określić, że reguła nie powinna być uruchamiana w żadnym kodzie w typach o nazwie MyType
, dodaj następującą parę klucz-wartość do pliku editorconfig w projekcie:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Dozwolone formaty nazw symboli w wartości opcji (oddzielone przez |
):
- Tylko nazwa symbolu (zawiera wszystkie symbole o nazwie, niezależnie od typu zawierającego lub przestrzeni nazw).
- W pełni kwalifikowane nazwy w formacie identyfikatora dokumentacji symbolu. Każda nazwa symboli wymaga prefiksu typu symboli, takiego jak
M:
metody,T:
dla typów iN:
przestrzeni nazw. .ctor
dla konstruktorów i.cctor
konstruktorów statycznych.
Przykłady:
Wartość opcji | Podsumowanie |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Pasuje do wszystkich symboli o nazwie MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Pasuje do wszystkich symboli o nazwie MyType1 lub MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Pasuje do określonej metody MyMethod z określonym w pełni kwalifikowanym podpisem. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Pasuje do określonych metod MyMethod1 i MyMethod2 z odpowiednimi w pełni kwalifikowanymi podpisami. |
Wykluczanie określonych typów i ich typów pochodnych
Z analizy można wykluczyć określone typy i ich typy pochodne. Aby na przykład określić, że reguła nie powinna być uruchamiana na żadnych metodach w typach nazwanych MyType
i ich typach pochodnych, dodaj następującą parę klucz-wartość do pliku .editorconfig w projekcie:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Dozwolone formaty nazw symboli w wartości opcji (oddzielone przez |
):
- Nazwa typu (zawiera tylko wszystkie typy o nazwie, niezależnie od typu zawierającego lub przestrzeni nazw).
- W pełni kwalifikowane nazwy w formacie identyfikatora dokumentacji symbolu z opcjonalnym
T:
prefiksem.
Przykłady:
Wartość opcji | Podsumowanie |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Pasuje do wszystkich typów nazwanych MyType i wszystkich ich typów pochodnych. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Dopasuje wszystkie typy o nazwie MyType1 lub MyType2 i wszystkie ich typy pochodne. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Pasuje do określonego typu MyType z daną w pełni kwalifikowaną nazwą i wszystkimi jego typami pochodnymi. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Pasuje do określonych typów MyType1 i MyType2 z odpowiednimi w pełni kwalifikowanymi nazwami i wszystkimi ich typami pochodnymi. |
Przykłady przykładów kodu przykładowego
Naruszenie
using System;
using System.Data;
using System.Data.SqlClient;
namespace TestNamespace
{
public partial class WebForm : System.Web.UI.Page
{
public static string ConnectionString { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
string name = Request.Form["product_name"];
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
SqlCommand sqlCommand = new SqlCommand()
{
CommandText = "SELECT ProductId FROM Products WHERE ProductName = '" + name + "'",
CommandType = CommandType.Text,
};
SqlDataReader reader = sqlCommand.ExecuteReader();
}
}
}
}
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Linq
Namespace VulnerableWebApp
Partial Public Class WebForm
Inherits System.Web.UI.Page
Public Property ConnectionString As String
Protected Sub Page_Load(sender As Object, e As EventArgs)
Dim name As String = Me.Request.Form("product_name")
Using connection As SqlConnection = New SqlConnection(ConnectionString)
Dim sqlCommand As SqlCommand = New SqlCommand With {.CommandText = "SELECT ProductId FROM Products WHERE ProductName = '" + name + "'",
.CommandType = CommandType.Text}
Dim reader As SqlDataReader = sqlCommand.ExecuteReader()
End Using
End Sub
End Class
End Namespace
Rozwiązanie sparametryzowane
using System;
using System.Data;
using System.Data.SqlClient;
namespace TestNamespace
{
public partial class WebForm : System.Web.UI.Page
{
public static string ConnectionString { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
string name = Request.Form["product_name"];
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
SqlCommand sqlCommand = new SqlCommand()
{
CommandText = "SELECT ProductId FROM Products WHERE ProductName = @productName",
CommandType = CommandType.Text,
};
sqlCommand.Parameters.Add("@productName", SqlDbType.NVarChar, 128).Value = name;
SqlDataReader reader = sqlCommand.ExecuteReader();
}
}
}
}
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Linq
Namespace VulnerableWebApp
Partial Public Class WebForm
Inherits System.Web.UI.Page
Public Property ConnectionString As String
Protected Sub Page_Load(sender As Object, e As EventArgs)
Dim name As String = Me.Request.Form("product_name")
Using connection As SqlConnection = New SqlConnection(ConnectionString)
Dim sqlCommand As SqlCommand = New SqlCommand With {.CommandText = "SELECT ProductId FROM Products WHERE ProductName = @productName",
.CommandType = CommandType.Text}
sqlCommand.Parameters.Add("@productName", SqlDbType.NVarChar, 128).Value = name
Dim reader As SqlDataReader = sqlCommand.ExecuteReader()
End Using
End Sub
End Class
End Namespace
Rozwiązanie procedury składowanej
using System;
using System.Data;
using System.Data.SqlClient;
namespace TestNamespace
{
public partial class WebForm : System.Web.UI.Page
{
public static string ConnectionString { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
string name = Request.Form["product_name"];
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
SqlCommand sqlCommand = new SqlCommand()
{
CommandText = "sp_GetProductIdFromName",
CommandType = CommandType.StoredProcedure,
};
sqlCommand.Parameters.Add("@productName", SqlDbType.NVarChar, 128).Value = name;
SqlDataReader reader = sqlCommand.ExecuteReader();
}
}
}
}
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Linq
Namespace VulnerableWebApp
Partial Public Class WebForm
Inherits System.Web.UI.Page
Public Property ConnectionString As String
Protected Sub Page_Load(sender As Object, e As EventArgs)
Dim name As String = Me.Request.Form("product_name")
Using connection As SqlConnection = New SqlConnection(ConnectionString)
Dim sqlCommand As SqlCommand = New SqlCommand With {.CommandText = "sp_GetProductIdFromName",
.CommandType = CommandType.StoredProcedure}
sqlCommand.Parameters.Add("@productName", SqlDbType.NVarChar, 128).Value = name
Dim reader As SqlDataReader = sqlCommand.ExecuteReader()
End Using
End Sub
End Class
End Namespace