CA3001: Examinar código quanto a vulnerabilidades de injeção de SQL
Property | Valor |
---|---|
ID da regra | CA3001 |
Título | Examinar código quanto a vulnerabilidades de injeção de SQL |
Categoria | Segurança |
Correção interruptiva ou sem interrupção | Sem interrupção |
Habilitado por padrão no .NET 8 | Não |
Causa
A entrada de solicitação HTTP potencialmente não confiável atinge uma instrução LDAP.
Por padrão, essa regra analisa toda a base de código, mas isso é configurável.
Descrição da regra
Ao trabalhar com comandos SQL e de entrada não confiáveis, tenha atenção quanto a ataques de injeção de SQL. Um ataque de injeção de SQL pode executar comandos SQL mal-intencionados que comprometem a segurança e a integridade do aplicativo. As técnicas típicas incluem o uso de uma única aspa ou apóstrofo para delimitar cadeias de caracteres literais, dois traços para um comentário e um ponto e vírgula para o final de uma instrução. Para obter mais informações, consulte SQL Injection.
Essa regra tenta localizar a entrada de solicitações HTTP que atingem um texto de um comando SQL.
Observação
Essa regra não é capaz de rastrear dados em assemblies. Por exemplo, se um assembly ler a entrada de solicitação HTTP e a transmitir a outro assembly que executa o comando SQL, essa regra não produzirá nenhum aviso.
Observação
Há um limite configurável para a profundidade com que essa regra analisa o fluxo de dados nas chamadas de método. Consulte Configuração do analisador para saber como configurar o limite em um arquivo EditorConfig.
Como corrigir violações
Use comandos SQL parametrizados ou procedimentos armazenados, com parâmetros que contenham a entrada não confiável.
Quando suprimir avisos
É seguro suprimir um aviso dessa regra se você souber que a entrada sempre é validada em relação a um conjunto de caracteres seguro conhecido.
Suprimir um aviso
Para suprimir apenas uma violação, adicione diretivas de pré-processador ao arquivo de origem a fim de desabilitar e, em seguida, reabilitar a regra.
#pragma warning disable CA3001
// The code that's violating the rule is on this line.
#pragma warning restore CA3001
Para desabilitar a regra em um arquivo, uma pasta ou um projeto, defina a severidade como none
no arquivo de configuração.
[*.{cs,vb}]
dotnet_diagnostic.CA3001.severity = none
Para obter mais informações, confira Como suprimir avisos de análise de código.
Configurar código para analisar
Use as opções a seguir para configurar em quais partes da base de código essa regra deve ser executada.
Você pode configurar essas opções apenas para essa regra, para todas as regras às quais ela se aplica ou para todas as regras nessa categoria (Segurança) às quais ela se aplica. Para saber mais, confira Opções de configuração de regra de qualidade de código.
Excluir símbolos específicos
Você pode excluir da análise símbolos específicos, como tipos e métodos. Por exemplo, para especificar que a regra não deve ser executada em nenhum código dentro de tipos nomeados MyType
, adicione o seguinte par chave-valor a um arquivo .editorconfig no seu projeto:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Formatos de nome de símbolo permitidos no valor da opção (separados por |
):
- Somente nome do símbolo (inclui todos os símbolos com o nome, independentemente do tipo ou namespace que contém).
- Nomes totalmente qualificados no formato de ID de documentação do símbolo. Cada nome de símbolo requer um prefixo do tipo símbolo, como
M:
para métodos,T:
para tipos eN:
para namespaces. .ctor
para construtores e.cctor
para construtores estáticos.
Exemplos:
Valor de Opção | Resumo |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Corresponde a todos os símbolos nomeados MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Corresponde a todos os símbolos nomeados MyType1 ou MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Corresponde ao método MyMethod específico com a assinatura totalmente qualificada especificada. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Corresponde aos métodos MyMethod1 e MyMethod2 específico com as assinaturas respectivas totalmente qualificadas. |
Excluir tipos específicos e seus tipos derivados
Você pode excluir tipos específicos e seus tipos derivados da análise. Por exemplo, para especificar que a regra não deve ser executada em nenhum método dentro de tipos nomeados MyType
e seus tipos derivados, adicione o seguinte par chave-valor a um arquivo .editorconfig no seu projeto:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Formatos de nome de símbolo permitidos no valor da opção (separados por |
):
- Somente nome do tipo (inclui todos os tipos com o nome, independentemente do tipo ou namespace que contém).
- Nomes totalmente qualificados no formato de ID de documentação do símbolo, com um prefixo opcional
T:
.
Exemplos:
Valor de Opção | Resumo |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Corresponde a todos os tipos nomeados MyType e todos os seus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Corresponde a todos os tipos nomeados MyType1 ou MyType2 e todos os seus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Corresponde a um tipo MyType específico com determinado nome totalmente qualificado e todos os seus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Corresponde a tipos MyType1 e MyType2 específicos com os respectivos nomes totalmente qualificados e todos os seus tipos derivados. |
Exemplos de pseudocódigo
Violação
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
Solução parametrizada
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
Solução de procedimento armazenado
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