Inyección SQL que evade mysql_real_escape_string(): análisis de vulnerabilidades

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

«¡Socorro! ¡Mi mysql_real_escape_string() no funciona!»



Si alguna vez has buscado en Google «SQL injection that gets around mysql_real_escape_string()», no estás solo. Esta pregunta en Stack Overflow ha acumulado decenas de miles de visitas y se ha convertido en un clásico de la seguridad web. En teoría, usas mysql_real_escape_string() y estás protegido. Pero no. Los hackers encuentran resquicios, y los desarrolladores, canas.



En este artículo, analizaremos cómo las inyecciones SQL pueden evadir el escape de mysql_real_escape_string() en PHP. Verás ejemplos reales de código, entenderás por qué el «viejo y confiable» enfoque ya no funciona y aprenderás cómo protegerte de verdad. ¡Allá vamos!



¿Por qué mysql_real_escape_string() no es una panacea?



Para empezar, un poco de historia. La función mysql_real_escape_string() apareció en la era de PHP 4 y 5, cuando todos usaban la extensión mysql_*. Escapa caracteres especiales como comillas, barras invertidas y caracteres de control. Pero el problema es que solo funciona en el contexto de una única codificación.



Si la codificación del cliente y del servidor no coinciden, comienza el caos. Y si usas codificaciones multibyte (por ejemplo, GBK o SJIS), la función puede convertirse en tu peor enemigo.



Ejemplo clásico: ataque multibyte



Imagina que tu sitio usa la codificación GBK (china) y envías la cadena:



$_POST['name'] = "0xbf27"; // ¿Apóstrofe escapado o simplemente '?


En GBK, el carácter 0xbf27 es un carácter chino válido. Pero si mysql_real_escape_string() «ve» 0x27 (apóstrofe), lo escapa con una barra invertida: 0xbf5c27. El problema es que 0xbf5c también es un carácter válido en GBK. ¡Esto significa que el apóstrofe 0x27 permanece sin escapar, y el hacker puede insertar su código SQL!



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

// Si se ingresa: 0xbf27// La función devuelve: 0xbf5c27// En GBK esto es: carácter chino + apóstrofe// La consulta se convierte en: SELECT * FROM users WHERE name = 'car_chi' OR 1=1 -- '


¡Voilà! La inyección ha tenido éxito. Y esto no es teoría: se han encontrado vulnerabilidades así en proyectos reales.



Vulnerabilidades típicas al usar mysql_real_escape_string()



Enumeremos los errores más comunes que permiten evadir el escape:



  • Codificación incorrecta — como en el ejemplo anterior. Si el servidor cree que los datos están en UTF-8, pero el cliente envía GBK, el escape se rompe.
  • Uso de campos numéricos sin comillas — si insertas un número directamente, el escape no funciona. Por ejemplo: SELECT * FROM users WHERE id = $id — y el hacker escribe 1 OR 1=1.
  • Consultas LIKE — el escape no maneja los caracteres % y _. Se puede realizar una inyección SQL ciega a través de patrones.
  • Escape múltiple — si llamas a la función dos veces, la barra invertida se duplica y la protección desaparece.


Ejemplo: ataque a un campo numérico



// Código vulnerable$id = mysql_real_escape_string($_GET['id']);$query = "SELECT * FROM products WHERE id = $id"; // ¡No se necesitan comillas!

// El hacker ingresa: 1 UNION SELECT username, password FROM users// La consulta se convierte en: SELECT * FROM products WHERE id = 1 UNION SELECT username, password FROM users


El escape aquí es inútil: no hay comillas que escapar. El hacker simplemente inserta su SQL directamente.



Métodos modernos de protección (que funcionan)



Basta de historias de terror: pasemos a las soluciones. Si programas en PHP y quieres olvidarte de las inyecciones SQL, aquí tienes tu lista de verificación:



1. Usa PDO o MySQLi con sentencias preparadas



Esto es

Blogs

Book Recommendations