Injeção SQL contornando mysql_real_escape_string(): análise de vulnerabilidades

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

"Socorro! Meu mysql_real_escape_string() não funciona!"



Se você já pesquisou no Google por "SQL injection that gets around mysql_real_escape_string()", não está sozinho. Esta pergunta no Stack Overflow acumulou dezenas de milhares de visualizações e se tornou um clássico da segurança web. À primeira vista, você usa mysql_real_escape_string() e está protegido. Mas não. Hackers encontram brechas, e desenvolvedores ganham cabelos brancos.



Neste artigo, vamos analisar exatamente como as injeções SQL podem contornar o escape do mysql_real_escape_string() em PHP. Você verá exemplos reais de código, entenderá por que a "boa e velha" abordagem não funciona mais e aprenderá como se proteger de verdade. Vamos lá!



Por que mysql_real_escape_string() não é uma panaceia?



Para começar — um pouco de história. A função mysql_real_escape_string() surgiu na era do PHP 4 e 5, quando todos usavam a extensão mysql_*. Ela escapa caracteres especiais como aspas, barras invertidas e caracteres de controle. Mas o problema é que ela funciona apenas no contexto de uma única codificação.



Se a codificação do cliente e do servidor não coincidirem — começa o caos. E se você usar codificações multibyte (como GBK ou SJIS) — a função pode se tornar seu pior inimigo.



Exemplo clássico: ataque multibyte



Imagine que seu site usa a codificação GBK (chinesa), e você envia a string:



$_POST['name'] = "0xbf27"; // ' escapado ou apenas '?


Em GBK, o caractere 0xbf27 é um caractere chinês válido. Mas se mysql_real_escape_string() "enxergar" o 0x27 (apóstrofo), ela o escapará com uma barra invertida: 0xbf5c27. O problema é que 0xbf5c também é um caractere válido em GBK! Resultado: o apóstrofo 0x27 permanece sem escape, e o hacker pode inserir seu código SQL.



// Código vulnerável$name = mysql_real_escape_string($_POST['name']);$query = "SELECT * FROM users WHERE name = '$name'";

// Se inserir: 0xbf27// A função retorna: 0xbf5c27// Em GBK isso é: caractere chinês + apóstrofo// A consulta se torna: SELECT * FROM users WHERE name = 'caract_chinês' OR 1=1 -- '


Voilà! A injeção foi bem-sucedida. E isso não é teoria — essas vulnerabilidades foram encontradas em projetos reais.



Vulnerabilidades típicas ao usar mysql_real_escape_string()



Vamos listar os erros mais comuns que permitem contornar o escape:



  • Codificação incorreta — como no exemplo acima. Se o servidor acha que os dados estão em UTF-8, mas o cliente envia GBK, o escape falha.
  • Uso de campos numéricos sem aspas — se você insere um número diretamente, o escape não funciona. Exemplo: SELECT * FROM users WHERE id = $id — e o hacker escreve 1 OR 1=1.
  • Consultas LIKE — o escape não trata os caracteres % e _. É possível realizar Blind SQL injection através de padrões.
  • Escape múltiplo — se você chamar a função duas vezes, a barra invertida é duplicada e a proteção desaparece.


Exemplo: ataque a campo numérico



// Código vulnerável$id = mysql_real_escape_string($_GET['id']);$query = "SELECT * FROM products WHERE id = $id"; // Aspas não são necessárias!

// O hacker insere: 1 UNION SELECT username, password FROM users// A consulta se torna: SELECT * FROM products WHERE id = 1 UNION SELECT username, password FROM users


O escape aqui é inútil — não há aspas para escapar. O hacker simplesmente insere seu SQL diretamente.



Métodos modernos de proteção (que funcionam)



Chega de histórias de terror — vamos às soluções. Se você programa em PHP e quer esquecer as injeções SQL, aqui está sua lista de verificação:



1. Use PDO ou MySQLi com prepared statements



Isto é

Blogs

Book Recommendations