CA2100: Analisar consultas SQL vulnerabilidades de segurança
TypeName |
ReviewSqlQueriesForSecurityVulnerabilities |
CheckId |
CA2100 |
<strong>Categoria</strong> |
Microsoft.Security |
Alteração significativa |
Não-separável |
Causa
Um método que define o IDbCommand.CommandText propriedade usando uma seqüência de caracteres que é criada a partir de um argumento de seqüência de caracteres para o método.
Descrição da regra
Esta regra pressupõe que o argumento de seqüência de caracteres contém a entrada do usuário. Uma seqüência de caracteres de comando SQL é criada a partir da entrada do usuário é vulnerável a ataques de injeção de SQL. Em um ataque de injeção de SQL, um usuário mal-intencionado fontes de entrada que altera a estrutura de uma consulta em uma tentativa de danificar ou obter acesso não autorizado ao banco de dados subjacente. Técnicas típicas incluem a injeção de uma aspa simples ou apóstrofe, que é o delimitador de seqüência de caracteres literal SQL; dois traços, o que significa um comentário SQL; e um ponto e vírgula, que indica que segue um novo comando. Se a entrada do usuário deve ser parte da consulta, use um dos seguintes, listados em ordem de eficácia, reduzir o risco de ataque.
Use um procedimento armazenado.
Use uma seqüência de comando com parâmetros.
Valide a entrada do usuário para o tipo e o conteúdo antes de construir a seqüência de comandos.
O seguinte .NET Framework tipos de implementam a CommandText propriedade ou forneço construtores que defina a propriedade usando um argumento de seqüência de caracteres.
System.Data.Odbc.OdbcCommand e System.Data.Odbc.OdbcDataAdapter
System.Data.OleDb.OleDbCommand e System.Data.OleDb.OleDbDataAdapter
System.Data.OracleClient.OracleCommand e System.Data.OracleClient.OracleDataAdapter
[System.Data.SqlServerCe.SqlCeCommand]e[System.Data.SqlServerCe.SqlCeDataAdapter]
System.Data.SqlClient.SqlCommand e System.Data.SqlClient.SqlDataAdapter
Observe que essa regra é violada quando o método ToString de um tipo é usado implicitamente ou explicitamente para construir a seqüência de caracteres de consulta. The following is an example.
int x = 10;
string query = "SELECT TOP " + x.ToString() + " FROM Table";
A regra é violada porque um usuário mal-intencionado pode substituir o método toString ().
A regra também é violada quando ToString é usada implicitamente.
int x = 10;
string query = String.Format("SELECT TOP {0} FROM Table", x);
Como corrigir violações
Para corrigir uma violação desta regra, use uma consulta parametrizada.
Quando suprimir avisos
É seguro eliminar um aviso esta regra se o texto do comando não contém qualquer entrada do usuário.
Exemplo
O exemplo a seguir mostra um método, UnsafeQuery, que viola a regra e um método SaferQuery, que satisfaça a regra usando uma seqüência de comando com parâmetros.
Imports System
Imports System.Data
Imports System.Data.SqlClient
Namespace SecurityLibrary
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 MalaciousCode
Shared Sub Main(args As String())
Dim queries As New SqlQueries()
queries.UnsafeQuery(args(0), "' OR 1=1 --", "anything")
' Resultant query (which is always true):
' SELECT AccountNumber FROM Users WHERE Username='' OR 1=1
queries.SaferQuery(args(0), "' OR 1 = 1 --", "anything")
' Resultant query (notice the additional single quote character):
' SELECT AccountNumber FROM Users WHERE Username=''' OR 1=1 --'
' AND Password='anything'
End Sub
End Class
End Namespace
using System;
using System.Data;
using System.Data.SqlClient;
namespace SecurityLibrary
{
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 MalaciousCode
{
static void Main(string[] args)
{
SqlQueries queries = new SqlQueries();
queries.UnsafeQuery(args[0], "' OR 1=1 --", "anything");
// Resultant query (which is always true):
// SELECT AccountNumber FROM Users WHERE Username='' OR 1=1
queries.SaferQuery(args[0], "' OR 1 = 1 --", "anything");
// Resultant query (notice the additional single quote character):
// SELECT AccountNumber FROM Users WHERE Username=''' OR 1=1 --'
// AND Password='anything'
}
}
}
#using <System.dll>
#using <System.Data.dll>
#using <System.EnterpriseServices.dll>
#using <System.Transactions.dll>
#using <System.Xml.dll>
using namespace System;
using namespace System::Data;
using namespace System::Data::SqlClient;
namespace SecurityLibrary
{
public ref class SqlQueries
{
public:
Object^ UnsafeQuery(
String^ connection, String^ name, String^ password)
{
SqlConnection^ someConnection = gcnew SqlConnection(connection);
SqlCommand^ someCommand = gcnew SqlCommand();
someCommand->Connection = someConnection;
someCommand->CommandText = String::Concat(
"SELECT AccountNumber FROM Users WHERE Username='",
name, "' AND Password='", password, "'");
someConnection->Open();
Object^ accountNumber = someCommand->ExecuteScalar();
someConnection->Close();
return accountNumber;
}
Object^ SaferQuery(
String^ connection, String^ name, String^ password)
{
SqlConnection^ someConnection = gcnew SqlConnection(connection);
SqlCommand^ someCommand = gcnew 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;
}
};
}
using namespace SecurityLibrary;
void main()
{
SqlQueries^ queries = gcnew SqlQueries();
queries->UnsafeQuery(Environment::GetCommandLineArgs()[1],
"' OR 1=1 --", "anything");
// Resultant query (which is always true):
// SELECT AccountNumber FROM Users WHERE Username='' OR 1=1
queries->SaferQuery(Environment::GetCommandLineArgs()[1],
"' OR 1 = 1 --", "anything");
// Resultant query (notice the additional single quote character):
// SELECT AccountNumber FROM Users WHERE Username=''' OR 1=1 --'
// AND Password='anything'
}