Tenho pregado para meus colegas e aqui no SO sobre a vantagem de usar parâmetros em consultas SQL, especialmente em aplicativos .NET. Cheguei até a prometer que eles forneceriam 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 de SQL conhecido que terá êxito em uma consulta parametrizada? Você pode, por exemplo, enviar uma string que causa um estouro de buffer no servidor?
É claro que há outras considerações a serem feitas para garantir que um aplicativo da web seja seguro (como limpar a entrada do usuário e tudo mais), mas agora estou pensando em injeções de SQL. Estou especialmente interessado em ataques contra MsSQL 2005 e 2008, uma vez que são meus bancos de dados principais, mas todos os bancos de dados são interessantes.
Edit: Para esclarecer o que quero dizer com parâmetros e consultas parametrizadas. Ao usar parâmetros, quero dizer usar "variáveis" em vez de construir a consulta sql em uma string.
Então, em vez 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 objeto de consulta / comando.
fonte
Respostas:
Espaços reservados são suficientes para prevenir as injeções. Você ainda pode estar aberto a estouros de buffer, mas esse é um tipo de ataque completamente diferente de uma injeção de SQL (o vetor de ataque não seria sintaxe SQL, mas binário). Uma vez que todos os parâmetros passados terão escape adequado, não há como um invasor passar dados que serão tratados como SQL "ao vivo".
Você não pode usar funções dentro de marcadores de posição e não pode usar marcadores de posição como nomes de coluna ou tabela, porque eles são escapados e citados como literais de string.
No entanto, se você usar parâmetros como parte de uma concatenação de string dentro de sua consulta dinâmica, ainda estará vulnerável à injeção, porque suas strings não terão escape, mas serão literais. Usar outros tipos de parâmetros (como inteiro) é seguro.
Dito isso, se você estiver usando a entrada de uso para definir o valor de algo como
security_level
, então alguém poderia simplesmente tornar-se administrador em seu sistema e ter um free-for-all. Mas isso é apenas validação de entrada básica e não tem nada a ver com injeção de SQL.fonte
Não, ainda há risco de injeção de SQL sempre que você interpola dados não validados em uma consulta SQL.
Os parâmetros de consulta ajudam a evitar esse risco, separando os valores literais da sintaxe SQL.
'SELECT * FROM mytable WHERE colname = ?'
Tudo bem, mas há outros propósitos 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 sintaxe.
'SELECT * FROM ' + @tablename + ' WHERE colname IN (' + @comma_list + ')' ' ORDER BY ' + @colname'
Não importa se você está usando procedimentos armazenados ou executando consultas SQL dinâmicas diretamente do código do aplicativo. O risco ainda existe.
A solução nesses casos é empregar o FIEO conforme necessário:
Filtro de entrada: valide se os dados parecem inteiros legítimos, nomes de tabelas, nomes de colunas, etc. antes de interpolar.
Saída de escape: neste caso, "saída" significa colocar dados em uma consulta SQL. Usamos funções para transformar variáveis 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 variáveis que seriam usadas como nomes de tabelas, nomes de colunas, etc. Quanto a outras sintaxes, como escrever expressões SQL inteiras de forma dinâmica, esse é um problema mais complexo.
fonte
Parece haver alguma confusão neste tópico sobre a definição de uma "consulta parametrizada".
Dada a definição anterior, muitos dos links mostram ataques que funcionam.
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 haja um, mas ainda não vi.
A partir dos comentários, não estou me expressando com clareza suficiente, então aqui está um exemplo que espero ser mais claro:
Esta abordagem está aberta para injeção de SQL
Esta abordagem não está aberta para injeção de SQL
fonte
qualquer parâmetro sql do tipo string (varchar, nvarchar, etc) que é usado para construir uma consulta dinâmica ainda é vulnerável
caso contrário, a conversão do tipo de parâmetro (por exemplo, para int, decimal, data, etc.) deve eliminar qualquer tentativa de injetar 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, é um possível vetor de ataque de injeção de sql;
Se @ p1 for formulado de forma programática sem a capacidade do usuário de intervir, então não é um vetor de ataque de injeção sql potencial
fonte
Um estouro de buffer não é injeção de SQL.
Consultas parametrizadas garantem que você está seguro contra injeção de SQL. Eles não garantem que não haja possíveis exploits na forma de bugs em seu servidor SQL, mas nada garante isso.
fonte
Seus dados não estarão seguros se você usar sql dinâmico de qualquer forma ou formato porque as permissões devem estar no nível da tabela. Sim, você limitou o tipo e a quantidade de ataque de injeção dessa consulta em particular, mas não limitou o acesso que um usuário pode obter se encontrar uma maneira de entrar no sistema e você estiver totalmente sujeito a usuários internos acessando o que não deveriam para cometer fraude ou roubar informações pessoais para vender. SQL dinâmico de qualquer tipo é uma prática perigosa. Se você usar procs armazenados não dinâmicos, você pode definir permissões no nível do procedimento e nenhum usuário pode fazer nada exceto o que é definido pelos procs (exceto administradores de sistema, é claro).
fonte
É possível que um procedimento armazenado seja vulnerável a tipos especiais de injeção SQL por meio de estouro / truncamento, consulte: Injeção habilitada por truncamento de dados aqui:
http://msdn.microsoft.com/en-us/library/ms161953.aspx
fonte
Lembre-se de que, com os parâmetros, você pode armazenar facilmente a string ou dizer o nome de usuário se não tiver nenhuma política, "); eliminar usuários da tabela; -"
Isso por si só não causará nenhum dano, mas você sabe melhor onde e como essa data é usada posteriormente em seu aplicativo (por exemplo, armazenado em um cookie, recuperado posteriormente para fazer outras coisas.
fonte
Você pode executar sql dinâmico 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'
fonte