Ir para o conteúdo do rodapé
Iron Academy Logo
Integração de banco de dados em C#

O que é injeção de SQL e como posso evitá-la em C#?

Tim Corey
34m 33s

A injeção de SQL é uma técnica de injeção de código que permite que invasores enviem código SQL malicioso para o seu servidor de banco de dados por meio da entrada do usuário. Em seu vídeo " O que é SQL Injection e como posso evitá-la em C#? ", Tim Corey demonstra exatamente como as vulnerabilidades de SQL Injection aparecem em código real, mostra vários exemplos de ataques de SQL Injection bem-sucedidos (incluindo ataques baseados em UNION e ataques destrutivos) e apresenta técnicas práticas de prevenção de SQL Injection que você pode aplicar em C#. Este artigo segue o passo a passo do Tim para que você possa ver exatamente os problemas e soluções que ele mostra.

Aplicativo de demonstração e por que isso é importante.

Tim começa com um pequeno aplicativo de demonstração WPF vinculado a um InjectableDB local (tabelas People e Secrets). A caixa de pesquisa do aplicativo, semelhante a um formulário da web, recebe a entrada do usuário (um sobrenome) e constrói uma consulta SQL para retornar o ID, o nome e o sobrenome. Funciona — digite Corey e você encontrará Tim Corey — mas Tim enfatiza o ponto principal: "Só porque um aplicativo funciona não significa que ele seja seguro." Um aplicativo web em funcionamento ainda pode ter vulnerabilidades de injeção de SQL quando a entrada fornecida pelo usuário é inserida diretamente em instruções SQL por meio de concatenação de strings ou SQL dinâmico.

Código inseguro — concatenação de strings e SQL dinâmico

Tim demonstra o padrão inseguro exato que muitos desenvolvedores utilizam:

var sql = $"SELECT * FROM People WHERE LastName = '{searchText}'";
var results = connection.Query<Person>(sql);
var sql = $"SELECT * FROM People WHERE LastName = '{searchText}'";
var results = connection.Query<Person>(sql);

Esta consulta original utiliza concatenação de strings para criar uma instrução SQL. Tim alerta: se você encontrar código que injeta entradas do usuário diretamente em consultas SQL, pare — isso é uma vulnerabilidade de injeção de SQL. Os atacantes podem criar entradas maliciosas que alteram a estrutura dos seus comandos SQL ou até mesmo executam instruções SQL maliciosas adicionais.

Como um atacante explora isso — UNION e DROP

Para demonstrar como funciona um ataque de injeção de SQL, Tim reproduz consultas no SQL Server e, em seguida, cria injeções usando UNION ALL e comentários SQL (--) para ocultar caracteres finais. Exemplos de payloads maliciosos que Tim demonstra:

  • Injeção de SQL baseada em UNION para ler outras tabelas:

    UNION ALL SELECT ID, Username AS FirstName, Password AS LastName FROM Secrets;

    Isso mistura os resultados de Secrets com o conjunto de resultados original do SELECT, expondo dados confidenciais como nomes de usuário e senhas.

  • Injeção destrutiva para excluir tabelas:

    DROP TABLE DemoTable;

    Isso executa uma segunda instrução SQL (DROP TABLE) finalizando a primeira instrução com um ponto e vírgula e, em seguida, adicionando o comando destrutivo. Tim mostra que a tabela desapareceu — o banco de dados foi modificado por um comando SQL malicioso.

A questão levantada por Tim é a seguinte: os atacantes não precisam saber os nomes das tabelas ou colunas com antecedência — eles podem enumerar os nomes das tabelas ou colunas nos servidores de banco de dados, ou simplesmente tentar técnicas baseadas em análise de dados ou em tempo real para descobrir o comportamento.

Correção 1 — Consultas parametrizadas

A primeira e principal defesa de Tim é parar de construir strings SQL com dados do usuário. Substitua o SQL dinâmico por consultas parametrizadas:

string sql = "SELECT * FROM People WHERE LastName = @LastName";
var results = connection.Query<Person>(sql, new { LastName = searchText });
string sql = "SELECT * FROM People WHERE LastName = @LastName";
var results = connection.Query<Person>(sql, new { LastName = searchText });

Tim explica que a parametrização (uso no estilo de instruções preparadas) significa que o banco de dados trata a entrada fornecida pelo usuário estritamente como dados — o SQL malicioso se torna apenas um valor de string e não pode alterar a estrutura do SQL. Isso impede muitos ataques comuns de injeção de SQL, incluindo payloads baseados em union e anexados; Comandos DROP TABLE.

Ele também recomenda combinar a parametrização com a validação mínima de entrada: higienizar ou bloquear caracteres improváveis ​​em um sobrenome (por exemplo, ponto e vírgula ou marcadores de comentário --) enquanto permite caracteres legítimos como apóstrofos (O'Reilly). Consultas parametrizadas e limpeza de entrada oferecem proteção substancial contra ataques de injeção de SQL.

Correção 2 — Procedimentos armazenados

Em seguida, Tim mostra dois procedimentos armazenados: um procedimento armazenado inseguro que concatena SQL dentro do procedimento e depois o executa, e um procedimento armazenado seguro que usa parâmetros diretamente.

  • O procedimento armazenado inseguro constrói uma string @sql a partir do parâmetro e a executa — ainda vulnerável a injeção.

  • O procedimento armazenado seguro executa SELECT ... WHERE LastName = @LastName e executa com o parâmetro — seguro.

Tim esclarece: procedimentos armazenados não são uma solução automática se você ainda construir SQL dinâmico dentro deles. Mas, quando usadas corretamente (sem SQL dinâmico), as stored procedures ajudam a centralizar as instruções SQL, facilitando a parametrização e a auditoria de consultas. Os procedimentos armazenados também podem ajudar a simplificar a prevenção de injeção de SQL em seu aplicativo.

Não confie em nenhum dado — nem mesmo em dados de banco de dados.

Um ponto importante, e muitas vezes ignorado, que Tim levanta: você não deve confiar cegamente nos dados recuperados do seu próprio banco de dados SQL. Os atacantes às vezes inserem cargas maliciosas em colunas (uma "bomba-relógio") que serão posteriormente concatenadas em SQL dinâmico por outro processo. Tim insiste: use sempre parâmetros e higienize os dados em cada etapa — seja por meio de um formulário da web, um upload de arquivo ou seu próprio banco de dados — para que entradas maliciosas não se tornem posteriormente uma via de injeção.

Dica extra — princípio do menor privilégio e limitação de privilégios em bancos de dados.

Além das correções de código, Tim recomenda uma configuração defensiva: limite os privilégios de banco de dados para as contas do seu aplicativo. Na demonstração, a conexão utiliza uma conta de administrador por meio de segurança integrada — o que é perigoso. Em vez disso, utilize o princípio do menor privilégio:

  • Crie uma conta de banco de dados para o aplicativo com apenas os direitos necessários.

  • Se você usar procedimentos armazenados, conceda a essa conta apenas a permissão EXECUTE em procedimentos armazenados específicos e nada mais.

  • Não conceda privilégios de administrador amplos às contas de aplicativos, que permitam executar comandos como DROP TABLE, listar todas as tabelas ou ler outros bancos de dados.

Isso reduz o impacto de um ataque de injeção de SQL bem-sucedido — mesmo que a injeção seja possível, o invasor não poderá fazer mais do que a conta permite.

Tim também observa que o Entity Framework complica isso: o EF geralmente requer permissões elevadas (migrações, alterações de esquema). Se você usa o EF em produção, planeje suas permissões e implantação com cuidado.

Resumo — parar, parametrizar, higienizar, limitar

Tim conclui seu vídeo com uma lista de verificação clara para evitar injeção de SQL em aplicações C#:

  1. Pare de criar instruções SQL com concatenação de strings ou SQL dinâmico que inclua entrada do usuário.

  2. Utilize consultas parametrizadas/padrões de instruções preparadas para que os dados do usuário sejam sempre tratados como dados.

  3. Limpe a entrada quando apropriado (bloqueie ponto e vírgula, comentários SQL e caracteres inesperados).

  4. Prefira procedimentos armazenados seguros (sem SQL dinâmico em seu interior) para centralizar a lógica de consulta.

  5. Aplique o princípio do menor privilégio às contas de banco de dados — limite o que o usuário do banco de dados do aplicativo pode fazer.

  6. Analise o código (especialmente os locais que constroem SQL dinamicamente) e teste em busca de falhas de injeção de SQL.

Último aviso de Tim: o manuseio inadequado de entradas de usuário, SQL dinâmico e privilégios excessivos de banco de dados podem levar a violações graves — vazamento de dados confidenciais, tabelas destruídas ou exfiltração de dados não detectada e de longa duração. Considere a prevenção de injeção de SQL como um requisito fundamental de segurança, não como um mero aprimoramento opcional.

Hero Worlddot related to O que é injeção de SQL e como posso evitá-la em C#?
Hero Affiliate related to O que é injeção de SQL e como posso evitá-la em C#?

Ganhe mais compartilhando o que você ama.

Você cria conteúdo para desenvolvedores que trabalham com .NET, C#, Java, Python ou Node.js? Transforme sua expertise em renda extra!

Equipe de suporte de ferro

Estamos online 24 horas por dia, 5 dias por semana.
Bater papo
E-mail
Liga para mim