Quais são as boas maneiras de impedir a injeção de SQL?

Eu tenho que programar um sistema de gerenciamento de aplicativos para a minha empresa OJT. O front end será feito em C # e o back end em SQL.

Agora eu nunca fiz um projeto desse escopo antes; na escola, tínhamos apenas lições básicas sobre SQL. De alguma forma, nosso professor falhou completamente em discutir as injeções de SQL, algo com o qual só agora entro em contato lendo sobre isso na net.

Enfim, minha pergunta é: como você evita injeções SQL em C #? Eu vagamente acho que isso pode ser feito por mascarando corretamente os campos de texto do aplicativo para que ele só aceita input em um formato especificado. Por exemplo: uma checkbox de texto de email deve ter o formato “example@examplecompany.tld”. Esta abordagem seria suficiente? Ou o .NET tem methods predefinidos que lidam com coisas assim? Posso aplicar um filtro a uma checkbox de texto para aceitar apenas o formato de endereço de e-mail ou uma checkbox de texto de nome para que ele não aceite caracteres especiais?

Usando o SqlCommand e sua coleção de parâmetros filhos, todo o esforço de verificar a injeção de sql é tirado de você e será tratado por essas classs.

Aqui está um exemplo, retirado de um dos artigos acima:

 private static void UpdateDemographics(Int32 customerID, string demoXml, string connectionString) { // Update the demographics for a store, which is stored // in an xml column. string commandText = "UPDATE Sales.Store SET Demographics = @demographics " + "WHERE CustomerID = @ID;"; using (SqlConnection connection = new SqlConnection(connectionString)) { SqlCommand command = new SqlCommand(commandText, connection); command.Parameters.Add("@ID", SqlDbType.Int); command.Parameters["@ID"].Value = customerID; // Use AddWithValue to assign Demographics. // SQL Server will implicitly convert strings into XML. command.Parameters.AddWithValue("@demographics", demoXml); try { connection.Open(); Int32 rowsAffected = command.ExecuteNonQuery(); Console.WriteLine("RowsAffected: {0}", rowsAffected); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } 

Injeção de SQL pode ser um problema complicado, mas existem maneiras de contornar isso. Seu risco é reduzido seu risco simplesmente usando um ORM como Linq2Entities, Linq2SQL, NHibrenate. No entanto, você pode ter problemas de injeção de SQL, mesmo com eles.

A principal coisa com injeção de SQL é a input controlada pelo usuário (como no XSS). No exemplo mais simples, se você tem um formulário de login (espero que você nunca tenha um que apenas faça isso) que leva um nome de usuário e senha.

 SELECT * FROM Users WHERE Username = '" + username + "' AND password = '" + password + "'" 

Se um usuário introduzisse o seguinte para o nome de usuário Admin ‘- a instrução SQL ficaria assim quando executada no database.

 SELECT * FROM Users WHERE Username = 'Admin' --' AND password = '' 

Nesse caso simples, usar uma consulta parametrizada (que é o que um ORM faz) removeria seu risco. Você também tem o problema de um vetor de ataque de injeção SQL menos conhecido e isso é com stored procedures. Neste caso, mesmo se você usar uma consulta parametrizada ou um ORM, você ainda terá um problema de injeção de SQL. Os stored procedures podem conter comandos de execução e esses comandos podem ser aceitáveis ​​para ataques de injeção de SQL.

 CREATE PROCEDURE SP_GetLogin @username varchar(100), @password varchar(100) AS DECLARE @sql nvarchar(4000) SELECT @sql = ' SELECT * FROM users' + ' FROM Product Where username = ''' + @username + ''' AND password = '''+@password+'''' EXECUTE sp_executesql @sql 

Portanto, este exemplo teria o mesmo problema de injeção SQL que o anterior, mesmo que você use consultas parametrizadas ou um ORM. E embora o exemplo pareça bobo, você ficaria surpreso com a frequência com que algo assim é escrito.

Minhas recomendações seriam usar um ORM para reduzir imediatamente suas chances de ter um problema de injeção de SQL e, em seguida, aprender a identificar o código e os stored procedures que podem ter o problema e trabalhar para corrigi-los. Eu não recomendo usar o ADO.NET (SqlClient, SqlCommand, etc …) diretamente, a menos que você precise, não porque não seja seguro usá-lo com parâmetros, mas porque é muito mais fácil ficar com preguiça e começar a escrever um SQL consulta usando strings e apenas ignorando os parâmetros. O ORMS faz um ótimo trabalho de forçar você a usar parâmetros porque é exatamente o que eles fazem.

Em seguida, visite o site do OWASP sobre injeção SQL https://www.owasp.org/index.php/SQL_Injection e use a folha de dicas de injeção de SQL para certificar-se de que você pode identificar e remover quaisquer problemas que possam surgir em seu código. https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet finalmente eu diria colocar em prática uma boa revisão de código entre você e outros desenvolvedores em sua empresa, onde você pode rever o código uns dos outros para coisas como injeção de SQL e XSS. Muitas vezes os programadores perdem essas coisas porque estão tentando apressar algum recurso e não gastam muito tempo revisando o código.

Minha resposta é bem fácil:

Use o Entity Framework para comunicação entre o C # e seu database SQL. Isso fará com sequências SQL parametrizadas que não são vulneráveis ​​à injeção de SQL.

Como bônus, é muito fácil trabalhar também.

Use consultas SQL parametrizadas.

Veja estas perguntas e respostas: https://stackoverflow.com/search?tab=votes&q=sql%20injection

Uma compreensão do conceito de injeção de SQL: http://en.wikipedia.org/wiki/SQL_injection

A injeção de SQL não deve ser evitada tentando validar sua input; em vez disso, essa input deve escaping corretamente antes de ser passada para o database.

Como escaping da input depende totalmente de qual tecnologia você está usando para fazer a interface com o database. Na maioria dos casos, e a menos que você esteja escrevendo o SQL puro (o que deve ser evitado o máximo possível), ele será automaticamente controlado pelo framework para que você obtenha proteção à prova de balas de graça.

Você deve explorar essa questão depois de decidir exatamente qual será a sua tecnologia de interface.