Nota
L'accés a aquesta pàgina requereix autorització. Podeu provar d'iniciar la sessió o de canviar els directoris.
L'accés a aquesta pàgina requereix autorització. Podeu provar de canviar els directoris.
| Propiedad | Valor |
|---|---|
| Identificador de la regla | CA2100 |
| Título | Revisar consultas SQL para comprobar si tienen vulnerabilidades de seguridad |
| Categoría | Seguridad |
| La solución es disruptiva o no disruptiva | No disruptivo |
| Habilitado de forma predeterminada en .NET 10 | No |
| Idiomas aplicables | C# y Visual Basic |
Causa
Un método establece la System.Data.IDbCommand.CommandText propiedad mediante una cadena que se compila a partir de un argumento de cadena al método .
De forma predeterminada, esta regla analiza todo el código base, pero esto es configurable.
Descripción de la regla
En esta regla se supone que cualquier cadena cuyo valor no se pueda determinar en tiempo de compilación puede contener entradas de usuario. Una cadena de comandos SQL creada a partir de la entrada del usuario es vulnerable a ataques por inyección de CÓDIGO SQL. En un ataque por inyección de código SQL, un usuario malintencionado proporciona entradas que alteran el diseño de una consulta en un intento de dañar u obtener acceso no autorizado a la base de datos subyacente. Entre las técnicas típicas se encuentra la inserción de una comilla simple, que es el delimitador de cadena literal de SQL; dos guiones, que indican un comentario SQL; y un punto y coma, que señala que sigue un nuevo comando. Si las entradas de usuarios deben formar parte de la consulta, use una de las siguientes técnicas, enumeradas en orden de efectividad, para reducir el riesgo de ataque.
- Usa un procedimiento almacenado.
- Use una cadena de comandos con parámetros.
- Valide la entrada de usuario para el tipo y el contenido antes de generar la cadena de comando.
Los siguientes tipos de .NET implementan la CommandText propiedad o proporcionan constructores que establecen la propiedad mediante un argumento de cadena:
- System.Data.Odbc.OdbcCommand y System.Data.Odbc.OdbcDataAdapter
- System.Data.OleDb.OleDbCommand y System.Data.OleDb.OleDbDataAdapter
- System.Data.OracleClient.OracleCommand y System.Data.OracleClient.OracleDataAdapter
- System.Data.SqlClient.SqlCommand y System.Data.SqlClient.SqlDataAdapter
En algunos casos, es posible que esta regla no determine el valor de una cadena en tiempo de compilación, aunque se pueda. En esos casos, esta regla produce falsos positivos al usar esas cadenas como comandos SQL. A continuación se muestra un ejemplo de dicha cadena.
int x = 10;
string query = "SELECT TOP " + x.ToString() + " FROM Table";
Lo mismo sucede cuando se usa ToString() implícitamente.
int x = 10;
string query = String.Format("SELECT TOP {0} FROM Table", x);
Cómo corregir infracciones
Para corregir una infracción de esta regla, use una consulta con parámetros.
Cuándo suprimir las advertencias
Es seguro suprimir una advertencia de esta regla si el texto del comando no contiene ninguna entrada del usuario.
Supresión de una advertencia
Si solo quiere suprimir una única infracción, agregue directivas de preprocesador al archivo de origen para deshabilitar y volver a habilitar la regla.
#pragma warning disable CA2100
// The code that's violating the rule is on this line.
#pragma warning restore CA2100
Para deshabilitar la regla de un archivo, una carpeta o un proyecto, establezca su gravedad en none del archivo de configuración.
[*.{cs,vb}]
dotnet_diagnostic.CA2100.severity = none
Para obtener más información, consulte Procedimiento para suprimir advertencias de análisis de código.
Configuración del código para analizar
Use las opciones siguientes para configurar en qué partes del código base se va a ejecutar esta regla.
Además, las siguientes opciones relacionadas con el análisis del flujo de datos se aplican a esta regla:
- interprocedural_analysis_kind
- cadena_máxima_de_llamadas_a_lambda_o_función_local_interprocedimental
- max_interprocedural_method_call_chain
- tipo_de_análisis_de_puntos
- copy_analysis
- conteo_suficiente_de_iteraciones_para_algoritmo_KDF_debil
Puede configurar estas opciones solo para esta regla, para todas las reglas a las que se aplican o para todas las reglas de esta categoría (Seguridad) a las que se aplican. Para más información, vea Opciones de configuración de reglas de calidad de código.
Exclusión de símbolos específicos
Puede excluir símbolos específicos del análisis, como tipos y métodos, estableciendo la opción excluded_symbol_names. Por ejemplo, para especificar que la regla no se debe ejecutar en ningún código dentro de los tipos con el nombre MyType, agregue el siguiente par clave-valor a un archivo .editorconfig en el proyecto:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Nota:
Reemplace la parte XXXX de CAXXXX por el identificador de la regla que aplique.
Formatos de nombre de símbolo permitidos en el valor de opción (separados por |):
- Nombre del símbolo solamente (incluye todos los símbolos con el nombre, independientemente del tipo contenedor o el espacio de nombres).
- Nombres completamente cualificados en el formato de ID de documentación del símbolo. Cada nombre de símbolo necesita un prefijo de tipo símbolo, como
M:para los métodos,T:para los tipos yN:para los espacios de nombres. -
.ctorpara los constructores y.cctorpara los constructores estáticos.
Ejemplos:
| Valor de la opción | Resumen |
|---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Coincide con todos los símbolos denominados MyType. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Coincide con todos los símbolos denominados MyType1 o MyType2. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Empareja el método MyMethod específico con la firma totalmente cualificada especificada. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Asocia los métodos MyMethod1 y MyMethod2 específicos con las firmas completamente cualificadas respectivas. |
Exclusión de tipos específicos y sus tipos derivados
Puede excluir tipos específicos y sus tipos derivados del análisis estableciendo la opción excluded_type_names_with_derived_types. Por ejemplo, para especificar que la regla no se debe ejecutar en ningún método dentro de los tipos con el nombre MyType y sus tipos derivados, agregue el siguiente par clave-valor a un archivo .editorconfig en el proyecto:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Nota:
Reemplace la parte XXXX de CAXXXX por el identificador de la regla que aplique.
Formatos de nombre de símbolo permitidos en el valor de opción (separados por |):
- Solo nombre de tipo (incluye todos los tipos con el nombre, con independencia del tipo contenedor o el espacio de nombres).
- Nombres completos en el formato de identificador de documentación del símbolo, con un prefijo
T:opcional.
Ejemplos:
| Valor de la opción | Resumen |
|---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Coincide con todos los tipos denominados MyType y todos sus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Coincide con todos los tipos denominados MyType1 o MyType2, y todos sus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Coincide con un tipo MyType específico con el nombre completo dado y todos sus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Relaciona los tipos MyType1 y MyType2 específicos con sus nombres completos correspondientes, así como todos sus tipos derivados. |
Ejemplo
En el ejemplo siguiente se muestra un método , UnsafeQuery, que infringe la regla. También muestra un método , SaferQuery, que satisface la regla mediante una cadena de comandos con parámetros.
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]'
}
}
Importante
Microsoft recomienda usar el flujo de autenticación más seguro disponible. Si se conecta a Azure SQL, el método de autenticación recomendado es Identidades administradas para recursos de Azure.