tutoriais mais recente desenvolvimento web
 

SQL injeção


Uma Injeção SQL pode destruir a sua base de dados.


SQL em páginas da Web

Nos capítulos anteriores, você aprendeu para recuperar dados de banco de dados (e atualização), usando SQL.

Quando o SQL é usado para exibir os dados em uma página da web, é comum deixar de entrada usuários da Internet os seus próprios valores de pesquisa.

Desde instruções SQL são apenas texto, é fácil, com um pequeno pedaço de código de computador, para alterar dinamicamente instruções SQL para fornecer ao usuário com os dados selecionados:

Código servidor

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

O exemplo acima, cria uma instrução SELECT, adicionando uma variável (txtUserId) para uma cadeia de seleção. A variável é obtido a partir da entrada do usuário (Request) para a página.

O restante deste capítulo descreve os potenciais perigos de usar a entrada do usuário em instruções SQL.


SQL Injection

injeção de SQL é uma técnica onde os usuários mal-intencionados pode injetar comandos SQL em uma instrução SQL, através da entrada de página da web.

comandos SQL injetadas podem alterar instrução SQL e comprometer a segurança de uma aplicação web.


SQL Injection Baseado em 1 = 1 é sempre verdadeiro

Olhe para o exemplo acima, mais uma vez.

Vamos dizer que o propósito original do código era criar uma instrução SQL para selecionar um usuário com um determinado ID de usuário.

Se não há nada para impedir que um usuário entrar "wrong" de entrada, o usuário pode entrar em alguns "smart" de entrada como esta:

ID do usuário:

Resultado servidor

SELECT * FROM Users WHERE UserId = 105 or 1=1

O SQL acima é válida. Ele irá retornar todas as linhas da tabela usuários, uma vez que 1 = 1 é sempre verdadeiro.

Será que o exemplo acima parece perigoso? O que se a tabela de usuários contém nomes e senhas?

A instrução SQL acima é da mesma forma como isto:

SELECT UserId, Name, Password FROM Users WHERE UserId = 105 or 1=1

Um hacker inteligente pode ter acesso a todos os nomes de usuário e senhas em um banco de dados, simplesmente inserindo 105 ou 1 = 1 na caixa de entrada.


SQL Injection Baseado em ""="" é sempre verdadeira

Aqui é uma construção comum, usado para verificar o login do usuário a um web site:

Nome de usuário:

Senha:

Código servidor

uName = getRequestString("UserName");
uPass = getRequestString("UserPass");

sql = "SELECT * FROM Users WHERE Name ='" + uName + "' AND Pass ='" + uPass + "'"

Um hacker inteligente pode ter acesso aos nomes de usuário e senhas em um banco de dados, simplesmente inserindo "ou ""=" na caixa de texto o nome de usuário ou senha.

O código no servidor vai criar uma instrução SQL válida como este:

Resultado

SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""

O SQL resultado é válido. Ele irá retornar todas as linhas da tabela usuários, desde onde "" = "" sempre é verdade.


SQL Injection Com base em instruções SQL em lote

A maioria dos bancos de dados suportam instrução SQL em lote, separados por ponto e vírgula.

Exemplo

SELECT * FROM Users; DROP TABLE Suppliers

O SQL acima irá retornar todas as linhas na tabela de usuários e, em seguida, excluir a tabela chamados Fornecedores.

Se tivéssemos o seguinte código do servidor:

Código servidor

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

E a seguinte entrada:

ID do usuário:

O código no servidor iria criar uma instrução SQL válida como este:

Resultado

SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers

Parâmetros para a Protecção

Alguns desenvolvedores web usar uma "blacklist" de palavras ou caracteres para pesquisar na entrada SQL, para evitar ataques de injeção SQL.

Esta não é uma idéia muito boa. Muitas destas palavras (como apagar ou gota) e caracteres (como o ponto e vírgula e aspas), são utilizados em linguagem comum, e deve ser permitido em muitos tipos de entrada.

(Na verdade ele deve ser perfeitamente legal para introduzir uma instrução SQL em um campo de banco de dados.)

A única forma comprovada de proteger um web site a partir de ataques de injeção SQL, é a utilização de parâmetros SQL.

parâmetros SQL são valores que são adicionados a uma consulta SQL em tempo de execução, de uma forma controlada.

Exemplo Navalha ASP.NET

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = @0";
db.Execute(txtSQL,txtUserId);

Note-se que os parâmetros são representados na instrução SQL por um @ marcador.

O motor de SQL verifica cada parâmetro para garantir que ele está correto para a sua coluna e são tratados literalmente, e não como parte do SQL para ser executado.

Outro exemplo

txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
db.Execute(txtSQL,txtNam,txtAdd,txtCit);

Você aprendeu apenas para evitar a injeção de SQL. Uma das principais vulnerabilidades do site.


Exemplos

Os exemplos a seguir mostra como criar consultas parametrizadas em algumas linguagens web comuns.

Instrução SELECT no ASP.NET:

txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserID);
command.ExecuteReader();

INSERT INTO declaração em ASP.NET:

txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
command = new SqlCommand(txtSQL);
command.Parameters.AddWithValue("@0",txtNam);
command.Parameters.AddWithValue("@1",txtAdd);
command.Parameters.AddWithValue("@2",txtCit);
command.ExecuteNonQuery();

INSERT INTO declaração em PHP:

$stmt = $dbh->prepare("INSERT INTO Customers (CustomerName,Address,City)
VALUES (:nam, :add, :cit)");
$stmt->bindParam(':nam', $txtNam);
$stmt->bindParam(':add', $txtAdd);
$stmt->bindParam(':cit', $txtCit);
$stmt->execute();