sexta-feira, 10 de fevereiro de 2012

Se protegendo de 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);
?>

Ela pode ser usada para autenticar um usuário, como em um login.
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 ''='";


A query ficará assim:

Código:

SELECT * FROM users WHERE user='admin' AND password=' ' OR ' '=' '
Ela permite que qualquer um faça o login sem uma senha válida.

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);
?>

Um usuário poderá enviar para nossa query o seguinte código:



Código PHP:

$_POST['name'] = "a';DROP TABLE users";


e ela ficará assim:

Código:

SELECT * FROM users WHERE name = 'a'; DROP TABLE users
Ela selecionará o usuário com nome igual a ‘a’ e logo após irá apagar nossa tabela ‘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);
?>

A query ficará assim:

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:


function anti_sql_injection($str) {
if (!is_numeric($str)) {
$str = get_magic_quotes_gpc() ? stripslashes($str) : $str;
$str = function_exists('mysql_real_escape_string') ? mysql_real_escape_string($str) : mysql_escape_string($str);
}
return $str;
}



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:

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$usuario = trim($_POST['usuario']);
$senha = trim($_POST['senha']);$sql = ’SELECT COUNT(id_usuario) ’;
$sql .= ’FROM usuarios ’;
$sql .= ’WHERE usuario = \” . anti_sql_injection($usuario) . ’\' ’;
$sql .= ’AND senha = \” . anti_sql_injection($senha) . ’\' ’;

$query = mysql_query($sql) or die(‘Erro na consulta: ’ . mysql_error());
$total = mysql_result($query, 0);
if ($total > 0) {
echo ’Usuário e senha corretos.’;
} else {
echo ’Usuário e/ou senha inválidos.’;
}
}

Pronto! Estamos protegidos contra ataques de SQL Injection, e o melhor de tudo, sem destruir o conteúdo dos nossos sistemas.

Sem comentários:

Enviar um comentário