C#: evitando a Injeção de SQL

A Injeção de SQL, ou em inglês SQL Injection, é uma vulnerabilidade que permite que algum usuário malicioso possa executar uma instrução em SQL dentro da aplicação, aproveitando uma brecha em uma consulta que permita acesso ao banco de dados.

Para demonstrar um exemplo desta vulnerabilidade, vamos criar um banco de dados de vendas, onde temos nossa tabela de usuários com alguns informações.

Abra o Visual Studio Code, e crie uma pasta chamada EvitandoAInjecaoDeSQL, e dentro dela outra chamada src. Em EvitandoAInjecaoDeSQL crie uma solução usando o comando dotnet new sln e logo em seguida abra a pasta src, adicione e logo abra um nova pasta chamada EvitandoAInjecaoDeSQL.Web e adicione um projeto do tipo MVC usando o comando dotnet new mvc, volte até a pasta EvitandoAInjecaoDeSQL e adicone o projeto na solução usando o comando  dotnet sln add .\src\EvitandoAInjecaoDeSQL.Web\EvitandoAInjecaoDeSQL.Web.csproj.

Adicione um controller na pasta Controllers do projeto de MVC chamado ContaController.cs e uma view chamada Login.cshtml na pasta Views/Conta.

A tela de login deve ser semelhante a esta, após abrir o site e digitar uma senha válida:

O nosso site está funcionando, então agora vamos aplicar o SQL Injection para verificar a vulnerabilidade. Como vimos, o campo usuário e senha só efetua login se for digitado um nome de usuário e uma senha correta. Mas vamos tentar burlar isto.

Para entdenr o que acontece no lado do banco de dados ao digitar o usuário e senha da captura de tela, vamos analisar a intrução SQL montada pelo aplicativo:

Se executarmos a instrução acima no SQL Server, temos o resultado 1, que é a informação que permite que o sistema permita o acesso.

Mas esta instrução é facilmente alterada usando alguns caracteres de ‘ (apóstrofo), fazendo a consulta ficar assim:

Que retorna um valor positivo, mesmo sem informar a senha.

Mas como isto é possível sem editar o SQL que está no código? Simples, pois a forma a instrução foi montada, permite que seja alterada, pois o SELECT é uma concatenação dos campos que são enviados no post e a o corpo da instrução, o C# não sabe o que é filtro e o que é comando de banco, ele monta primeiro uma string e depois executa no banco. Sendo assim, vamos recriar esta consulta direto no campo de senha.

Antes, tente digitar uma senha errada, para conferir se formulário está funcionando e acessando os dados corretamente.

Agora vamos explorar a vulnerabilidades, digitando no campo de senha ‘ OR ‘1’ = ‘1 e clique em login.

E acabamos de ser invadidos por uma falha bem simples no site, pois é possivel “editar” a instrução SQL antes de enviar. Este tipo de falha, pode ser tão grave que é até pode permitir acessar e alterar informações do próprio sistema operacional, dependendo da configuração do banco de dados.

Mas como consertamos este caso específico? A solução a seguir vai resolver este tipo de abertura, mas há outros tipos de falahas que podem precisar uma solução mais avançada. O que vamos fazer é passar parâmetros para o banco de dados em vez de montar todo o sql de uma vez, para isso, em vez de usar uma concatenação, mas nomer estes dados usando um @ (arroba antes) antes, então, para isto, vou comentar o código vulnerável do arquivo ContaController.cs e adicionar a forma mais segura, como segue:

Com isto, temos um código mais seguro. Outra solução, seria usar frameworks ORM, como Entity Framework ou NHibernate.

O projeto completo está disponível no meu GitHub:

https://github.com/tiagopariz/EvitandoAInjecaoDeSQL

Obrigado e um bom dia a todos.