Os parâmetros são realmente suficientes para evitar injeções de Sql?

Tenho pregado tanto para meus colegas quanto para SO sobre a utilidade de usar parâmetros em consultas SQL, especialmente em aplicativos .NET. Eu cheguei a prometer a imunidade contra ataques de injeção de SQL.

Mas estou começando a me perguntar se isso é realmente verdade. Há algum ataque de injeção SQL conhecido que será bem-sucedido em relação a uma consulta parametrizada? Você pode, por exemplo, enviar uma string que causa um estouro de buffer no servidor?

É claro que existem outras considerações a serem feitas para garantir que um aplicativo da Web seja seguro (como sanear a input do usuário e todas essas coisas), mas agora estou pensando em injeções de SQL. Estou especialmente interessado em ataques contra o MsSQL 2005 e 2008, uma vez que são meus bancos de dados principais, mas todos os bancos de dados são interessantes.

Editar: para esclarecer o que quero dizer com parâmetros e consultas parametrizadas. Usando parâmetros eu quero dizer usando “variables” em vez de construir a consulta sql em uma string.
Então, ao invés de fazer isso:

SELECT * FROM Table WHERE Name = 'a name' 

Nós fazemos isso:

 SELECT * FROM Table WHERE Name = @Name 

e, em seguida, defina o valor do parâmetro @Name no object query / command.

Placeholders são suficientes para evitar injeções. Você ainda pode estar aberto a buffer overflows, mas esse é um tipo de ataque completamente diferente de uma injeção SQL (o vetor de ataque não seria syntax SQL, mas sim binário). Como os parâmetros transmitidos serão todos escapados corretamente, não há como um invasor transmitir dados que serão tratados como SQL “ativa”.

Você não pode usar funções dentro de espaços reservados, e você não pode usar espaços reservados como nomes de coluna ou tabela, porque eles são escapados e citados como literais de seqüência de caracteres.

No entanto, se você usar parâmetros como parte de uma concatenação de cadeia de caracteres dentro de sua consulta dinâmica, ainda estará vulnerável à injeção, porque suas cadeias não terão escape, mas serão literais. Usar outros tipos para parâmetros (como integer) é seguro.

Dito isso, se você estiver usando a input de uso para definir o valor de algo como security_level , alguém pode se tornar administrador no seu sistema e ter um free-for-all. Mas isso é apenas validação de input básica e não tem nada a ver com injeção de SQL.

Não, ainda há risco de injeção de SQL sempre que você interpolar dados não validados em uma consulta SQL.

Os parâmetros de consulta ajudam a evitar esse risco, separando valores literais da syntax SQL.

 'SELECT * FROM mytable WHERE colname = ?' 

Isso é bom, mas há outras finalidades de interpolação de dados em uma consulta SQL dinâmica que não pode usar parâmetros de consulta, porque não é um valor SQL, mas um nome de tabela, nome de coluna, expressão ou alguma outra syntax.

 'SELECT * FROM ' + @tablename + ' WHERE colname IN (' + @comma_list + ')' ' ORDER BY ' + @colname' 

Não importa se você está usando stored procedures ou executando consultas SQL dinâmicas diretamente do código do aplicativo. O risco ainda está lá.

O remédio nesses casos é empregar o FIEO conforme necessário:

  • Entrada de filtro: confirme se os dados se parecem com inteiros legítimos, nomes de tabelas, nomes de colunas, etc. antes de você interpolar os dados.

  • Saída de escape: neste caso, “saída” significa colocar dados em uma consulta SQL. Usamos funções para transformar variables ​​usadas como literais de string em uma expressão SQL, para que as aspas e outros caracteres especiais dentro da string sejam escapados. Devemos também usar funções para transformar variables ​​que seriam usadas como nomes de tabelas, nomes de colunas, etc. Quanto a outras syntaxs, como escrever expressões SQL inteiras dinamicamente, esse é um problema mais complexo.

Parece haver alguma confusão nesta discussão sobre a definição de uma “consulta parametrizada”.

  • SQL, como um procedimento armazenado que aceita parâmetros.
  • SQL que é chamado usando a coleção DBMS Parameters.

Dada a antiga definição, muitos dos links mostram ataques operacionais.

Mas a definição “normal” é a última. Dada essa definição, não conheço nenhum ataque de injeção de SQL que funcione. Isso não significa que não exista, mas ainda tenho que ver.

A partir dos comentários, não estou me expressando com clareza suficiente, então aqui está um exemplo que esperamos ser mais claro:

Essa abordagem está aberta para injeção de SQL

 exec dbo.MyStoredProc 'DodgyText' 

Esta abordagem não está aberta para injeção de SQL

 using (SqlCommand cmd = new SqlCommand("dbo.MyStoredProc", testConnection)) { cmd.CommandType = CommandType.StoredProcedure; SqlParameter newParam = new SqlParameter(paramName, SqlDbType.Varchar); newParam.Value = "DodgyText"; ..... cmd.Parameters.Add(newParam); ..... cmd.ExecuteNonQuery(); } 

qualquer parâmetro sql do tipo string (varchar, nvarchar, etc) usado para construir uma consulta dinâmica ainda é vulnerável

caso contrário, a conversão de tipo de parâmetro (por exemplo, int, decimal, data, etc.) deve eliminar qualquer tentativa de injeção de sql por meio do parâmetro

EDIT: um exemplo, onde o parâmetro @ p1 se destina a ser um nome de tabela

 create procedure dbo.uspBeAfraidBeVeryAfraid ( @p1 varchar(64) ) AS SET NOCOUNT ON declare @sql varchar(512) set @sql = 'select * from ' + @p1 exec(@sql) GO 

Se @ p1 for selecionado em uma lista suspensa, será um possível vetor de ataque de injeção SQL;

Se @ p1 for formulado programaticamente sem a capacidade do usuário de intervir, então não é um vetor de ataque potencial de injeção de SQL

Um estouro de buffer não é injeção de SQL.

Consultas parametrizadas garantem que você esteja seguro contra a injeção de SQL. Eles não garantem que não há falhas possíveis na forma de erros no seu servidor SQL, mas nada garante isso.

Seus dados não são seguros se você usar o SQL dynamic em qualquer formato ou forma, porque as permissions devem estar no nível da tabela. Sim, você limitou o tipo e quantidade de ataque de injeção daquela consulta em particular, mas não limitou o access que um usuário pode obter se encontrar um caminho para o sistema e você é completamente vulnerável a usuários internos que acessam o que não devem para cometer fraudes ou roubar informações pessoais para vender. SQL dynamic de qualquer tipo é uma prática perigosa. Se você usar procs armazenados não dynamics, você pode definir permissions no nível de processo e nenhum usuário pode fazer nada, exceto o que é definido pelo procs (exceto administradores do sistema, é claro).

É possível que um proc armazenado seja vulnerável a tipos especiais de injeção SQL via overflow / truncation, veja: Injeção Habilitada por truncamento de dados aqui:

http://msdn.microsoft.com/pt-br/library/ms161953.aspx

Apenas lembre-se que com parâmetros você pode facilmente armazenar a string, ou dizer username se você não tem políticas, “); drop table users; -”

Isso por si só não causa nenhum dano, mas é melhor você saber onde e como essa data é usada mais adiante em seu aplicativo (por exemplo, armazenado em um cookie, recuperado posteriormente para fazer outras coisas.

Você pode executar o SQL dynamic como exemplo

 DECLARE @SQL NVARCHAR(4000); DECLARE @ParameterDefinition NVARCHAR(4000); SELECT @ParameterDefinition = '@date varchar(10)' SET @SQL='Select CAST(@date AS DATETIME) Date' EXEC sp_executeSQL @SQL,@ParameterDefinition,@date='04/15/2011'