Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

mysql_real_escape_string() e mysql_escape_string() são suficientes para a segurança do aplicativo?


@Charles está extremamente correto!

Você se coloca em risco por vários tipos de conhecidos Ataques SQL, incluindo, como você mencionou
  • Injeção de SQL:Sim! Mysql_Escape_String provavelmente AINDA mantém você suscetível a injeções de SQL, dependendo de onde você usa variáveis ​​PHP em suas consultas.

Considere isto:
$sql = "SELECT number FROM PhoneNumbers " .
       "WHERE " . mysql_real_escape_string($field) . " = " . mysql_real_escape_string($value);  

Isso pode ser escapado com segurança e precisão dessa maneira? NÃO! Por quê? porque um hacker ainda pode fazer isso:

Repita depois de mim:

mysql_real_escape_string() serve apenas para escapar de dados variáveis, NÃO nomes de tabelas, nomes de colunas e, especialmente, não campos LIMIT.

  • LIKE explora:LIKE "$data%" onde $data poderia ser "%" que retornaria TODOS os registros ... o que pode muito bem ser um exploit de segurança... imagine uma pesquisa pelos últimos quatro dígitos de um cartão de crédito... OOPs! Agora os hackers podem potencialmente receber todos os números de cartão de crédito em seu sistema! (BTW:Armazenar cartões de crédito completos dificilmente é recomendado!)

  • Exploits de Charset:Não importa o que os inimigos digam, o Internet Explorer ainda , em 2011, vulnerável a Exploits de Conjunto de Caracteres, e isso é se você projetou sua página HTML corretamente, com o equivalente a <meta name="charset" value="UTF-8"/> ! Esses ataques são MUITO desagradáveis, pois dão ao hacker tanto controle quanto injeções de SQL diretas:por exemplo, cheio.

Aqui está um código de exemplo para demonstrar tudo isso:
// Contains class DBConfig; database information.
require_once('../.dbcreds');                       

$dblink = mysql_connect(DBConfig::$host, DBConfig::$user, DBConfig::$pass);
mysql_select_db(DBConfig::$db);
//print_r($argv);

$sql = sprintf("SELECT url FROM GrabbedURLs WHERE %s LIKE '%s%%' LIMIT %s",
               mysql_real_escape_string($argv[1]),
               mysql_real_escape_string($argv[2]),
               mysql_real_escape_string($argv[3]));
echo "SQL: $sql\n";
$qq = mysql_query($sql);
while (($data = mysql_fetch_array($qq)))
{
        print_r($data);
}

Aqui estão os resultados deste código quando várias entradas são passadas:
$ php sql_exploits.php url http://www.reddit.com id
SQL generated: SELECT url FROM GrabbedURLs 
               WHERE url LIKE 'http://www.reddit.com%'
               ORDER BY id;
Returns: Just URLs beginning w/ "http://www.reddit.com"

$ php sql_exploits.php url % id
SQL generated: SELECT url FROM GrabbedURLs 
               WHERE url LIKE '%%' 
               ORDER BY id;
Results: Returns every result Not what you programmed, ergo an exploit --

$ php sql_exploits.php 1=1'http://www.reddit.com ' id Results:Retorna todas as colunas e todos os resultados.

Depois, há as explorações LIMIT REALLLY desagradáveis:
$ php sql_exploits.php url 
> 'http://www.reddit.com'
> "UNION SELECT name FROM CachedDomains"
Generated SQL: SELECT url FROM GrabbedURLs 
               WHERE url LIKE 'http://reddit.com%' 
               LIMIT 1 
               UNION
               SELECT name FROM CachedDomains;
Returns:  An entirely unexpected, potentially (probably) unauthorized query
          from another, completely different table. 

Se você entende o SQL nos ataques ou não, é irrelevante. O que isso demonstrou é que mysql_real_escape_string() é facilmente contornado até mesmo pelos hackers mais imaturos. Isso porque é um mecanismo de defesa REATIVO. Ele apenas corrige exploits muito limitados e CONHECIDOS no banco de dados.

Todos os escapes NUNCA serão suficientes para proteger os bancos de dados. Na verdade, você pode REAGIR explicitamente a cada exploração CONHECIDA e, no futuro, seu código provavelmente se tornará vulnerável a ataques descobertos no futuro.

A defesa adequada e única (realmente) é PROATIVA:Use Declarações Preparadas. As instruções preparadas são projetadas com cuidado especial para que APENAS SQL válido e PROGRAMADO seja executado. Isso significa que, quando feito corretamente, as chances de SQL inesperado poder ser executado são drasticamente reduzidas.

Teoricamente, declarações preparadas e implementadas perfeitamente seriam imunes a TODOS os ataques, conhecidos e desconhecidos, pois são uma técnica SERVER SIDE, manipulada pelos próprios SERVIDORES DE BANCO DE DADOS e pelas bibliotecas que fazem interface com a linguagem de programação. Portanto, você SEMPRE estará protegido contra TODOS OS HACK CONHECIDOS, no mínimo.

E é menos código:
$pdo = new PDO($dsn);

$column = 'url';
$value = 'http://www.stackoverflow.com/';
$limit = 1;

$validColumns = array('url', 'last_fetched');

// Make sure to validate whether $column is a valid search parameter.
// Default to 'id' if it's an invalid column.
if (!in_array($column, $validColumns) { $column = 'id'; }


$statement = $pdo->prepare('SELECT url FROM GrabbedURLs ' .
                           'WHERE ' . $column . '=? ' .
                           'LIMIT ' . intval($limit));
$statement->execute(array($value));
while (($data = $statement->fetch())) { }

Agora que não era tão difícil era? E é quarenta e sete por cento menos código (195 caracteres (PDO) vs 375 caracteres (mysql_). Isso é o que eu chamo de "full of win".

EDIT:Para resolver toda a controvérsia que essa resposta gerou, permita-me reiterar o que já disse:

O uso de instruções preparadas permite aproveitar as medidas de proteção do próprio servidor SQL e, portanto, você está protegido de coisas que as pessoas do servidor SQL conhecem. Devido a esse nível extra de proteção, você está muito mais seguro do que apenas usar o escape, não importa o quão completo seja.