Saltar para o conteúdo

Injeção de SQL: diferenças entre revisões

Origem: Wikipédia, a enciclopédia livre.
Conteúdo apagado Conteúdo adicionado
m
 
(Há 28 revisões intermédias de 21 utilizadores que não estão a ser apresentadas)
Linha 1: Linha 1:
[[Ficheiro:SQL injection.png|miniaturadaimagem|260x260px|Exemplo de ataque usando comandos SQL.]]
{{Reciclagem|data=março de 2010}}
'''Injeção de SQL''' (do [[Língua inglesa|inglês]] ''SQL Injection'') é um tipo de ameaça de [[segurança]] que se aproveita de [[Vulnerabilidade (computação)|vulnerabilidades em sistemas]] que trabalham com [[bases de dados]] realizando ataques com [[SQL|comandos SQL]]; onde o atacante consegue inserir uma [[instruções|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.<ref name=":0">{{Citar periódico|ultimo=TecMundo|data=2017-01-05|titulo=SQL Injection: saiba tudo sobre um ataque simples que pode ser devastador|url=https://www.tecmundo.com.br/tecmundo-explica/113195-sql-injection-saiba-tudo-ataque-simples-devastador.htm|jornal=TecMundo - Descubra e aprenda tudo sobre tecnologia|lingua=pt-BR}}</ref>
{{Sem-fontes|data=agosto de 2010| arte=| Brasil=| ciência=| geografia=| música=| Portugal=| sociedade=|1=|2=|3=|4=|5=|6=}}


== Danos ==
A '''Injeção de SQL''', mais conhecida através do termo americano ''SQL Injection'', é um tipo de ameaça de [[segurança]] que se aproveita de falhas em sistemas que interagem com [[bases de dados]] via [[SQL]]. A injeção de SQL ocorre quando o atacante consegue inserir uma série de [[instruções]] SQL dentro de uma consulta (query) através da manipulação das entradas de dados de uma aplicação.
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 [[Servidor|computador servidor]].<ref name=":0" /> Dependendo da versão do banco, também é possível inserir comandos maliciosos e conseguir permissão total ([[Superusuário|acesso root]]) à máquina em que o banco está em execução.<ref name=":0" />


Veja abaixo um exemplo de um sistema de login (na [[linguagem de programação]] [[PHP]]) com vulnerabilidade:<ref name=":1">{{Citar web|url=http://www.zoomdigital.com.br/sql-injection-o-que-e-e-como-evitar/|titulo=SQL Injection: o que é e como evitar|data=|acessodata=2018-04-27|obra=Destaques|publicado=Zoom Digital|ultimo=Cardoso|primeiro=Philipe}}</ref><syntaxhighlight lang="php">
== Funcionamento ==
$usuario = $_POST['usuario'];
$senha = $_POST['senha'];
$sql = "SELECT * FROM usuarios WHERE usuario = '".$usuario."' AND senha = '".$senha."' ";
$processa = mysql_query($sql);
</syntaxhighlight>Esta instrução "SQL query" de login funciona da seguinte forma:<syntaxhighlight lang="text">
SELECIONE TODOS (select *) da tabela "usuarios" (nome da tabela) ONDE obrigatoriamente o "usuario" digitado no formulário é igual ao cadastrado no banco de dados "E" (and) a "senha" digitada no formulário também é igual ao cadastrado;
</syntaxhighlight>...onde as variaveis $usuario e $senha recebem os conteúdos digitados nos campos de um formulário através do método POST.<ref name=":1" /> Imagine que o conteúdo da variável $senha seja:<ref name=":1" />


* $senha = " 'or 1='1 " " 'or 1='1 ".
Para exemplificar o funcionamento da injeção de SQL, consideremos uma instrução [[SQL]] comum:


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.<ref name=":1" />
<source lang="sql">SELECT id, nome, sobrenome FROM autores;</source>

== 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, que representa uma [[SQL#DQL - Linguagem de Consulta de Dados|consulta]] na base de dados, 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 através da inclusão da [[SQL#Cláusulas|cláusula WHERE]], como é visto no exemplo abaixo:


<source lang="sql">SELECT id, nome, sobrenome FROM autores WHERE nome = 'josé' AND sobrenome = 'silva';</source>
<syntaxhighlight lang="sql">SELECT id, nome, sobrenome FROM autores;</syntaxhighlight>Essa instrução representa uma [[SQL#DQL - Linguagem de Consulta de Dados|consulta]] na base de dados, funcionará da seguinte forma:<syntaxhighlight lang="text">
SELECIONE (select) todos os "ids", "nomes" e "sobrenome" DA TABELA (from) "autores" (nome da tabela);
</syntaxhighlight>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 [[SQL#Cláusulas|cláusula WHERE]], como é visto no exemplo abaixo:


<syntaxhighlight lang="sql">SELECT id, nome, sobrenome FROM autores WHERE nome = 'josé' AND sobrenome = 'silva';</syntaxhighlight>Esta instrução de consulta na base de dados, funcionará da seguinte forma:<syntaxhighlight lang="text">
Com base nesta instrução, é fácil supor que "josé" e "silva" são [[string]]s, cujo conteúdo será preenchido pela entrada feita por algum usuário que estiver fazendo uso da aplicação.
SELECIONE (select) todos os "ids", "nomes" e "sobrenome" DA TABELA (from) "autores" (nome da tabela) ONDE (where) os nomes deverão ser iguais a 'josé' E os sobrenomes iguais a 'silva' (condições do filtro);
</syntaxhighlight>Com base nesta instrução, é fácil supor que os itens "josé" e "silva" são do tipo texto ([[string]]s), solicitados por algum usuário que esteja usando a aplicação.


=== Problema ===
Portanto, supondo que a aplicação não faça o tratamento apropriado do conteúdo inserido pelo usuário, o mesmo pode fazer o uso acidental do caractere apóstrofo. Gerando a entrada:
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é''
* nome = ''jo'sé''
Linha 23: Linha 38:
E fazendo com que a aplicação gere o código:
E fazendo com que a aplicação gere o código:


<source lang="sql">SELECT id, nome, sobrenome FROM autores WHERE nome = 'jo'sé' AND sobrenome = 'silva';</source>
<syntaxhighlight lang="sql">SELECT id, nome, sobrenome FROM autores WHERE nome = 'jo'sé' AND sobrenome = 'silva';</syntaxhighlight>


De acordo com a especificação da [[linguagem]] SQL, existe um erro de [[sintaxe]] nessa instrução, uma vez que a string passada para o campo '''nome''' é a apenas palavra "jo", pois a adição de apóstrofo quebrou a delimitação dos apóstrofos originais da consulta. O [[interpretador]] do SQL espera que o restante da instrução seja outros comandos SQL válidos que complementem a instrução principal. No entanto, como "sé" não é um identificador válido, essa instrução não será executada e retornará um erro.
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 ===
Com base neste problema, um possível atacante pode manipular os dados de entrada a fim de gerar um comportamento não esperado na base de dados.
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:

Para exemplificar este conceito, consideremos na mesma consulta apresentada, a entrada dos seguintes dados pela aplicação:


* nome = ''jo'; DROP TABLE autores ; --''
* nome = ''jo'; DROP TABLE autores ; --''
* sobrenome = ''silva''
* sobrenome = ''silva''


A instrução completa ficaria:
Fazendo com que a aplicação gere o código:


<source lang="sql">SELECT id, nome, sobrenome FROM autores WHERE nome = 'jo'; DROP TABLE autores ; --' AND sobrenome = 'silva';</source>
<syntaxhighlight lang="sql">SELECT id, nome, sobrenome FROM autores WHERE nome = 'jo'; DROP TABLE autores ; --' AND sobrenome = 'silva';</syntaxhighlight>A instrução personalizada funcionará da seguinte forma:<syntaxhighlight lang="text">
SELECIONE (select) todos os "ids", "nomes" e "sobrenome" DA TABELA (from) "autores" (nome da tabela) ONDE (where) os nomes deverão ser iguais a 'josé'; (quebra, novo comando) Em seguida EXCLUA (drop) a tabela "autores"; -- (continuação) E os sobrenomes iguais a 'silva' (condições do filtro);
</syntaxhighlight>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.
Neste caso, a instrução será executada normalmente, pois não há um erro de sintaxe, no entanto, com a adição do [[caractere]] [[ponto-e-vírgula]], a instrução foi dada como finalizada de modo prematuro dando espaço para uma nova instrução. Essa nova instrução, que poderia ser qualquer uma escolhida pelo atacante, pode ser a responsável por 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 pode ser visto no exemplo apresentado.


=== Possíveis soluções ===
Aparentemente um método para prevenir esse problema seria a remoção de apóstrofos dos campos de inserção da aplicação, ou simplesmente não executando a query nestas situações. Isso é verdade, mas existem várias dificuldades com esse método tanto quanto soluções. Primeiro, nem todos os usuários inserem dados em forma de strings. Se o usuário puder selecionar um autor pelo 'id' (presumivelmente um [[número]]) por exemplo, nossa query aparecerá como abaixo:
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:


<source lang="sql">SELECT id, forename, surname FROM authors WHERE id=1234</source>
<syntaxhighlight lang="sql">SELECT id, forename, surname FROM authors WHERE id=1234</syntaxhighlight>A instrução funcionará da seguinte forma:<syntaxhighlight lang="text">
SELECIONE (select) todos os "ids", "forenames e "surnames" DA TABELA (from) "autors" (nome da tabela) ONDE (where) id deverá ser igual a "1234";
</syntaxhighlight>


Nesta situação, o atacante pode simplesmente adicionar uma instrução SQL no fim do 'input' numérico. Verificando os [[dialeto]]s de SQL, vários delimitadores podem ser usados no [[Microsoft]] Jet [[DBMS]] engine, por exemplo, datas podem ser delimitadas com o caracter [[sustenido]]. Portanto, escapando da execução da adição de apóstrofos, não necessariamente uma solução como demonstrado anteriormente.
Nesta situação, o atacante pode simplesmente adicionar uma instrução SQL no fim do 'input' numérico. Verificando as variações do SQL ([[dialeto]]s), 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]] em [[Active Server Pages]] ([[ASP]]), que acessa um servidor de banco de dados SQL e tenta autenticar o acesso em uma aplicação fictícia.
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, em que um usuário insere o username e o password para autenticaçã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]]:


(...)
(...)
<source lang="java">
<syntaxhighlight lang="java">
function Login( cn )
function Login( cn )
{
{
Linha 80: Linha 99:
cn.close();
cn.close();
}
}
</syntaxhighlight>
</source>


A parte critica é a parte do 'process_login.ascp' que cria uma 'query string':
A parte critica é o código "var sql" que cria uma SQL query string:


<source lang="java">
<syntaxhighlight lang="java">
var sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
var sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
</syntaxhighlight>A instrução funcionará da seguinte forma:<syntaxhighlight lang="text">
</source>
SELECIONE todos os itens (select *) DA TABELA (from) "users" ONDE (where) o username é igual ao texto "username" digitado no formulario E (and) password igual ao texto "password" digitado;
</syntaxhighlight>Se o usuário digitar no formulário os seguintes dados:


<syntaxhighlight lang="java">
Se o usuário inserir os seguintes dados:

<source lang="java">
* Username: '; drop table users--
* Username: '; drop table users--
* Password:
* Password:
</syntaxhighlight>
</source>


A instrução SQL será modificada da seguinte forma:<syntaxhighlight lang="asp">
... a tabela 'users' será apagada, negando o acesso para todos os usuários. A seqüência de caracteres '--' é o comentário de uma linha de SQL, a o ';' denota o fim de uma query e o começo de outra. O '--' no fim do campo username é requerido para que a query em questão seja executada sem erros.
var sql = "SELECT * FROM users WHERE username = '" + ; (quebra, novo comando) drop table users-- + "' AND password = '" + password + "'";
</syntaxhighlight>A instrução funcionará da seguinte forma:<syntaxhighlight lang="text">
SELECIONE todos os itens (select *) DA TABELA (from) "users" ONDE (where) o username é igual ; (quebra, novo comando) EXCLUA (drop) a TABELA users (nome da tabela) -- (comentário, continuação) E (and) password igual ao texto "password" digitado;
</syntaxhighlight>


... a tabela 'users' será apagada, negando o acesso para todos os usuários.
O atacante pode logar como qualquer usuário, se souber o nome do usuário, usando o input abaixo:

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'--
* Username: admin'--
Linha 108: Linha 133:
* Username: ' union select 1, 'fictional_user', 'some_password', 1--
* 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.
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.<ref name=":0" />


== Injeção de SQL Avançado ==
== Injeção de SQL Avançado ==
Do inglês ''Advanced Sql Injection'', esse método consiste em explorar a injeção de instruções SQL através do método GET da página.
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.
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 ==
=== Injeção "Cega" de SQL ===
Conhecido como ''Blind Sql Injection'', esse 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 do 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 booleana.
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:
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:
Linha 128: Linha 155:
Sabe-se que é um retorno verdadeiro porque a página é carregada normalmente, ao contrário de quando o retorno é falso.
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 - Advanced SQL Injection|Havij]]..
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:<ref name=":1" /><syntaxhighlight lang="php">
if (isset($_GET['pagina'])) {
$arquivo = $_GET['pagina'];
}else {
$arquivo = 'home.php';
}
include ($arquivo);
</syntaxhighlight>... 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().<ref name=":1" />{{Referências|título=Referências}}


== Ver também ==
== Ver também ==

* [[Exploit (segurança de computadores)]]
* [[Segurança da informação]]
* [[Segurança da informação]]

* [[SQL]]
* [[Modelagem de ameaças]]


[[Categoria:SQL]]
[[Categoria:SQL]]
[[Categoria:Administração de dados]]
[[Categoria:Administração de dados]]
[[Categoria:Falhas em segurança de computadores]]
[[Categoria:Falhas em segurança de computadores]]

{{Bom interwiki|de}}

Edição atual tal como às 18h53min de 7 de outubro de 2024

Exemplo de ataque usando comandos 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.[1]

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.[1] 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.[1]

Veja abaixo um exemplo de um sistema de login (na linguagem de programação PHP) com vulnerabilidade:[2]

$usuario = $_POST['usuario'];
$senha = $_POST['senha'];
$sql = "SELECT * FROM usuarios WHERE usuario = '".$usuario."' AND senha = '".$senha."' ";
$processa = mysql_query($sql);

Esta instrução "SQL query" de login funciona da seguinte forma:

SELECIONE TODOS (select *) da tabela "usuarios" (nome da tabela) ONDE obrigatoriamente o "usuario" digitado no formulário é igual ao cadastrado no banco de dados "E" (and) a "senha" digitada no formulário também é igual ao cadastrado;

...onde as variaveis $usuario e $senha recebem os conteúdos digitados nos campos de um formulário através do método POST.[2] Imagine que o conteúdo da variável $senha seja:[2]

  • $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.[2]

Funcionamento

[editar | editar código-fonte]

Para exemplificar o funcionamento da injeção de SQL, consideremos o comando básico de consuta abaixo, a instrução SQL query:

SELECT id, nome, sobrenome FROM autores;

Essa instrução representa uma consulta na base de dados, funcionará da seguinte forma:

SELECIONE (select) todos os "ids", "nomes" e "sobrenome" DA TABELA (from) "autores" (nome da tabela);

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:

SELECT id, nome, sobrenome FROM autores WHERE nome = 'josé' AND sobrenome = 'silva';

Esta instrução de consulta na base de dados, funcionará da seguinte forma:

SELECIONE (select) todos os "ids", "nomes" e "sobrenome" DA TABELA (from) "autores" (nome da tabela) ONDE (where) os nomes deverão ser iguais a 'josé' E os sobrenomes iguais a 'silva' (condições do filtro);

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.

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:

SELECT id, nome, sobrenome FROM autores WHERE nome = 'jo'' AND sobrenome = 'silva';

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.

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:

SELECT id, nome, sobrenome FROM autores WHERE nome = 'jo'; DROP TABLE autores ; --' AND sobrenome = 'silva';

A instrução personalizada funcionará da seguinte forma:

SELECIONE (select) todos os "ids", "nomes" e "sobrenome" DA TABELA (from) "autores" (nome da tabela) ONDE (where) os nomes deverão ser iguais a 'josé'; (quebra, novo comando) Em seguida EXCLUA (drop) a tabela "autores"; -- (continuação) E os sobrenomes iguais a 'silva' (condições do filtro);

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

[editar | editar código-fonte]

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:

SELECT id, forename, surname FROM authors WHERE id=1234

A instrução funcionará da seguinte forma:

SELECIONE (select) todos os "ids", "forenames e "surnames" DA TABELA (from) "autors" (nome da tabela) ONDE (where) id deverá ser igual a "1234";

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:

(...)

function Login( cn )
{
   var username;
   var password;
   username = Request.form("username");
   password = Request.form("password");
   var rso = Server.CreateObject("ADODB.Recordset");
   var sql = "select * from users where username = '" + username + "' and password = '" + password + "'";
   trace( "query: " + sql );
   rso.open( sql, cn );
   if (rso.EOF)  {
      rso.close();
   }
}

function Main()
{
//Set up connection
   var username
   var cn = Server.createobject( "ADODB.Connection" );
   cn.connectiontimeout = 20;
   cn.open( "localserver", "sa", "password" );
   username = new String( Request.form("username") );
   if( username.length > 0)  {
      Login( cn );
   }
   cn.close();
}

A parte critica é o código "var sql" que cria uma SQL query string:

var sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";

A instrução funcionará da seguinte forma:

SELECIONE todos os itens (select *) DA TABELA (from) "users" ONDE (where) o username é igual ao texto "username" digitado no formulario E (and) password igual ao texto "password" digitado;

Se o usuário digitar no formulário os seguintes dados:

* Username: '; drop table users--
* Password:

A instrução SQL será modificada da seguinte forma:

var sql = "SELECT * FROM users WHERE username = '" + ; (quebra, novo comando) drop table users-- + "'  AND password = '" + password + "'";

A instrução funcionará da seguinte forma:

SELECIONE todos os itens (select *) DA TABELA (from) "users" ONDE (where) o username é igual ; (quebra, novo comando) EXCLUA (drop) a TABELA users (nome da tabela) -- (comentário, continuação) E (and) password igual ao texto "password" digitado;

... 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.[1]

Injeção de SQL Avançado

[editar | editar código-fonte]

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

[editar | editar código-fonte]

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

[editar | editar código-fonte]

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:[2]

if (isset($_GET['pagina'])) { 
    $arquivo = $_GET['pagina']; 
}else {
    $arquivo = 'home.php'; 
} 
include ($arquivo);

... 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().[2]

Referências

  1. a b c d TecMundo (5 de janeiro de 2017). «SQL Injection: saiba tudo sobre um ataque simples que pode ser devastador». TecMundo - Descubra e aprenda tudo sobre tecnologia 
  2. a b c d e f Cardoso, Philipe. «SQL Injection: o que é e como evitar». Destaques. Zoom Digital. Consultado em 27 de abril de 2018