TL; DR
- A aplicação aceita a entrada, neste caso 'Nancy', sem tentar - higienizar a entrada, como por escapar caracteres especiais
escola => INSERÇÃO EM estudantes VALORES ( 'Nancy' ); INSERIR 0 1
- injeção SQL ocorre quando a entrada em um comando de banco de dados é manipulado para - causa o servidor de banco de dados para executar SQL arbitrárias
escola => INSERÇÃO EM estudantes VALORES ( 'Robert' ); Alunos da DROP TABLE ; - '); INSERIR 0 1 TABELA DE QUEDA
- Os registros dos alunos já se foram - poderia ter sido ainda pior!
escola => SELECIONE * DOS ALUNOS ;
ERRO : relação "estudantes" que não existem
LINHA 1 : SELECIONE * DOS ALUNOS ; ^
Isso elimina (exclui) a tabela do aluno.
( Todos os exemplos de código nesta resposta foram executados em um servidor de banco de dados PostgreSQL 9.1.2. )
Para deixar claro o que está acontecendo, vamos tentar isso com uma tabela simples contendo apenas o campo de nome e adicionar uma única linha:
escola => CRIAR TABELA alunos ( nome CHAVE PRIMÁRIA DO TEXTO );
AVISO : CRIAR TABELA / PRIMARY KEY vai criar implícita índice "students_pkey" por tabela "estudantes" CRIAR TABELA
escola => INSERÇÃO EM estudantes VALORES ( 'John' ); INSERIR 0 1
Vamos supor que o aplicativo use o seguinte SQL para inserir dados na tabela:
INSERÇÃO EM estudantes VALORES ( 'foobar' );
Substitua foobar
pelo nome real do aluno. Uma operação de inserção normal ficaria assim:
- Entrada: Nancy
escola => INSERÇÃO EM estudantes VALORES ( 'Nancy' ); INSERIR 0 1
Quando consultamos a tabela, obtemos o seguinte:
escola => SELECIONE * DOS ALUNOS ;
nome
-------
John
Nancy
( 2 linhas )
O que acontece quando inserimos o nome de Little Bobby Tables na tabela?
- Entrada: Robert '); Alunos da DROP TABLE; -
escola => INSERÇÃO EM estudantes VALORES ( 'Robert' ); Alunos da DROP TABLE ; - '); INSERIR 0 1 TABELA DE QUEDA
A injeção de SQL aqui é o resultado do nome do aluno encerrando a instrução e incluindo um DROP TABLE
comando separado ; os dois traços no final da entrada devem comentar qualquer código restante que, de outra forma, causaria um erro. A última linha da saída confirma que o servidor de banco de dados descartou a tabela.
É importante observar que, durante a INSERT
operação, o aplicativo não verifica os caracteres especiais da entrada e, portanto, permite que entradas arbitrárias sejam inseridas no comando SQL. Isso significa que um usuário mal-intencionado pode inserir, em um campo normalmente destinado à entrada do usuário, símbolos especiais como aspas e código SQL arbitrário para fazer com que o sistema de banco de dados o execute, daí a injeção de SQL .
O resultado?
escola => SELECIONE * DOS ALUNOS ;
ERRO : relação "estudantes" que não existem
LINHA 1 : SELECIONE * DOS ALUNOS ; ^
A injeção de SQL é o equivalente ao banco de dados de uma vulnerabilidade de execução remota de código arbitrário em um sistema operacional ou aplicativo. O impacto potencial de um ataque de injeção SQL bem-sucedido não pode ser subestimado - dependendo do sistema de banco de dados e da configuração do aplicativo, ele pode ser usado por um invasor para causar perda de dados (como neste caso), obter acesso não autorizado a dados ou até mesmo executar código arbitrário na própria máquina host.
Conforme observado pelo quadrinho do XKCD, uma maneira de proteger contra ataques de injeção de SQL é higienizar as entradas do banco de dados, como escapar caracteres especiais, para que eles não possam modificar o comando SQL subjacente e, portanto, não possam causar a execução de código SQL arbitrário. Se você usar consultas parametrizadas, como SqlParameter
no ADO.NET, a entrada será, no mínimo, higienizada automaticamente para proteger contra injeção de SQL.
No entanto, a limpeza das entradas no nível do aplicativo pode não parar as técnicas mais avançadas de injeção de SQL. Por exemplo, existem maneiras de contornar a mysql_real_escape_string
função PHP . Para proteção adicional, muitos sistemas de banco de dados suportam instruções preparadas . Se implementadas corretamente no back-end, as instruções preparadas podem impossibilitar a injeção de SQL tratando as entradas de dados como semanticamente separadas do restante do comando.