Injeção SQL

Se você pegar a entrada de um usuário por meio de uma página da web e inseri-la em um banco de dados SQL, há uma chance de você ter se deixado vulnerável a um problema de segurança conhecido como SQL Injection. Este capítulo irá ensiná-lo a evitar que isso aconteça e ajudá-lo a proteger seus scripts e instruções SQL em seus scripts do lado do servidor, como um script PERL.

A injeção geralmente ocorre quando você pede a entrada de um usuário, como seu nome e, em vez de um nome, eles fornecem uma instrução SQL que você executará sem saber em seu banco de dados. Nunca confie nos dados fornecidos pelo usuário, processe esses dados somente após a validação; como regra, isso é feito porPattern Matching.

No exemplo abaixo, o name é restrito aos caracteres alfanuméricos mais sublinhados e a um comprimento entre 8 e 20 caracteres (modifique essas regras conforme necessário).

if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) {
   $result = mysql_query("SELECT * FROM CUSTOMERS 
      WHERE name = $matches[0]");
} else {
   echo "user name not accepted";
}

Para demonstrar o problema, considere este trecho -

// supposed input
$name = "Qadir'; DELETE FROM CUSTOMERS;";
mysql_query("SELECT * FROM CUSTOMSRS WHERE name='{$name}'");

A chamada de função deve recuperar um registro da tabela CUSTOMERS onde a coluna de nome corresponde ao nome especificado pelo usuário. Sob circunstâncias normais,$nameconteria apenas caracteres alfanuméricos e talvez espaços, como a string ilia. Mas aqui, ao anexar uma consulta inteiramente nova a $ name, a chamada para o banco de dados se transforma em um desastre; a consulta DELETE injetada remove todos os registros da tabela CUSTOMERS.

Felizmente, se você usa MySQL, o mysql_query()função não permite o empilhamento de consultas ou a execução de várias consultas SQL em uma única chamada de função. Se você tentar empilhar consultas, a chamada falhará.

No entanto, outras extensões de banco de dados PHP, como SQLite e PostgreSQL felizmente execute consultas empilhadas, executando todas as consultas fornecidas em uma string e criando um sério problema de segurança.

Prevenção de injeção de SQL

Você pode lidar com todos os caracteres de escape de forma inteligente em linguagens de script como PERL e PHP. A extensão MySQL para PHP fornece a funçãomysql_real_escape_string() para escapar de caracteres de entrada que são especiais para MySQL.

if (get_magic_quotes_gpc()) {
   $name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM CUSTOMERS WHERE name='{$name}'");

O dilema LIKE

Para resolver o dilema LIKE, um mecanismo de escape personalizado deve converter os caracteres '%' e '_' fornecidos pelo usuário em literais. Usaraddcslashes(), uma função que permite especificar um intervalo de caracteres para o escape.

$sub = addcslashes(mysql_real_escape_string("%str"), "%_");
// $sub == \%str\_
mysql_query("SELECT * FROM messages 
   WHERE subject LIKE '{$sub}%'");