MySQL - e SQL Injection
Se você pegar a entrada do usuário por meio de uma página da Web e inseri-la em um banco de dados MySQL, há uma chance de que você tenha se deixado abrir para um problema de segurança conhecido como SQL Injection. Este capítulo irá ensiná-lo como ajudar a evitar que isso aconteça e ajudá-lo a proteger seus scripts e instruções MySQL.
A injeção SQL 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 MySQL que você executará inadvertidamente em seu banco de dados.
Nunca confie nos dados fornecidos por um usuário, processe esses dados somente após a validação; como regra, isso é feito por correspondência de padrões. No exemplo a seguir, o nome de usuário está restrito a 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 users WHERE username = $matches[0]");
} else {
echo "username not accepted";
}
Para demonstrar esse problema, considere o seguinte trecho.
// supposed input
$name = "Qadir'; DELETE FROM users;";
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
A chamada de função deve recuperar um registro da tabela de usuários, onde a coluna de nome corresponde ao nome especificado pelo usuário. Em circunstâncias normais, $ name conteria apenas caracteres alfanuméricos e talvez espaços. Mas aqui, anexando 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 dos usuários.
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 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 executa 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 users WHERE name = '{$name}'");
O dilema LIKE
Para resolver o dilema LIKE, um mecanismo de escape personalizado deve converter% e _ caracteres 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("%something_"), "%_");
// $sub == \%something\_
mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");