Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
| Свойство | Значение |
|---|---|
| Идентификатор правила | CA2100 |
| Заголовок | Проверьте запросы SQL на наличие уязвимостей системы безопасности |
| Категория | Безопасность |
| Исправление является разрушающим или неразрушающим | Неразрывный |
| Включен по умолчанию в .NET 10 | Нет |
| Применимые языки | C# и Visual Basic |
Причина
Метод задает свойство System.Data.IDbCommand.CommandText с помощью строки, которая создается из строкового аргумента, переданного в метод.
По умолчанию это правило анализирует всю базу кода, но такое поведение можно настроить.
Описание правила
Это правило предполагает, что любая строка, значение которой невозможно определить во время компиляции, может содержать входные данные пользователя. Командная строка SQL, созданная из ввода пользователем, уязвима для атак внедрения SQL. При атаке путем внедрения кода SQL злоумышленник предоставляет входные данные, которые изменяют структуру запроса при попытке нанести вред или получить несанкционированный доступ к основной базе данных. Типичные методы включают в себя введение одинарной кавычки или апострофа, которые являются разделителями строк в SQL литералах; двух тире, обозначающих комментарий SQL; и точки с запятой, которая указывает на новую команду. Если входные данные пользователя должны быть частью запроса, используйте один из следующих методов, перечисленных в порядке эффективности, чтобы снизить риск атаки.
- Используйте хранимую процедуру.
- Использование параметризованной командной строки.
- Проверка данных, введенных пользователем, на предмет типа и содержимого перед сборкой командной строки.
Следующие типы .NET реализуют CommandText свойство или предоставляют конструкторы, которые задают свойство с помощью строкового аргумента:
- System.Data.Odbc.OdbcCommand и System.Data.Odbc.OdbcDataAdapter
- System.Data.OleDb.OleDbCommand и System.Data.OleDb.OleDbDataAdapter
- System.Data.OracleClient.OracleCommand и System.Data.OracleClient.OracleDataAdapter
- System.Data.SqlClient.SqlCommand и System.Data.SqlClient.SqlDataAdapter
В некоторых случаях это правило может не определять значение строки во время компиляции, даже если это возможно. В этих случаях это правило создает ложноположительный результат при использовании этих строк в качестве команд SQL. Ниже приводится пример подобной строки.
int x = 10;
string query = "SELECT TOP " + x.ToString() + " FROM Table";
То же самое применяется при неявном использовании ToString().
int x = 10;
string query = String.Format("SELECT TOP {0} FROM Table", x);
Устранение нарушений
Чтобы устранить нарушение этого правила, используйте параметризованный запрос.
Когда лучше отключить предупреждения
Подавление предупреждения в этом правиле безопасно, если текст команды не содержит входных данных пользователя.
Отключение предупреждений
Если вы просто хотите отключить одно нарушение, добавьте директивы препроцессора в исходный файл, чтобы отключить и повторно включить правило.
#pragma warning disable CA2100
// The code that's violating the rule is on this line.
#pragma warning restore CA2100
Чтобы отключить правило для файла, папки или проекта, задайте его серьезность none в файле конфигурации.
[*.{cs,vb}]
dotnet_diagnostic.CA2100.severity = none
Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.
Настройка кода для анализа
Используйте следующие параметры, чтобы указать части базы кода, к которым будет применяться это правило.
Кроме того, к этому правилу применяются следующие параметры анализа потока данных:
- вид межпроцедурного анализа
- max_interprocedural_lambda_or_local_function_call_chain
- макс_межпроцедурная_цепочка_вызовов_методов
- тип_анализа_указателей
- copy_analysis
- sufficient_IterationCount_for_weak_KDF_algorithm
Эти параметры можно настроить только для этого правила, для всех правил, к которым они применяются, или для всех правил в этой категории (безопасности), к которым они применяются. Дополнительные сведения см. в статье Параметры конфигурации правила качества кода.
Исключение определенных символов
Вы можете исключить определенные символы, такие как типы и методы, из анализа, задав параметр excluded_symbol_names. Например, чтобы указать, что правило не должно выполняться для какого-либо кода в типах с именем MyType, добавьте следующую пару "ключ-значение" в файл EDITORCONFIG в своем проекте:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Заметка
Замените XXXX частью CAXXXX идентификатором применимого правила.
Допустимые форматы имени символа в значении параметра (разделенные |):
- Только имя символа (включает все символы с данным именем, вне зависимости от типа и пространства имен).
- Полные имена в формате идентификатора документации для символа. Для каждого имени символа требуется префикс в виде символа, например
M:для методов,T:для типов иN:для пространств имен. -
.ctorиспользуется для конструкторов, а.cctor— для статических конструкторов.
Примеры:
| Значение опции | Итоги |
|---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Соответствует всем символам с именем MyType. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Соответствует всем символам с именем MyType1 или MyType2. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Определяет соответствие конкретного метода MyMethod с заданной полной сигнатурой. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Сопоставляет конкретные методы MyMethod1 и MyMethod2 с соответствующими полными квалифицированными сигнатурами. |
Исключить определенные типы и их производные типы
Вы можете исключить определенные типы и производные типы из анализа, задав параметр excluded_type_names_with_derived_types. Например, чтобы указать, что правило не должно выполняться в каких-либо методах типов MyType и их производных типов, добавьте следующую пару "ключ-значение" в файл .editorconfig своего проекта:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Заметка
Замените XXXX частью CAXXXX идентификатором применимого правила.
Допустимые форматы имени символа в значении параметра (разделенные |):
- Только имя типа (включает все типы с этим именем, независимо от содержащего типа или пространства имен).
- полные имена символов в формате идентификатора документации с необязательным префиксом
T:.
Примеры:
| Значение параметра выбора | Итоги |
|---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Соответствует всем типам с именем MyType и всем их производным типам. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Соответствует всем типам с именем MyType1 или MyType2 и всем их производным типам. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Соответствует конкретному типу MyType с заданным полным именем и всем производным от него типам. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Соответствует конкретным типам MyType1 и MyType2 с их соответствующими полными именами и всеми производными от них типами. |
Пример
В следующем примере показан метод, UnsafeQueryкоторый нарушает правило. В нем также показан метод, SaferQueryкоторый удовлетворяет правилу с помощью параметризованной командной строки.
Imports System.Data
Imports System.Data.OleDb
Imports System.Runtime.Versioning
Namespace ca2100
Public Class SqlQueries
<SupportedOSPlatform("windows")>
Function UnsafeQuery(connection As String,
name As String, password As String) As Object
Dim someConnection As New OleDbConnection(connection)
Dim someCommand As New OleDbCommand With {
.Connection = someConnection,
.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
<SupportedOSPlatform("windows")>
Function SaferQuery(connection As String,
name As String, password As String) As Object
Dim someConnection As New OleDbConnection(connection)
Dim someCommand As New OleDbCommand With {
.Connection = someConnection
}
someCommand.Parameters.AddWithValue(
"@username", OleDbType.Char).Value = name
someCommand.Parameters.AddWithValue(
"@password", OleDbType.Char).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
<SupportedOSPlatform("windows")>
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
[SupportedOSPlatform("Windows")]
public class OleDbQueries
{
public object UnsafeQuery(
string connection, string name, string password)
{
using OleDbConnection someConnection = new(connection);
using OleDbCommand someCommand = new();
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)
{
using OleDbConnection someConnection = new(connection);
using OleDbCommand someCommand = new();
someCommand.Connection = someConnection;
someCommand.Parameters.Add(
"@username", OleDbType.Char).Value = name;
someCommand.Parameters.Add(
"@password", OleDbType.Char).Value = password;
someCommand.CommandText = "SELECT AccountNumber FROM Users " +
"WHERE Username=@username AND Password=@password";
someConnection.Open();
object accountNumber = someCommand.ExecuteScalar();
someConnection.Close();
return accountNumber;
}
}
[SupportedOSPlatform("Windows")]
class MaliciousCode
{
static void Main2100(string[] args)
{
OleDbQueries queries = new();
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]'
}
}
Внимание
Корпорация Майкрософт рекомендует использовать самый безопасный поток проверки подлинности. Если вы подключаетесь к Azure SQL, Управляемые удостоверения для ресурсов Azure — это рекомендуемый метод проверки подлинности.