Injeção de SQL
# Injeção de SQL

Injeção de SQL (do inglês SQL Injection) é um tipo de ameaça de segurança que se aproveita de vulnerabilidades em sistemas que trabalham com bases de dados realizando ataques com comandos SQL; onde o atacante consegue inserir uma instrução SQL personalizada e indevida através da entrada de dados de uma aplicação, como formulários ou URL de uma aplicação online.

## Danos

Um usuário por meio de ataques com injeção SQL, é possível obter qualquer tipo de dado sigiloso mantido no banco de dados de um computador servidor. Dependendo da versão do banco, também é possível inserir comandos maliciosos e conseguir permissão total (acesso root) à máquina em que o banco está em execução.
Veja abaixo um exemplo de um sistema de login (na linguagem de programação PHP) com vulnerabilidade:
Esta instrução "SQL query" de login funciona da seguinte forma:
...onde as variaveis $usuario e $senha recebem os conteúdos digitados nos campos de um formulário através do método POST. Imagine que o conteúdo da variável $senha seja:
* $senha = " 'or 1='1 " " 'or 1='1 ".
Se nenhuma verificação de dados (validação) for realizada, o usuário atacante conseguirá efetuar o login no sistema sem ter um cadastro válido, devido a uma falha gerada na instrução SQL.

## Funcionamento

Para exemplificar o funcionamento da injeção de SQL, consideremos o comando básico de consuta abaixo, a instrução SQL query:
Essa instrução representa uma consulta na base de dados, funcionará da seguinte forma:
Esta retorna todos os registros das colunas "id", "nome" e "sobrenome" da tabela "autores". A partir desta mesma instrução, os registros a serem retornados podem ser restritos, usando um filtro com a inclusão da cláusula WHERE, como é visto no exemplo abaixo:
Esta instrução de consulta na base de dados, funcionará da seguinte forma:
Com base nesta instrução, é fácil supor que os itens "josé" e "silva" são do tipo texto (strings), solicitados por algum usuário que esteja usando a aplicação.

### Problema

Portanto, supondo que a aplicação não faça o entendimento apropriado do conteúdo inserido pelo usuário, o mesmo pode fazer o uso acidental do caractere apóstrofo. Gerando a entrada:
* nome = jo'sé
* sobrenome = silva
E fazendo com que a aplicação gere o código:
De acordo com a especificação da linguagem SQL, o uso de apóstrofo na consulta causa uma quebra na consulta, ocorrendo um erro de sintaxe nessa instrução, a string será considerada no campo nome apenas a palavra "jo" (dentro da primeira dupla de apóstrofo 'texto'). O interpretador do SQL espera que a continuação da instrução sejam outros comandos SQL válidos que completam a instrução principal. No entanto, como a outra parte do texto, o "sé" não é um identificador válido, essa instrução não será executada e retornará um erro inesperado.

### Ataque

Assim, um atacante pode personalizar os dados de entrada a fim de gerar um comportamento inesperado na base de dados. Para exemplificar este conceito, consideremos na consulta apresentada, a entrada dos seguintes dados através da aplicação:
* nome = jo'; DROP TABLE autores ; --
* sobrenome = silva
A instrução completa ficaria:
A instrução personalizada funcionará da seguinte forma:
Neste caso, a instrução será executada normalmente, pois a adição do caractere ponto-e-vírgula ";" na instrução representa o fim de uma SQL query e o começo de outra. Assim no exemplo acima, a SQL query será reconhecida como completa - não ocorrendo erro de sintaxe - de modo prematuro dando espaço para uma nova instrução. de livre escolha do atacante. Podendo retornar dados confidenciais armazenados na base de dados ou de executar instruções que comprometam o sistema, como a remoção de dados e/ou tabelas, como apresentado no exemplo acima.
A seqüência de caracteres "--" representa um comentário em uma linha de SQL. O "--" no fim do campo username é obrigatório para que a SQL query continue sendo executada sem erros.

### Possíveis soluções

Aparentemente um método para prevenir esse problema seria a retirada dos apóstrofos dos campos de entrada da aplicação, ou simplesmente ignorar a SQL query nestas situações. Mas, apareceram outras dificuldades com esse método. Primeiro, nem todos os usuários inserem dados em forma de strings. Por exemplo, se o usuário tiver a opção de selecionar um autor pelo 'id' (presumivelmente um número), nossa query aparecerá como abaixo:
A instrução funcionará da seguinte forma:
Nesta situação, o atacante pode simplesmente adicionar uma instrução SQL no fim do 'input' numérico. Verificando as variações do SQL (dialetos), por exemplo, vários delimitadores podem ser usados no Microsoft Jet DBMS engine, onde as datas podem ser delimitadas com o caracter sustenido. Assim, escapando da execução com apóstrofos, não necessariamente uma solução como demonstrado anteriormente.
Pode-se ilustrar esse ponto usando um exemplo de página de login na linguagem Active Server Pages (ASP), que acessa um servidor de banco de dados SQL e tenta autenticar o acesso em uma aplicação.
Abaixo está um pedaço de código de uma página de formulário (process_login.ascp), onde um usuário insere o username e o password para autenticação:
A parte critica é o código "var sql" que cria uma SQL query string:
A instrução funcionará da seguinte forma:
Se o usuário digitar no formulário os seguintes dados:
A instrução SQL será modificada da seguinte forma:
A instrução funcionará da seguinte forma:
... a tabela 'users' será apagada, negando o acesso para todos os usuários.
O atacante pode entrar no sistema (logar) como qualquer usuário, se souber o nome do usuário, digitando o comando abaixo no formulário:
* Username: admin'--
O atacante pode logar como o primeiro usuário da tabelas 'users', com a inserção abaixo:
* Username: ' or 1=1--
O atacante pode ainda logar como um usuário completamente fictício com o input abaixo:
* Username: ' union select 1, 'fictional_user', 'some_password', 1--
A razão para que isso funcione, é que a aplicação acredita que a linha 'constante' que o atacante especificou é parte do 'recordset' recuperado da base de dados.
Assim funciona uma injeção manual de SQL. Também podem ser usadas ferramentas que automatizam as consultas para vários tipo de banco de dados, descobrindo a vulnerabilidade injetável.

## Injeção de SQL Avançado

Termo do inglês Advanced Sql Injection, método consiste em explorar a injeção de instruções SQL através do método GET existente na URL da página.
Através do mesmo, o invasor pode conseguir por exemplo, os dados de usuário e senha do painel administrativo do site.

### Injeção "Cega" de SQL

Termo do inglês Blind Sql Injection, método assemelha-se ao anterior, a diferença é que nesse caso a página possui uma certa segurança e o invasor não visualiza os dados da base de dados através da página web. O invasor descobre os dados desejados de 1 em 1 caractere, utilizando a função SUBSTRING do SQL em conjunto com uma verificação booliana.
Por exemplo, supondo que o usuário do sistema seja JOAO, o invasor vai ter um retorno falso com a seguinte tentativa injetada na cláusula WHERE:
... AND SELECT 1 FROM USUARIO WHERE SUBSTRING(USUARIO,1,1) = 'A'
No entanto, vai receber um retorno verdadeiro quando chegar na letra J:
... AND SELECT 1 FROM USUARIO WHERE SUBSTRING(USUARIO,1,1) = 'J'
Sabe-se que é um retorno verdadeiro porque a página é carregada normalmente, ao contrário de quando o retorno é falso.
Muitos invasores conseguem dados de usuário e senha sem ao menos ter conhecimento da teoria do método, mas apenas por utilizar a ferramenta Havij.

### Injeção Duplamente "Cega" de SQL

Termo do inglês Double Blind Sql Injection, neste método além do invasor não visualizar os dados da base de dados (usuário e senha, por exemplo) através da página web (expostos no html, visível em tela), ele também não obtêm diferença visível na página em caso de retorno verdadeiro. Enquanto no método anterior o invasor sabe se sua verificação booleana é verdadeira ou falsa pelo carregamento ou não da página, nesse método chamado de duplamente cego o invasor faz uma comparação de tempo de carregamento de página para saber se sua comparação que ele está enviando ao banco de dados (via método GET, por exemplo) é verdadeira ou falsa.
Ou seja, se a página demora 1 segundo para carregar o site "and 1=1" e demora metade do tempo para carregar " and 1=0", o invasor considera que o servidor está aceitando os comandos de injeção de SQL e sempre que tiver 1 segundo de tempo de carregamento significa que teve um retorno verdadeiro, dessa forma o invasor consegue obter caractere por caractere da senha do administrador do site.
Analisemos outro exemplo de vulnerabilidade, onde diversos sites usam sistemas que organizam as páginas internas usando a função include, usando uma variável do método $_GET:
... verifica se a variável pagina ($_GET['pagina']) existe usando a função isset, em seguida guarda o valor da pagina na variável $arquivo. Caso não exista uma variável, a variável $arquivo recebe a página inicial "home.php". Por fim é exibido a página usando a função include.