Partilhar via


CA2100: revisar consultas SQL para vulnerabilidades de segurança

TypeName

ReviewSqlQueriesForSecurityVulnerabilities

CheckId

CA2100

Categoria

Microsoft.Security

Alteração Significativa

Sem quebra

Causa

Um método define a propriedade de IDbCommand.CommandText usando uma cadeia de caracteres que é criada a partir de um argumento de cadeia de caracteres para o método.

Descrição da Regra

Esta regra presume que o argumento de cadeia de caracteres contém a entrada do usuário.Uma cadeia de caracteres de comando SQL que é criada da entrada do usuário é vulnerável a ataques de injeção SQL.Em um ataque de injeção SQL, um usuário mal-intencionado fornece entrada que modificar o design de uma consulta na tentativa de danificar ou ter acesso não autorizado a base de dados subjacente.As técnicas básicas incluem a injeção de uma aspa simples ou de apóstrofo, que é o delimitador de cadeia de caracteres literal SQL; dois características, que significa um comentário SQL; e um ponto-e-vírgula, que indica que um novo comando a seguir.Se a entrada de usuário deve fazer parte da consulta, use uma das opções a seguir, listados em ordem de eficiência, para reduzir o risco de ataque.

  • Use um procedimento armazenado.

  • Use uma cadeia de caracteres de comando com parâmetros.

  • Validar entrada do usuário para o tipo e o conteúdo antes de compilar a cadeia de caracteres de comando.

Os seguintes tipos de .NET Framework implementam a propriedade de CommandText ou fornecem construtores esse conjunto a propriedade usando um argumento de cadeia de caracteres.

Observe que esta regra for violada quando o método ToString de um tipo é usado para construir explicitamente ou implicitamente a cadeia de caracteres da consulta.A seguir temos um exemplo.

int x = 10;
string query = "SELECT TOP " + x.ToString() + " FROM Table";

A regra é violada como um usuário mal-intencionado pode substituir o método de ToString() .

A regra é violada também quando ToString é usado 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 Alertas

É seguro suprimir um aviso dessa regra se o texto do comando não contém nenhuma entrada do usuário.

Exemplo

O exemplo a seguir mostra um método, UnsafeQuery, que viola a regra e um método, SaferQuery, que obedece à regra usando uma cadeia de caracteres 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'
}

Consulte também

Conceitos

Visão geral da segurança [wd_adonet]