Entendendo o SQL Injection
Olá a todos, explicarei o que é SQL Injection e demonstrarei algumas técnicas para evita-lo.
Mas o que é SQL Injection?
SQL Injection é uma técnica usada por hackers (crackers) para executar comandos SQL não autorizados e assim obter vantagem de aplicações que utilizam queries SQL dinâmicas.
Exemplo:
Considere a seguinte query:
Código PHP:
<?php
mysql_connect('localhost', 'user', 'pass') OR die(mysql_error());
$query = "SELECT * FROM users WHERE user='".$_POST['username']."' AND password='".$_POST['password']."'";
mysql_query($query);
?>
Nós não verificamos os dados enviados pelo usuário, $_POST['username'] e $_POST['password'], sendo assim ele pode enviar qualquer coisa, por exemplo:
Código PHP:
$_POST['username'] = 'admin';
$_POST['password'] = "' OR ''='";
Código:
SELECT * FROM users WHERE user='admin' AND password=' ' OR ' '=' '
Exemplo 2:
O SQL Injection pode ser bem mais perigoso como o seguinte exemplo.
Código PHP:
<?php
mysql_connect('localhost', 'user', 'pass') OR die(mysql_error());
$query = "SELECT * FROM users WHERE name = '".$_POST['name']."'";
mysql_query($query);
?>
Código PHP:
$_POST['name'] = "a';DROP TABLE users";
Código:
SELECT * FROM users WHERE name = 'a'; DROP TABLE users
Como Evitar o SQL injection
Para evitar é necessário que sempre sejam validados os dados enviados pelo usuário. O PHP nos fornece uma função para tratar este problema. É a mysql_real_escape_string()
Exemplo:
Podemos solucionar o SQL Injection do primeiro exemplo da seguinte maneira:
Código PHP:
<?php
mysql_connect('localhost', 'user', 'pass') OR die(mysql_error());
$user = mysql_real_escape_string($_POST['username']);
$pass = mysql_real_escape_string($_POST['password']);
$query = "SELECT * FROM users WHERE user='$user' AND password='$pass' ";
mysql_query($query);
?>
Código:
SELECT * FROM users WHERE user='admin' AND password=' ' OR ' '=' ''
e elá não permitirá mais que qualquer um faça o login sem possuir uma senha válida.
A melhor função para proteger seus sistemas em PHP e MySQL contra SQL Injection é a mysql_real_escape_string(), ela escapa os caracteres especiais como aspas simples e duplas antes de enviar para o banco de dados. Porém esta função não funciona em todas as versões do PHP, então na função que iremos criar temos quer verificar se ela existe, e caso não exista vamos utilizar a função mysql_escape_string().
Também devemos ter em mente que se a diretiva get_magic_quotes_gpc() estiver ON ele irá acrescentar barras invertidas automaticamente antes de aspas simples e duplas, o problema é que ele irá enviar para o banco de dados com as barras invertidas, estragando o texto. Para contornar isso basta usar a função stripslashes() para remover essas barras invertidas.
Então vamos montar a nossa função com o nome de anti_sql_injection():
Código PHP:
1 function anti_sql_injection($str) {
2 if (!is_numeric($str)) {
3 $str = get_magic_quotes_gpc() ? stripslashes($str) : $str;
4 $str = function_exists('mysql_real_escape_string') ? mysql_real_escape_string($str) : mysql_escape_string($str);
5 }
6 return $str;
7 }
Note que em nossa função primeiro verificamos se a o valor informado não é numérico, ou seja, que precisa ser tratado, em seguida verificamos se a diretiva get_magic_quotes_gpc() está ativada, se estiver usamos a função stripslashes(). Em seguida verificamos se existe a função mysql_real_escape_string(), se existir usamos ela, caso contrário usamos a função mysql_escape_string().
Veja um exemplo de como usar a função:
Código PHP:
01 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
02 $usuario = trim($_POST['usuario']);
03 $senha = trim($_POST['senha']);
04
05 $sql = 'SELECT COUNT(id_usuario) ';
06 $sql .= 'FROM usuarios ';
07 $sql .= 'WHERE usuario = \'' . anti_sql_injection($usuario) . '\' ';
08 $sql .= 'AND senha = \'' . anti_sql_injection($senha) . '\' ';
09
10 $query = mysql_query($sql) or die('Erro na consulta: ' . mysql_error());
11 $total = mysql_result($query, 0);
12 if ($total > 0) {
13 echo 'Usuário e senha corretos.';
14 } else {
15 echo 'Usuário e/ou senha inválidos.';
16 }
17 }
Comment